diff --git a/.cargo/config b/.cargo/config index 72652ad2f11c848a7b1dd184899acc04caa604f9..3f07816e3c73c52e359cbf4cad249f5e6975604c 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,3 +1,3 @@ [target.x86_64-pc-windows-msvc] -# Link the C runtime statically ; https://github.com/paritytech/parity/issues/6643 +# Link the C runtime statically ; https://github.com/paritytech/parity-ethereum/issues/6643 rustflags = ["-Ctarget-feature=+crt-static"] diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index e3438f10a23b548453645c4a5d5b65d58fbabc3c..fc187a534fdf160b5e33c32c19ef95b57f32326a 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -2,7 +2,7 @@ ## Do you have a question? -Check out our [Basic Usage](https://github.com/paritytech/parity/wiki/Basic-Usage), [Configuration](https://github.com/paritytech/parity/wiki/Configuring-Parity), and [FAQ](https://github.com/paritytech/parity/wiki/FAQ) articles on our [wiki](https://github.com/paritytech/parity/wiki)! +Check out our [Basic Usage](https://wiki.parity.io/Basic-Usage), [Configuration](https://wiki.parity.io/Configuring-Parity-Ethereum), and [FAQ](https://wiki.parity.io/FAQ) articles on our [wiki](https://wiki.parity.io/)! See also frequently asked questions [tagged with `parity`](https://ethereum.stackexchange.com/questions/tagged/parity?sort=votes&pageSize=50) on Stack Exchange. @@ -10,7 +10,7 @@ See also frequently asked questions [tagged with `parity`](https://ethereum.stac Do **not** open an issue on Github if you think your discovered bug could be a **security-relevant vulnerability**. Please, read our [security policy](../SECURITY.md) instead. -Otherwise, just create a [new issue](https://github.com/paritytech/parity/issues/new) in our repository and state: +Otherwise, just create a [new issue](https://github.com/paritytech/parity-ethereum/issues/new) in our repository and state: - What's your Parity version? - What's your operating system and version? @@ -22,9 +22,9 @@ Also, try to include **steps to reproduce** the issue and expand on the **actual ## Contribute! -If you would like to contribute to Parity, please **fork it**, fix bugs or implement features, and [propose a pull request](https://github.com/paritytech/parity/compare). +If you would like to contribute to Parity, please **fork it**, fix bugs or implement features, and [propose a pull request](https://github.com/paritytech/parity-ethereum/compare). -Please, refer to the [Coding Guide](https://github.com/paritytech/parity/wiki/Coding-guide) in our wiki for more details about hacking on Parity. +Please, refer to the [Coding Guide](https://wiki.parity.io/Coding-guide) in our wiki for more details about hacking on Parity. ## License. diff --git a/.gitignore b/.gitignore index 3bc041c90812930bfb6e6c9ac90a3f36ba83e2be..53c0e8ac65f28d19c9bef795c59a6baf30399f07 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ node_modules # Build artifacts out/ +parity-clib-examples/cpp/build/ .vscode rls/ diff --git a/CHANGELOG.md b/CHANGELOG.md index ee66149ed0045f42b9ddf271eb78601ef08ecb7d..a86383349dccdc14ec1222a11f49f693f52a84b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,381 +1,371 @@ -## Parity [v1.11.1](https://github.com/paritytech/parity/releases/tag/v1.11.1) (2018-05-15) +## Parity-Ethereum [v2.0.1](https://github.com/paritytech/parity-ethereum/releases/tag/v2.0.1) (2018-07-27) -This is the Parity 1.11.1-beta release! Hurray! +Parity-Ethereum 2.0.1-beta is a bug-fix release to improve performance and stability. -Notable changes in reversed alphabetical order: - -- TOOLING: **Whisper CLI** [#8201](https://github.com/paritytech/parity/pull/8201) - - `whisper-cli` is a standalone tool to communicate with the Whisper protocol. - - It provides functionality to specify `whisper-pool-size`, `port` and `address` to use. - - All whisper RPC APIs are enabled and can be directly accessed. -- JSON-RPC API: **Return error in case eth_call returns VM errors** [#8448](https://github.com/paritytech/parity/pull/8448) - - This changes the behaviors of `eth_call` to respect VM errors if any. - - In case of `REVERT`, it will also return the reverted return data in hex format. -- ENGINES: **Block Reward Contract** [#8419](https://github.com/paritytech/parity/pull/8419) - - The _AuRa_ PoA engine has now support for having a contract to calculate the block rewards. - - The engine passes a list of benefactors and reward types to the contract which then returns a list of addresses and respective rewards. -- CORE: **Private Transactions** [#6422](https://github.com/paritytech/parity/pull/6422) - - Parity now provides a private transactions system. - - Please, check out our wiki to get an [overview and setup instructions](https://wiki.parity.io/Private-Transactions.html). -- CORE: **New Transaction Queue implementation** [#8074](https://github.com/paritytech/parity/pull/8074) - - Verification is now done in parallel. - - Previous queue had `O(1)` time to get pending set, but `O(n^2)` insertion time. And obviously insertion/removal happens much more often than retrieving the pending set (only for propagation and pending block building) Currently we have `O(n * log(senders))` pending set time (with cache) and `O(tx_per_sender)` (usually within `log(tx_per_sender)`) insertion time. - - `Scoring` and `Readiness` are separated from the pool, so it's easier to customize them or introduce different definitions (for instance for [EIP-859](https://github.com/ethereum/EIPs/issues/859) or private transactions, etc). - - Banning removed, soft-penalization introduced instead: if transaction exceeds the limit other transactions from that sender get lower priority. - - There is no explicit distinction between current and future transactions in the pool - `Readiness` determines that. Because of this we additionally remove `future` transactions that occupy the pool for long time. -- CONFIGURATION: **Warp-only sync with --warp-barrier [block-number] flag.** [#8228](https://github.com/paritytech/parity/pull/8228) - - Enables warp-only sync in case `--warp-barrier [block-number]` is provided. - - This avoids clients to warp to outdated snapshots that are too far away from the best block. - - This avoids clients to fall back to normal sync if there are no recent snapshots available currently. -- CONFIGURATION: **Disable UI by default.** [#8105](https://github.com/paritytech/parity/pull/8105) - - The user interface is now disabled by default. It still can be activated with the `--force-ui` flag. - - To get the stand-alone Parity UI, please check the dedicated [releases page](https://github.com/parity-js/shell/releases). -- CONFIGURATION: **Auto-updater improvements** [#8078](https://github.com/paritytech/parity/pull/8078) - - Added `--auto-update-delay` to randomly delay updates by `n` blocks. This takes into account the number of the block of the update release (old updates aren't delayed). - - Added `--auto-update-check-frequency` to define the periodicity of auto-update checks in number of blocks. - - This is an important improvement to ensure the network does not update all clients at the same time. -- CHAIN SPECS: **Enable WebAssembly and Byzantium for Ellaism** [#8520](https://github.com/paritytech/parity/pull/8520) - - This activates the Ellaism Byzantium hardfork ([2018-0004-byzantium](https://github.com/ellaism/specs/blob/master/specs/2018-0004-byzantium.md)) at block `2_000_000`. - - This enables the Wasm VM on Ellaism ([2018-0003-wasm-hardfork](https://github.com/ellaism/specs/blob/master/specs/2018-0003-wasm-hardfork.md)) at block `2_000_000`. - - Please, upgrade your clients if you run an Ellaism configuration. -- CHAIN SPECS: **Dev chain - increase gasLimit to 8_000_000** [#8362](https://github.com/paritytech/parity/pull/8362) - - This increases the default block gas limit on development chains to `8_000_000`. - - Please note, this makes previous dev chain configurations incompatible. -- CHAIN SPECS: **Add MCIP-6 Byzyantium transition to Musicoin spec** [#7841](https://github.com/paritytech/parity/pull/7841) - - This activates the Musicoin Byzantium hardfork ([MCIP-6](https://github.com/Musicoin/MCIPs/blob/master/MCIPS/mcip-6.md)) at block `2_222_222`. - - Please, upgrade your clients if you run a Musicoin configuration. +Note, authorities in PoA networks based on the Aura engine, should upgrade their nodes to 1.11.8-stable or 2.0.1-beta as this release includes a critical fix. The full list of included changes: -- Backports ([#8624](https://github.com/paritytech/parity/pull/8624)) - - Trace precompiled contracts when the transfer value is not zero ([#8486](https://github.com/paritytech/parity/pull/8486)) - - Trace precompiled contracts when the transfer value is not zero - - Add tests for precompiled CALL tracing - - Use byzantium test machine for the new test - - Add notes in comments on why we don't trace all precompiles - - Use is_transferred instead of transferred - - Return error if RLP size of transaction exceeds the limit ([#8473](https://github.com/paritytech/parity/pull/8473)) - - Return error if RLP size of transaction exceeds the limit - - Review comments fixed - - RLP check moved to verifier, corresponding pool test added - - Don't block sync when importing old blocks ([#8530](https://github.com/paritytech/parity/pull/8530)) - - Alter IO queueing. - - Don't require IoMessages to be Clone - - Ancient blocks imported via IoChannel. - - Get rid of private transactions io message. - - Get rid of deadlock and fix disconnected handler. - - Revert to old disconnect condition. - - Fix tests. - - Fix deadlock. - - Refactoring `ethcore-sync` - Fixing warp-sync barrier ([#8543](https://github.com/paritytech/parity/pull/8543)) - - Start dividing sync chain : first supplier method - - WIP - updated chain sync supplier - - Finish refactoring the Chain Sync Supplier - - Create Chain Sync Requester - - Add Propagator for Chain Sync - - Add the Chain Sync Handler - - Move tests from mod -> handler - - Move tests to propagator - - Refactor SyncRequester arguments - - Refactoring peer fork header handler - - Fix wrong highest block number in snapshot sync - - Small refactor... - - Address PR grumbles - - Retry failed CI job - - Fix tests - - PR Grumbles - - Handle socket address parsing errors ([#8545](https://github.com/paritytech/parity/pull/8545)) - - Fix packet count when talking with PAR2 peers ([#8555](https://github.com/paritytech/parity/pull/8555)) - - Support diferent packet counts in different protocol versions. - - Fix light timeouts and eclipse protection. - - Fix devp2p tests. - - Fix whisper-cli compilation. - - Fix compilation. - - Fix ethcore-sync tests. - - Revert "Fix light timeouts and eclipse protection." - - Increase timeouts. - - Add whisper CLI to the pipelines ([#8578](https://github.com/paritytech/parity/pull/8578)) - - Add whisper CLI to the pipelines - - Address todo, ref [#8579](https://github.com/paritytech/parity/pull/8579) - - Rename `whisper-cli binary` to `whisper` ([#8579](https://github.com/paritytech/parity/pull/8579)) - - Rename whisper-cli binary to whisper - - Fix tests - - Remove manually added text to the errors ([#8595](https://github.com/paritytech/parity/pull/8595)) - - Fix account list double 0x display ([#8596](https://github.com/paritytech/parity/pull/8596)) - - Remove unused self import - - Fix account list double 0x display - - Fix BlockReward contract "arithmetic operation overflow" ([#8611](https://github.com/paritytech/parity/pull/8611)) - - Fix BlockReward contract "arithmetic operation overflow" - - Add docs on how execute_as_system works - - Fix typo - - Rlp decode returns Result ([#8527](https://github.com/paritytech/parity/pull/8527)) - - Remove expect ([#8536](https://github.com/paritytech/parity/pull/8536)) - - Remove expect and propagate rlp::DecoderErrors as TrieErrors - - Decoding headers can fail ([#8570](https://github.com/paritytech/parity/pull/8570)) - - Rlp::decode returns Result - - Fix journaldb to handle rlp::decode Result - - Fix ethcore to work with rlp::decode returning Result - - Light client handles rlp::decode returning Result - - Fix tests in rlp_derive - - Fix tests - - Cleanup - - Cleanup - - Allow panic rather than breaking out of iterator - - Let decoding failures when reading from disk blow up - - Syntax - - Fix the trivial grumbles - - Fix failing tests - - Make Account::from_rlp return Result - - Syntx, sigh - - Temp-fix for decoding failures - - Header::decode returns Result - - Do not continue reading from the DB when a value could not be read - - Fix tests - - Handle header decoding in light_sync - - Handling header decoding errors - - Let the DecodeError bubble up unchanged - - Remove redundant error conversion - - Fix compiler warning ([#8590](https://github.com/paritytech/parity/pull/8590)) - - Attempt to fix intermittent test failures ([#8584](https://github.com/paritytech/parity/pull/8584)) - - Block_header can fail so return Result ([#8581](https://github.com/paritytech/parity/pull/8581)) - - Block_header can fail so return Result - - Restore previous return type based on feedback - - Fix failing doc tests running on non-code - - Block::decode() returns Result ([#8586](https://github.com/paritytech/parity/pull/8586)) - - Gitlab test script fixes ([#8573](https://github.com/paritytech/parity/pull/8573)) - - Exclude /docs from modified files. - - Ensure all references in the working tree are available - - Remove duplicated line from test script -- Bump beta to 1.11.1 ([#8627](https://github.com/paritytech/parity/pull/8627)) +- Backports to 2.0.1-beta ([#9145](https://github.com/paritytech/parity-ethereum/pull/9145)) + - Parity-version: bump beta to 2.0.1 + - Ci: update version strings for snaps ([#9160](https://github.com/paritytech/parity-ethereum/pull/9160)) + - Be more graceful on Aura difficulty validation ([#9164](https://github.com/paritytech/parity-ethereum/pull/9164)) + - Be more graceful on Aura difficulty validation + - Test: rejects_step_backwards + - Test: proposer_switching + - Test: rejects_future_block + - Test: reports_skipped + - Test: verify_empty_seal_steps + - Remove node-health ([#9119](https://github.com/paritytech/parity-ethereum/pull/9119)) + - Remove node-health + - Remove ntp_servers + - Add --ntp-servers as legacy instead of removing it + - Add --ntp-servers to deprecated args + - Remove unused stuff + - Remove _legacy_ntp_servers + - Parity: fix UserDefaults json parser ([#9189](https://github.com/paritytech/parity-ethereum/pull/9189)) + - Parity: fix UserDefaults json parser + - Parity: use serde_derive for UserDefaults + - Parity: support deserialization of old UserDefault json format + - Parity: make UserDefaults serde backwards compatible + - Parity: tabify indentation in UserDefaults + - Fix bugfix hard fork logic ([#9138](https://github.com/paritytech/parity-ethereum/pull/9138)) + - Fix bugfix hard fork logic + - Remove dustProtectionTransition from bugfix category + - Eip-168 is not enabled by default + - Remove unnecessary 'static + - Disable per-sender limit for local transactions. ([#9148](https://github.com/paritytech/parity-ethereum/pull/9148)) + - Disable per-sender limit for local transactions. + - Add a missing new line. + - Rpc: fix is_major_importing sync state condition ([#9112](https://github.com/paritytech/parity-ethereum/pull/9112)) + - Rpc: fix is_major_importing sync state condition + - Rpc: fix informant printout when waiting for peers + - Fix verification in ethcore-sync collect_blocks ([#9135](https://github.com/paritytech/parity-ethereum/pull/9135)) + - Docker: update hub dockerfile ([#9173](https://github.com/paritytech/parity-ethereum/pull/9173)) + - Update Dockerfile for hub + - Update to Ubuntu Xenial 16.04 + - Fix cmake version + - Docker: fix tab indentation in hub dockerfile + - Rpc: fix broken merge + - Rpc: remove node_health leftover from merge + - Rpc: remove dapps leftover from merge + +## Parity-Ethereum [v2.0.0](https://github.com/paritytech/parity-ethereum/releases/tag/v2.0.0) "Ethereum" (2018-07-18) + +This is the Parity-Ethereum//v2.0.0-beta release, code-named "Ethereum", **YOLO!** + +Please note, Parity-Ethereum//v2.0.0 comes with some breaking changes that might be interrupting your usual workflows. Please mind them before upgrading: + +- The Parity client is now called _Parity-Ethereum_ to distinguish it from other software we provide, such as [_Parity-Bitcoin_](https://github.com/paritytech/parity-bitcoin/) and [_Parity-Polkadot_](https://github.com/paritytech/polkadot) ([#9052](https://github.com/paritytech/parity-ethereum/pull/9052)). +- The public node and the user interface (a.k.a. _"Parity Wallet"_) are completely removed from the Parity-Ethereum//v2.0.0 client ([#8758](https://github.com/paritytech/parity-ethereum/pull/8758), [#8783](https://github.com/paritytech/parity-ethereum/pull/8783), [#8641](https://github.com/paritytech/parity-ethereum/pull/8641)). Users interested running a Parity Wallet, check out [the stand-alone UI application](https://github.com/Parity-JS/shell/releases). +- The DApps subsystem was completely removed from the client ([#9017](https://github.com/paritytech/parity-ethereum/pull/9017), [#9107](https://github.com/paritytech/parity-ethereum/pull/9107)). Again, use the standalone wallet if you wish to continue working with them. +- Windows and MacOS versions are not available as installer anymore and the system trays were removed ([#8778](https://github.com/paritytech/parity-ethereum/pull/8778)). If you desire to run Parity-Ethereum on Windows or MacOS, you still can get the binaries from our mirrors. Furthermore, MacOS users are encouraged [to use our homebrew tap](https://github.com/paritytech/homebrew-paritytech/). +- Linux versions are not available as deb-/rpm-packages anymore ([#8887](https://github.com/paritytech/parity-ethereum/pull/8887)). Communities are encouraged to provide their own packages or maintain their own repositories, such as [Arch Linux does](https://www.archlinux.org/packages/community/x86_64/parity/) for instance. +- MD5-checksums are completely replaced by SHA256-checksums ([#8884](https://github.com/paritytech/parity-ethereum/pull/8884)). This is also reflected on our homepage by now. +- Deprecated, removed, or replaced CLI-options are hidden from client `--help` to further discourage their usage ([#8967](https://github.com/paritytech/parity-ethereum/pull/8967)). + +Additional noteworthy changes to the client: + +- Tracing of precompiled contracts when the transfer value is not zero ([#8486](https://github.com/paritytech/parity-ethereum/pull/8486)) +- _Parity-Ethereum_ as a library now provides APIs for running full and light nodes and a C interface ([#8412](https://github.com/paritytech/parity-ethereum/pull/8412)). Shared crates are now available in [_Parity-Common_](https://github.com/paritytech/parity-common) ([#9083](https://github.com/paritytech/parity-ethereum/pull/9083)). +- The Morden database and keys are now moved to a `./Morden` subdirectory instead of `./test` which is by default used by Ropsten ([#8621](https://github.com/paritytech/parity-ethereum/pull/8621)). +- Adding support for having an on-chain contract calculating the block rewards ([#8419](https://github.com/paritytech/parity-ethereum/pull/8419)). +- Enforcing warp-only synchronization with `--warp-barrier [blocknumber]` flag ([#8228](https://github.com/paritytech/parity-ethereum/pull/8228)). +- Adding a fork-choice and meta-data framework suitable for implementing Casper ([#8401](https://github.com/paritytech/parity-ethereum/pull/8401)). +- Returning an error if RLP-size of a transaction exceeds a 300kB limit ([#8473](https://github.com/paritytech/parity-ethereum/pull/8473)). +- Warp-sync is now resumable by keeping the downloaded chunks between client restarts. Also, it seeds downloaded snapshots for other nodes ([#8544](https://github.com/paritytech/parity-ethereum/pull/8544)). +- The developer chain `--chain dev` now contains Byzantium features, this breaks existing developer chains ([#8717](https://github.com/paritytech/parity-ethereum/pull/8717)). +- The EIP150, EIP160 and EIP161 forks are now to be specified in common params section of a chain-spec file instead of the Ethash params to enable these features on non-proof-of-work chains ([#8614](https://github.com/paritytech/parity-ethereum/pull/8614)). Please update your chain specs. +- Allowing to disable local-by-default for transactions with new configurations ([#8882](https://github.com/paritytech/parity-ethereum/pull/8882)). +- Never drop local transactions from different senders ([#9002](https://github.com/paritytech/parity-ethereum/pull/9002)). +- Optimize pending transactions filter and fix ethstats reporting of pending transactions ([#9026](https://github.com/paritytech/parity-ethereum/pull/9026)). +- Add separate database directory for light client allowing to run full and light nodes at the same time ([#9064](https://github.com/paritytech/parity-ethereum/pull/9064)). -## Parity [v1.11.0](https://github.com/paritytech/parity/releases/tag/v1.11.0) (2018-05-09) +If you are upgrading directly from versions 1.10.9 or earlier, please note important changes to our transaction-queue implementation, namely: -This is the Parity 1.11.0-beta release! ~~Hurray!~~ This release has been pulled due to peering issues, please use 1.11.1-beta. +- The pool now limits transactions per-sender (see `--tx-queue-per-sender`), local transactions also have to obey that limit. Consider increasing the limit via CLI-flag when running benchmarks or sending a lot of transactions at once. +- In case the pool is full, transactions received over the network, but originating from accounts that you have private keys for might not get accepted to the pool any more with higher priority. Consider running with larger pool size or submitting the transactions directly on the node via `eth_sendRawTransaction`. The full list of included changes: -- Backports ([#8558](https://github.com/paritytech/parity/pull/8558)) - - Fetching logs by hash in blockchain database ([#8463](https://github.com/paritytech/parity/pull/8463)) - - Fetch logs by hash in blockchain database - - Fix tests - - Add unit test for branch block logs fetching - - Add docs that blocks must already be sorted - - Handle branch block cases properly - - typo: empty -> is_empty - - Remove return_empty_if_none by using a closure - - Use BTreeSet to avoid sorting again - - Move is_canon to BlockChain - - typo: pass value by reference - - Use loop and wrap inside blocks to simplify the code - - typo: missed a comment - - Pass on storage keys tracing to handle the case when it is not modified ([#8491](https://github.com/paritytech/parity/pull/8491)) - - Pass on storage keys even if it is not modified - - typo: account and storage query - - Fix tests - - Use state query directly because of suicided accounts - - Fix a RefCell borrow issue - - Add tests for unmodified storage trace - - Address grumbles - - typo: remove unwanted empty line - - ensure_cached compiles with the original signature - - Update wasmi and pwasm-utils ([#8493](https://github.com/paritytech/parity/pull/8493)) - - Update wasmi to 0.2 - - Update pwasm-utils to 0.1.5 - - Show imported messages for light client ([#8517](https://github.com/paritytech/parity/pull/8517)) - - Enable WebAssembly and Byzantium for Ellaism ([#8520](https://github.com/paritytech/parity/pull/8520)) - - Enable WebAssembly and Byzantium for Ellaism - - Fix indentation - - Remove empty lines - - Don't panic in import_block if invalid rlp ([#8522](https://github.com/paritytech/parity/pull/8522)) - - Don't panic in import_block if invalid rlp - - Remove redundant type annotation - - Replace RLP header view usage with safe decoding - - Node table sorting according to last contact data ([#8541](https://github.com/paritytech/parity/pull/8541)) - - network-devp2p: sort nodes in node table using last contact data - - network-devp2p: rename node contact types in node table json output - - network-devp2p: fix node table tests - - network-devp2p: note node failure when failed to establish connection - - network-devp2p: handle UselessPeer error - - network-devp2p: note failure when marking node as useless -- Betalize 1.11 :) ([#8475](https://github.com/paritytech/parity/pull/8475)) - - Betalize 1.11 :) - - Update Gitlab scripts - - Use master as gitlab latest - - Fix snap builds ([#8483](https://github.com/paritytech/parity/pull/8483)) - - Update hardcodedSync for Ethereum, Kovan, and Ropsten ([#8489](https://github.com/paritytech/parity/pull/8489)) -- Fix typos in vm description comment ([#8446](https://github.com/paritytech/parity/pull/8446)) -- Add changelog for 1.9.7 and 1.10.2 ([#8460](https://github.com/paritytech/parity/pull/8460)) -- Fix docker build ([#8462](https://github.com/paritytech/parity/pull/8462)) -- Parityshell::open `Return result` ([#8377](https://github.com/paritytech/parity/pull/8377)) -- Return error in case eth_call returns VM errors ([#8448](https://github.com/paritytech/parity/pull/8448)) -- Update wasmi ([#8452](https://github.com/paritytech/parity/pull/8452)) -- Allow 32 bit pipelines to fail ([#8454](https://github.com/paritytech/parity/pull/8454)) -- Update Cargo hidapi-rs dependency ([#8447](https://github.com/paritytech/parity/pull/8447)) -- Private transactions processing error handling ([#8431](https://github.com/paritytech/parity/pull/8431)) -- Improve VM executor stack size estimation rules ([#8439](https://github.com/paritytech/parity/pull/8439)) -- Block reward contract ([#8419](https://github.com/paritytech/parity/pull/8419)) -- Permission fix ([#8441](https://github.com/paritytech/parity/pull/8441)) -- Use forked app_dirs crate for reverted Windows dir behavior ([#8438](https://github.com/paritytech/parity/pull/8438)) -- Remove From::from. ([#8390](https://github.com/paritytech/parity/pull/8390)) -- Move ethcore::Error to error_chain ([#8386](https://github.com/paritytech/parity/pull/8386)) -- Changelogs for 1.9.6 and 1.10.1 ([#8411](https://github.com/paritytech/parity/pull/8411)) -- Fix receipts stripping. ([#8414](https://github.com/paritytech/parity/pull/8414)) -- Typo, docs parity_chainId: empty string -> None ([#8434](https://github.com/paritytech/parity/pull/8434)) -- Update zip to 0.3 ([#8381](https://github.com/paritytech/parity/pull/8381)) -- Fix TODO comments ([#8413](https://github.com/paritytech/parity/pull/8413)) -- Replace legacy Rlp with UntrustedRlp and use in ethcore rlp views ([#8316](https://github.com/paritytech/parity/pull/8316)) -- Tokio-core v0.1.16 -> v0.1.17 ([#8408](https://github.com/paritytech/parity/pull/8408)) -- More code refactoring to integrate Duration ([#8322](https://github.com/paritytech/parity/pull/8322)) -- Remove Tendermint extra_info due to seal inconsistencies ([#8367](https://github.com/paritytech/parity/pull/8367)) -- Use tokio::spawn in secret_store listener and fix Uri ([#8373](https://github.com/paritytech/parity/pull/8373)) -- Unify and limit rocksdb dependency places ([#8371](https://github.com/paritytech/parity/pull/8371)) -- Clarify that windows need perl and yasm ([#8402](https://github.com/paritytech/parity/pull/8402)) -- New Transaction Queue implementation ([#8074](https://github.com/paritytech/parity/pull/8074)) -- Some tweaks to main.rs for parity as a library ([#8370](https://github.com/paritytech/parity/pull/8370)) -- Handle queue import errors a bit more gracefully ([#8385](https://github.com/paritytech/parity/pull/8385)) -- Ci: fix change detection in master builds ([#8382](https://github.com/paritytech/parity/pull/8382)) -- Fix config test by adding no-hardcodec-sync ([#8380](https://github.com/paritytech/parity/pull/8380)) -- Fixed unsafe shell call on windows ([#8372](https://github.com/paritytech/parity/pull/8372)) -- Parity uses winapi 0.3.4 ([#8366](https://github.com/paritytech/parity/pull/8366)) -- No hardcoded client name ([#8368](https://github.com/paritytech/parity/pull/8368)) -- Add `util/mem` to zero out memory on drop. ([#8356](https://github.com/paritytech/parity/pull/8356)) -- Use atty instead of isatty ([#8365](https://github.com/paritytech/parity/pull/8365)) -- Increase gasLimit to 8'000'000 ([#8362](https://github.com/paritytech/parity/pull/8362)) -- Util `fake-fetch` ([#8363](https://github.com/paritytech/parity/pull/8363)) -- Bump snappy and ring, use single rayon version, closes [#8296](https://github.com/paritytech/parity/issues/8296) ([#8364](https://github.com/paritytech/parity/pull/8364)) -- Use async hyper server in secret_store and upgrade igd ([#8359](https://github.com/paritytech/parity/pull/8359)) -- Enable UI by default, but only display deprecation notice ([#8262](https://github.com/paritytech/parity/pull/8262)) -- Ethcrypto renamed to ethcore-crypto and moved to ethcore dir ([#8340](https://github.com/paritytech/parity/pull/8340)) -- Use hyper 0.11 in ethcore-miner and improvements in parity-reactor ([#8335](https://github.com/paritytech/parity/pull/8335)) -- Ethcore-sync ([#8347](https://github.com/paritytech/parity/pull/8347)) -- Rpc, eth_filter: return error if the filter id does not exist ([#8341](https://github.com/paritytech/parity/pull/8341)) -- Ethcore-stratum crate moved to ethcore directory ([#8338](https://github.com/paritytech/parity/pull/8338)) -- Secretstore: get rid of engine.signer dependency ([#8173](https://github.com/paritytech/parity/pull/8173)) -- Whisper cli ([#8201](https://github.com/paritytech/parity/pull/8201)) -- Replace_home for password_files, reserved_peers and log_file ([#8324](https://github.com/paritytech/parity/pull/8324)) -- Add Ethereum Social support ([#8325](https://github.com/paritytech/parity/pull/8325)) -- Private transactions integration pr ([#6422](https://github.com/paritytech/parity/pull/6422)) -- Decouple rocksdb dependency from ethcore ([#8320](https://github.com/paritytech/parity/pull/8320)) -- Remove the clone operation of code_cache ([#8334](https://github.com/paritytech/parity/pull/8334)) -- Fix the JSONRPC API not running with the light client ([#8326](https://github.com/paritytech/parity/pull/8326)) -- Read registry_address from block with REQUEST_CONFIRMATIONS_REQUIRED ([#8309](https://github.com/paritytech/parity/pull/8309)) -- Tweaks and add a Dockerfile for Android ([#8036](https://github.com/paritytech/parity/pull/8036)) -- Use associated type M::Error instead of Error ([#8308](https://github.com/paritytech/parity/pull/8308)) -- Remove InvalidParentHash in favor of assert! ([#8300](https://github.com/paritytech/parity/pull/8300)) -- Bump proc macro deps ([#8310](https://github.com/paritytech/parity/pull/8310)) -- Decouple timestamp open-block-assignment/verification to Engine ([#8305](https://github.com/paritytech/parity/pull/8305)) -- Validate if gas limit is not zero ([#8307](https://github.com/paritytech/parity/pull/8307)) -- Implement Easthub chain spec ([#8295](https://github.com/paritytech/parity/pull/8295)) -- Update some dependencies ([#8285](https://github.com/paritytech/parity/pull/8285)) -- Ethcore now uses Rayon 1.0 as a dependency ([#8296](https://github.com/paritytech/parity/pull/8296)) ([#8304](https://github.com/paritytech/parity/pull/8304)) -- Upgrader `remove raw unwrap` and bump semver ([#8251](https://github.com/paritytech/parity/pull/8251)) -- Cleaner binary shutdown system ([#8284](https://github.com/paritytech/parity/pull/8284)) -- Ethcore now uses rayon to 0.9 as a dependency ([#8296](https://github.com/paritytech/parity/pull/8296)) ([#8302](https://github.com/paritytech/parity/pull/8302)) -- Include suicided accounts in state diff ([#8297](https://github.com/paritytech/parity/pull/8297)) -- Remove evmjit ([#8229](https://github.com/paritytech/parity/pull/8229)) -- Build: fix updater rand dependency in Cargo.lock ([#8298](https://github.com/paritytech/parity/pull/8298)) -- Honor --max-peers if --min-peers is not specified ([#8087](https://github.com/paritytech/parity/pull/8087)) -- Auto-updater improvements ([#8078](https://github.com/paritytech/parity/pull/8078)) -- Dapps-fetcher: calculate keccak in-flight while reading the response ([#8294](https://github.com/paritytech/parity/pull/8294)) -- Cleanup Ellaism bootnodes ([#8276](https://github.com/paritytech/parity/pull/8276)) -- Allow unsafe js eval on Parity Wallet. ([#8204](https://github.com/paritytech/parity/pull/8204)) -- Remove RefCell from Header ([#8227](https://github.com/paritytech/parity/pull/8227)) -- Typo fix: todo with no content ([#8292](https://github.com/paritytech/parity/pull/8292)) -- Revert "ci: disable link-dead-code in coverage build ([#8118](https://github.com/paritytech/parity/pull/8118))" ([#8287](https://github.com/paritytech/parity/pull/8287)) -- Bump ethabi & ethereum-types. ([#8258](https://github.com/paritytech/parity/pull/8258)) -- Allow customization of max WS connections. ([#8257](https://github.com/paritytech/parity/pull/8257)) -- Supress TemporaryInvalid verification failures. ([#8256](https://github.com/paritytech/parity/pull/8256)) -- Return null number for pending block in eth_getBlockByNumber ([#8281](https://github.com/paritytech/parity/pull/8281)) -- Use constant durations ([#8278](https://github.com/paritytech/parity/pull/8278)) -- Typo fix: Mode doc - RLP should be client ([#8283](https://github.com/paritytech/parity/pull/8283)) -- Eth_uninstallfilter should return false for non-existent filter ([#8280](https://github.com/paritytech/parity/pull/8280)) -- Update `app_dirs` to 1.2.1 ([#8268](https://github.com/paritytech/parity/pull/8268)) -- Add missing license header for runtime.rs ([#8252](https://github.com/paritytech/parity/pull/8252)) -- Warp-only sync with warp-barrier [blocknumber] flag. ([#8228](https://github.com/paritytech/parity/pull/8228)) -- Replace all Rlp usages with UntrustedRlp except for ethcore views ([#8233](https://github.com/paritytech/parity/pull/8233)) -- Add test for ethstore-cli, fixes [#8027](https://github.com/paritytech/parity/issues/8027) ([#8187](https://github.com/paritytech/parity/pull/8187)) -- Update musicoin spec in line with gmc v2.6.2 ([#8242](https://github.com/paritytech/parity/pull/8242)) -- Fixed ethcore tx_filter ([#8200](https://github.com/paritytech/parity/pull/8200)) -- Update CLI help for jsonrpc-apis, ws-apis and ipc-apis ([#8234](https://github.com/paritytech/parity/pull/8234)) -- Remove network stats ([#8225](https://github.com/paritytech/parity/pull/8225)) -- Node-filter does not use ChainNotify ([#8231](https://github.com/paritytech/parity/pull/8231)) -- Implement hardcoded sync in the light client ([#8075](https://github.com/paritytech/parity/pull/8075)) -- Update some of the dependencies for WASM ([#8223](https://github.com/paritytech/parity/pull/8223)) -- Bump wasmi version ([#8209](https://github.com/paritytech/parity/pull/8209)) -- Updated jsonrpc to point to the 1.11 branch ([#8180](https://github.com/paritytech/parity/pull/8180)) -- Change name Wallet -> UI ([#8164](https://github.com/paritytech/parity/pull/8164)) -- Introduce Parity UI ([#8202](https://github.com/paritytech/parity/pull/8202)) -- Update Changelogs ([#8175](https://github.com/paritytech/parity/pull/8175)) -- Returns number of topcis to take fr.. ([#8199](https://github.com/paritytech/parity/pull/8199)) -- Make docopt usage non-const ([#8189](https://github.com/paritytech/parity/pull/8189)) -- Avoid allocations when computing triehash. ([#8176](https://github.com/paritytech/parity/pull/8176)) -- Handle rlp decoding Result in patricia trie ([#8166](https://github.com/paritytech/parity/pull/8166)) -- Bump wasm libs ([#8171](https://github.com/paritytech/parity/pull/8171)) -- Re-enable signer, even with no UI. ([#8167](https://github.com/paritytech/parity/pull/8167)) -- Update daemonize ([#8165](https://github.com/paritytech/parity/pull/8165)) -- Some tiny modifications. ([#8163](https://github.com/paritytech/parity/pull/8163)) -- Secretstore: store key author address in db ([#7887](https://github.com/paritytech/parity/pull/7887)) -- Rename DatabaseValueView::new to from_rlp ([#8159](https://github.com/paritytech/parity/pull/8159)) -- Dapps: update parity-ui dependencies ([#8160](https://github.com/paritytech/parity/pull/8160)) -- Disable UI by default. ([#8105](https://github.com/paritytech/parity/pull/8105)) -- Fix wasmi x32 builds ([#8155](https://github.com/paritytech/parity/pull/8155)) -- Postpone Kovan hard fork ([#8137](https://github.com/paritytech/parity/pull/8137)) -- Secretstore: ability to identify requester via Public/Address ([#7886](https://github.com/paritytech/parity/pull/7886)) -- Optional dependency on secp256k1 for ethcrypto ([#8109](https://github.com/paritytech/parity/pull/8109)) -- Network: init discovery using healthy nodes ([#8061](https://github.com/paritytech/parity/pull/8061)) -- Check one step deeper if we're on release track branches ([#8134](https://github.com/paritytech/parity/pull/8134)) -- Explicitly mention pruning_history uses RAM ([#8130](https://github.com/paritytech/parity/pull/8130)) -- Remove `ethcrypto::{en,de}crypt_single_message`. ([#8126](https://github.com/paritytech/parity/pull/8126)) -- Fix typo ([#8124](https://github.com/paritytech/parity/pull/8124)) -- Secret_store: use `ecies::encrypt`/`ecies::decrypt`. ([#8125](https://github.com/paritytech/parity/pull/8125)) -- Fix comment for fn gas() in wasm/runtime ([#8122](https://github.com/paritytech/parity/pull/8122)) -- Structured rlp encoding in journaldb ([#8047](https://github.com/paritytech/parity/pull/8047)) -- Ci: disable link-dead-code in coverage build ([#8118](https://github.com/paritytech/parity/pull/8118)) -- Fix trace filter returning returning unrelated reward calls, closes [#8070](https://github.com/paritytech/parity/issues/8070) ([#8098](https://github.com/paritytech/parity/pull/8098)) -- Const time comparison ([#8113](https://github.com/paritytech/parity/pull/8113)) -- Replace reqwest with hyper ([#8099](https://github.com/paritytech/parity/pull/8099)) -- More dos protection ([#8104](https://github.com/paritytech/parity/pull/8104)) -- Remove the time dependency where possible ([#8100](https://github.com/paritytech/parity/pull/8100)) -- Fix comment for gas extern in Wasm runtime ([#8101](https://github.com/paritytech/parity/pull/8101)) -- Replace std::env::temp_dir with tempdir in tests ([#8103](https://github.com/paritytech/parity/pull/8103)) -- Fix Cargo.lock not parsable ([#8102](https://github.com/paritytech/parity/pull/8102)) -- Additional data in EVMTestClient ([#7964](https://github.com/paritytech/parity/pull/7964)) -- Update serde, serde-derive, ethabi-derive, syn, quote and rlp_derive ([#8085](https://github.com/paritytech/parity/pull/8085)) -- Ethcore-service ([#8089](https://github.com/paritytech/parity/pull/8089)) -- [contract-client] refactor ([#7978](https://github.com/paritytech/parity/pull/7978)) -- Revert removing blooms ([#8066](https://github.com/paritytech/parity/pull/8066)) -- Ethcore test::helpers cleanup ([#8086](https://github.com/paritytech/parity/pull/8086)) -- Add some dos protection ([#8084](https://github.com/paritytech/parity/pull/8084)) -- Wasm libraries bump ([#7970](https://github.com/paritytech/parity/pull/7970)) -- Echo back the message hash of a ping in the pong request ([#8042](https://github.com/paritytech/parity/pull/8042)) -- Add Kovan WASM activation blocknumber ([#8057](https://github.com/paritytech/parity/pull/8057)) -- [ethkey] Unify debug/display for Address/Public/Secret ([#8076](https://github.com/paritytech/parity/pull/8076)) -- Limit incoming connections. ([#8060](https://github.com/paritytech/parity/pull/8060)) -- Max code size on Kovan ([#8067](https://github.com/paritytech/parity/pull/8067)) -- Updater: apply exponential backoff after download failure ([#8059](https://github.com/paritytech/parity/pull/8059)) -- Make blockchain functions more idiomatic, avoid needless writes to cache_man ([#8054](https://github.com/paritytech/parity/pull/8054)) -- Make patricia-trie more idiomatic and remove redundant code ([#8056](https://github.com/paritytech/parity/pull/8056)) -- Abstract devp2p ([#8048](https://github.com/paritytech/parity/pull/8048)) -- Update refs to shell ([#8051](https://github.com/paritytech/parity/pull/8051)) -- Fix cache & snapcraft CI build ([#8052](https://github.com/paritytech/parity/pull/8052)) -- Prelude to the block module cleanup ([#8025](https://github.com/paritytech/parity/pull/8025)) -- Add MCIP-6 Byzyantium transition to Musicoin spec ([#7841](https://github.com/paritytech/parity/pull/7841)) -- Bump master to 1.11.0 ([#8021](https://github.com/paritytech/parity/pull/8021)) -- `client` refactoring ([#7038](https://github.com/paritytech/parity/pull/7038)) -- [hardware wallet] sleeping -> pollling ([#8018](https://github.com/paritytech/parity/pull/8018)) -- Fixed broken link in README ([#8012](https://github.com/paritytech/parity/pull/8012)) -- Support parity protocol. ([#8035](https://github.com/paritytech/parity/pull/8035)) -- Add changelog for 1.8.11 stable and 1.9.4 beta ([#8017](https://github.com/paritytech/parity/pull/8017)) -- Fix for verify_block_basic crashing on invalid transaction rlp ([#8032](https://github.com/paritytech/parity/pull/8032)) -- Extract the hard dependency on rocksdb from the light client ([#8034](https://github.com/paritytech/parity/pull/8034)) -- Fixed parsing ethash seals and verify_block_undordered ([#8031](https://github.com/paritytech/parity/pull/8031)) -- Fixed ethstore sign ([#8026](https://github.com/paritytech/parity/pull/8026)) -- Ci: Fix cargo cache ([#7968](https://github.com/paritytech/parity/pull/7968)) -- Update ref to new shell ([#8024](https://github.com/paritytech/parity/pull/8024)) +- Backports to 2.0.0-beta ([#9094](https://github.com/paritytech/parity-ethereum/pull/9094)) + - Parity-version: betalize 2.0 + - Multiple improvements to discovery ping handling ([#8771](https://github.com/paritytech/parity-ethereum/pull/8771)) + - Discovery: Only add nodes to routing table after receiving pong. + - Discovery: Refactor packet creation into its own function. + - Discovery: Additional testing for new add_node behavior. + - Discovery: Track expiration of pings to non-yet-in-bucket nodes. + - Discovery: Verify echo hash on pong packets. + - Discovery: Track timeouts on FIND_NODE requests. + - Discovery: Retry failed pings with exponential backoff. + - !fixup Use slice instead of Vec for request_backoff. + - Add separate database directory for light client ([#9064](https://github.com/paritytech/parity-ethereum/pull/9064)) + - Add separate default DB path for light client ([#8927](https://github.com/paritytech/parity-ethereum/pull/8927)) + - Improve readability + - Revert "Replace `std::env::home_dir` with `dirs::home_dir` ([#9077](https://github.com/paritytech/parity-ethereum/pull/9077))" ([#9097](https://github.com/paritytech/parity-ethereum/pull/9097)) + - Revert "Replace `std::env::home_dir` with `dirs::home_dir` ([#9077](https://github.com/paritytech/parity-ethereum/pull/9077))" + - This reverts commit 7e77932. + - Restore some of the changes + - Update parity-common + - Offload cull to IoWorker. ([#9099](https://github.com/paritytech/parity-ethereum/pull/9099)) + - Fix work-notify. ([#9104](https://github.com/paritytech/parity-ethereum/pull/9104)) + - Update hidapi, fixes [#7542](https://github.com/paritytech/parity-ethereum/issues/7542) ([#9108](https://github.com/paritytech/parity-ethereum/pull/9108)) + - Docker: add cmake dependency ([#9111](https://github.com/paritytech/parity-ethereum/pull/9111)) + - Update light client hardcoded headers ([#9098](https://github.com/paritytech/parity-ethereum/pull/9098)) + - Insert Kovan hardcoded headers until 7690241 + - Insert Kovan hardcoded headers until block 7690241 + - Insert Ropsten hardcoded headers until 3612673 + - Insert Mainnet hardcoded headers until block 5941249 + - Make sure to produce full blocks. ([#9115](https://github.com/paritytech/parity-ethereum/pull/9115)) + - Insert ETC (classic) hardcoded headers until block 6170625 ([#9121](https://github.com/paritytech/parity-ethereum/pull/9121)) + - Fix verification in ethcore-sync collect_blocks ([#9135](https://github.com/paritytech/parity-ethereum/pull/9135)) + - Completely remove all dapps struct from rpc ([#9107](https://github.com/paritytech/parity-ethereum/pull/9107)) + - Completely remove all dapps struct from rpc + - Remove unused pub use + - `evm bench` fix broken dependencies ([#9134](https://github.com/paritytech/parity-ethereum/pull/9134)) + - `evm bench` use valid dependencies + - Benchmarks of the `evm` used stale versions of a couple a crates that this commit fixes! + - Fix warnings + - Update snapcraft.yaml ([#9132](https://github.com/paritytech/parity-ethereum/pull/9132)) +- Parity Ethereum 2.0.0 ([#9052](https://github.com/paritytech/parity-ethereum/pull/9052)) +- Don't fetch snapshot chunks at random ([#9088](https://github.com/paritytech/parity-ethereum/pull/9088)) +- Remove the dapps system ([#9017](https://github.com/paritytech/parity-ethereum/pull/9017)) +- Fix nightly warnings ([#9080](https://github.com/paritytech/parity-ethereum/pull/9080)) +- Db: remove wal disabling / fast-and-loose option. ([#8963](https://github.com/paritytech/parity-ethereum/pull/8963)) +- Transactions hashes missing in trace_replayBlockTransactions method result [#8725](https://github.com/paritytech/parity-ethereum/issues/8725) ([#8883](https://github.com/paritytech/parity-ethereum/pull/8883)) +- Delete crates from parity-ethereum and fetch them from parity-common instead ([#9083](https://github.com/paritytech/parity-ethereum/pull/9083)) +- Updater verification ([#8787](https://github.com/paritytech/parity-ethereum/pull/8787)) +- Phrasing, precisions and typos in CLI help ([#9060](https://github.com/paritytech/parity-ethereum/pull/9060)) +- Some work towards iOS build ([#9045](https://github.com/paritytech/parity-ethereum/pull/9045)) +- Clean up deprecated options and add CHECK macro ([#9036](https://github.com/paritytech/parity-ethereum/pull/9036)) +- Replace `std::env::home_dir` with `dirs::home_dir` ([#9077](https://github.com/paritytech/parity-ethereum/pull/9077)) +- Fix warning in secret-store test ([#9074](https://github.com/paritytech/parity-ethereum/pull/9074)) +- Seedhashcompute remove needless `new` impl ([#9063](https://github.com/paritytech/parity-ethereum/pull/9063)) +- Remove trait bounds from several structs ([#9055](https://github.com/paritytech/parity-ethereum/pull/9055)) +- Docs: add changelog for 1.10.9 stable and 1.11.6 beta ([#9069](https://github.com/paritytech/parity-ethereum/pull/9069)) +- Enable test in `miner/pool/test` ([#9072](https://github.com/paritytech/parity-ethereum/pull/9072)) +- Fetch: replace futures-timer with tokio-timer ([#9066](https://github.com/paritytech/parity-ethereum/pull/9066)) +- Remove util-error ([#9054](https://github.com/paritytech/parity-ethereum/pull/9054)) +- Fixes for misbehavior reporting in AuthorityRound ([#8998](https://github.com/paritytech/parity-ethereum/pull/8998)) +- A last bunch of txqueue performance optimizations ([#9024](https://github.com/paritytech/parity-ethereum/pull/9024)) +- Reduce number of constraints for triedb types ([#9043](https://github.com/paritytech/parity-ethereum/pull/9043)) +- Bump fs-swap to 0.2.3 so it is compatible with osx 10.11 again ([#9050](https://github.com/paritytech/parity-ethereum/pull/9050)) +- Recursive test ([#9042](https://github.com/paritytech/parity-ethereum/pull/9042)) +- Introduce more optional features in ethcore ([#9020](https://github.com/paritytech/parity-ethereum/pull/9020)) +- Update ETSC bootnodes ([#9038](https://github.com/paritytech/parity-ethereum/pull/9038)) +- Optimize pending transactions filter ([#9026](https://github.com/paritytech/parity-ethereum/pull/9026)) +- Eip160/eip161 spec: u64 -> BlockNumber ([#9044](https://github.com/paritytech/parity-ethereum/pull/9044)) +- Move the C/C++ example to another directory ([#9032](https://github.com/paritytech/parity-ethereum/pull/9032)) +- Bump parking_lot to 0.6 ([#9013](https://github.com/paritytech/parity-ethereum/pull/9013)) +- Never drop local transactions from different senders. ([#9002](https://github.com/paritytech/parity-ethereum/pull/9002)) +- Precise HTTP or WebSockets for JSON-RPC options ([#9027](https://github.com/paritytech/parity-ethereum/pull/9027)) +- Recently rejected cache for transaction queue ([#9005](https://github.com/paritytech/parity-ethereum/pull/9005)) +- Make HashDB generic ([#8739](https://github.com/paritytech/parity-ethereum/pull/8739)) +- Only return error log for rustls ([#9025](https://github.com/paritytech/parity-ethereum/pull/9025)) +- Update Changelogs for 1.10.8 and 1.11.5 ([#9012](https://github.com/paritytech/parity-ethereum/pull/9012)) +- Attempt to graceful shutdown in case of panics ([#8999](https://github.com/paritytech/parity-ethereum/pull/8999)) +- Simplify kvdb error types ([#8924](https://github.com/paritytech/parity-ethereum/pull/8924)) +- Add option for user to set max size limit for RPC requests ([#9010](https://github.com/paritytech/parity-ethereum/pull/9010)) +- Bump ntp to 0.5.0 ([#9009](https://github.com/paritytech/parity-ethereum/pull/9009)) +- Removed duplicate dependency ([#9021](https://github.com/paritytech/parity-ethereum/pull/9021)) +- Minimal effective gas price in the queue ([#8934](https://github.com/paritytech/parity-ethereum/pull/8934)) +- Parity: fix db path when migrating to blooms db ([#8975](https://github.com/paritytech/parity-ethereum/pull/8975)) +- Preserve the current abort behavior ([#8995](https://github.com/paritytech/parity-ethereum/pull/8995)) +- Improve should_replace on NonceAndGasPrice ([#8980](https://github.com/paritytech/parity-ethereum/pull/8980)) +- Tentative fix for missing dependency error ([#8973](https://github.com/paritytech/parity-ethereum/pull/8973)) +- Refactor evm Instruction to be a c-like enum ([#8914](https://github.com/paritytech/parity-ethereum/pull/8914)) +- Fix deadlock in blockchain. ([#8977](https://github.com/paritytech/parity-ethereum/pull/8977)) +- Snap: downgrade rust to revision 1.26.2, ref snapcraft/+bug/1778530 ([#8984](https://github.com/paritytech/parity-ethereum/pull/8984)) +- Use local parity-dapps-glue instead of crate published at crates.io ([#8983](https://github.com/paritytech/parity-ethereum/pull/8983)) +- Parity: omit redundant last imported block number in light sync informant ([#8962](https://github.com/paritytech/parity-ethereum/pull/8962)) +- Disable hardware-wallets on platforms that don't support `libusb` ([#8464](https://github.com/paritytech/parity-ethereum/pull/8464)) +- Bump error-chain and quick_error versions ([#8972](https://github.com/paritytech/parity-ethereum/pull/8972)) +- Evm benchmark utilities ([#8944](https://github.com/paritytech/parity-ethereum/pull/8944)) +- Parity: hide legacy options from cli --help ([#8967](https://github.com/paritytech/parity-ethereum/pull/8967)) +- Scripts: fix docker build tag on latest using master ([#8952](https://github.com/paritytech/parity-ethereum/pull/8952)) +- Add type for passwords. ([#8920](https://github.com/paritytech/parity-ethereum/pull/8920)) +- Deps: bump fs-swap ([#8953](https://github.com/paritytech/parity-ethereum/pull/8953)) +- Eliminate some more `transmute()` ([#8879](https://github.com/paritytech/parity-ethereum/pull/8879)) +- Restrict vault.json permssion to owner and using random suffix for temp vault.json file ([#8932](https://github.com/paritytech/parity-ethereum/pull/8932)) +- Print SS.self_public when starting SS node ([#8949](https://github.com/paritytech/parity-ethereum/pull/8949)) +- Scripts: minor improvements ([#8930](https://github.com/paritytech/parity-ethereum/pull/8930)) +- Rpc: cap gas limit of local calls ([#8943](https://github.com/paritytech/parity-ethereum/pull/8943)) +- Docs: update changelogs ([#8931](https://github.com/paritytech/parity-ethereum/pull/8931)) +- Ethcore: fix compilation when using slow-blocks or evm-debug features ([#8936](https://github.com/paritytech/parity-ethereum/pull/8936)) +- Fixed blooms dir creation ([#8941](https://github.com/paritytech/parity-ethereum/pull/8941)) +- Update hardcoded headers ([#8925](https://github.com/paritytech/parity-ethereum/pull/8925)) +- New blooms database ([#8712](https://github.com/paritytech/parity-ethereum/pull/8712)) +- Ethstore: retry deduplication of wallet file names until success ([#8910](https://github.com/paritytech/parity-ethereum/pull/8910)) +- Update ropsten.json ([#8926](https://github.com/paritytech/parity-ethereum/pull/8926)) +- Include node identity in the P2P advertised client version. ([#8830](https://github.com/paritytech/parity-ethereum/pull/8830)) +- Allow disabling local-by-default for transactions with new config entry ([#8882](https://github.com/paritytech/parity-ethereum/pull/8882)) +- Allow Poll Lifetime to be configured via CLI ([#8885](https://github.com/paritytech/parity-ethereum/pull/8885)) +- Cleanup nibbleslice ([#8915](https://github.com/paritytech/parity-ethereum/pull/8915)) +- Hardware-wallets `Clean up things I missed in the latest PR` ([#8890](https://github.com/paritytech/parity-ethereum/pull/8890)) +- Remove debian/.deb and centos/.rpm packaging scripts ([#8887](https://github.com/paritytech/parity-ethereum/pull/8887)) +- Remove a weird emoji in new_social docs ([#8913](https://github.com/paritytech/parity-ethereum/pull/8913)) +- Minor fix in chain supplier and light provider ([#8906](https://github.com/paritytech/parity-ethereum/pull/8906)) +- Block 0 is valid in queries ([#8891](https://github.com/paritytech/parity-ethereum/pull/8891)) +- Fixed osx permissions ([#8901](https://github.com/paritytech/parity-ethereum/pull/8901)) +- Atomic create new files with permissions to owner in ethstore ([#8896](https://github.com/paritytech/parity-ethereum/pull/8896)) +- Add ETC Cooperative-run load balanced parity node ([#8892](https://github.com/paritytech/parity-ethereum/pull/8892)) +- Add support for --chain tobalaba ([#8870](https://github.com/paritytech/parity-ethereum/pull/8870)) +- Fix some warns on nightly ([#8889](https://github.com/paritytech/parity-ethereum/pull/8889)) +- Add new ovh bootnodes and fix port for foundation bootnode 3.2 ([#8886](https://github.com/paritytech/parity-ethereum/pull/8886)) +- Secretstore: service pack 1 ([#8435](https://github.com/paritytech/parity-ethereum/pull/8435)) +- Handle removed logs in filter changes and add geth compatibility field ([#8796](https://github.com/paritytech/parity-ethereum/pull/8796)) +- Fixed ipc leak, closes [#8774](https://github.com/paritytech/parity-ethereum/issues/8774) ([#8876](https://github.com/paritytech/parity-ethereum/pull/8876)) +- Scripts: remove md5 checksums ([#8884](https://github.com/paritytech/parity-ethereum/pull/8884)) +- Hardware_wallet/Ledger `Sign messages` + some refactoring ([#8868](https://github.com/paritytech/parity-ethereum/pull/8868)) +- Check whether we need resealing in miner and unwrap has_account in account_provider ([#8853](https://github.com/paritytech/parity-ethereum/pull/8853)) +- Docker: Fix alpine build ([#8878](https://github.com/paritytech/parity-ethereum/pull/8878)) +- Remove mac os installers etc ([#8875](https://github.com/paritytech/parity-ethereum/pull/8875)) +- Readme.md: update the list of dependencies ([#8864](https://github.com/paritytech/parity-ethereum/pull/8864)) +- Fix concurrent access to signer queue ([#8854](https://github.com/paritytech/parity-ethereum/pull/8854)) +- Tx permission contract improvement ([#8400](https://github.com/paritytech/parity-ethereum/pull/8400)) +- Limit the number of transactions in pending set ([#8777](https://github.com/paritytech/parity-ethereum/pull/8777)) +- Use sealing.enabled to emit eth_mining information ([#8844](https://github.com/paritytech/parity-ethereum/pull/8844)) +- Don't allocate in expect_valid_rlp unless necessary ([#8867](https://github.com/paritytech/parity-ethereum/pull/8867)) +- Fix Cli Return Code on --help for ethkey, ethstore & whisper ([#8863](https://github.com/paritytech/parity-ethereum/pull/8863)) +- Fix subcrate test compile ([#8862](https://github.com/paritytech/parity-ethereum/pull/8862)) +- Network-devp2p: downgrade logging to debug, add target ([#8784](https://github.com/paritytech/parity-ethereum/pull/8784)) +- Clearing up a comment about the prefix for signing ([#8828](https://github.com/paritytech/parity-ethereum/pull/8828)) +- Disable parallel verification and skip verifiying already imported txs. ([#8834](https://github.com/paritytech/parity-ethereum/pull/8834)) +- Devp2p: Move UDP socket handling from Discovery to Host. ([#8790](https://github.com/paritytech/parity-ethereum/pull/8790)) +- Fixed AuthorityRound deadlock on shutdown, closes [#8088](https://github.com/paritytech/parity-ethereum/issues/8088) ([#8803](https://github.com/paritytech/parity-ethereum/pull/8803)) +- Specify critical release flag per network ([#8821](https://github.com/paritytech/parity-ethereum/pull/8821)) +- Fix `deadlock_detection` feature branch compilation ([#8824](https://github.com/paritytech/parity-ethereum/pull/8824)) +- Use system allocator when profiling memory ([#8831](https://github.com/paritytech/parity-ethereum/pull/8831)) +- Added from and to to Receipt ([#8756](https://github.com/paritytech/parity-ethereum/pull/8756)) +- Ethcore: fix ancient block error msg handling ([#8832](https://github.com/paritytech/parity-ethereum/pull/8832)) +- Ci: Fix docker tags ([#8822](https://github.com/paritytech/parity-ethereum/pull/8822)) +- Parity: fix indentation in sync logging ([#8794](https://github.com/paritytech/parity-ethereum/pull/8794)) +- Removed obsolete IpcMode enum ([#8819](https://github.com/paritytech/parity-ethereum/pull/8819)) +- Remove UI related settings from CLI ([#8783](https://github.com/paritytech/parity-ethereum/pull/8783)) +- Remove windows tray and installer ([#8778](https://github.com/paritytech/parity-ethereum/pull/8778)) +- Docs: add changelogs for 1.10.6 and 1.11.3 ([#8810](https://github.com/paritytech/parity-ethereum/pull/8810)) +- Fix ancient blocks queue deadlock ([#8751](https://github.com/paritytech/parity-ethereum/pull/8751)) +- Disallow unsigned transactions in case EIP-86 is disabled ([#8802](https://github.com/paritytech/parity-ethereum/pull/8802)) +- Fix evmbin compilation ([#8795](https://github.com/paritytech/parity-ethereum/pull/8795)) +- Have space between feature cfg flag ([#8791](https://github.com/paritytech/parity-ethereum/pull/8791)) +- Rpc: fix address formatting in TransactionRequest Display ([#8786](https://github.com/paritytech/parity-ethereum/pull/8786)) +- Conditionally compile ethcore public test helpers ([#8743](https://github.com/paritytech/parity-ethereum/pull/8743)) +- Remove Result wrapper from AccountProvider in RPC impls ([#8763](https://github.com/paritytech/parity-ethereum/pull/8763)) +- Update `license header` and `scripts` ([#8666](https://github.com/paritytech/parity-ethereum/pull/8666)) +- Remove HostTrait altogether ([#8681](https://github.com/paritytech/parity-ethereum/pull/8681)) +- Ethcore-sync: fix connection to peers behind chain fork block ([#8710](https://github.com/paritytech/parity-ethereum/pull/8710)) +- Remove public node settings from cli ([#8758](https://github.com/paritytech/parity-ethereum/pull/8758)) +- Custom Error Messages on ENFILE and EMFILE IO Errors ([#8744](https://github.com/paritytech/parity-ethereum/pull/8744)) +- Ci: Fixes for Android Pipeline ([#8745](https://github.com/paritytech/parity-ethereum/pull/8745)) +- Remove NetworkService::config() ([#8653](https://github.com/paritytech/parity-ethereum/pull/8653)) +- Fix XOR distance calculation in discovery Kademlia impl ([#8589](https://github.com/paritytech/parity-ethereum/pull/8589)) +- Print warnings when fetching pending blocks ([#8711](https://github.com/paritytech/parity-ethereum/pull/8711)) +- Fix PoW blockchains sealing notifications in chain_new_blocks ([#8656](https://github.com/paritytech/parity-ethereum/pull/8656)) +- Remove -k/--insecure option from curl installer ([#8719](https://github.com/paritytech/parity-ethereum/pull/8719)) +- Ease tiny-keccak version requirements (1.4.1 -> 1.4) ([#8726](https://github.com/paritytech/parity-ethereum/pull/8726)) +- Bump tinykeccak to 1.4 ([#8728](https://github.com/paritytech/parity-ethereum/pull/8728)) +- Remove a couple of unnecessary `transmute()` ([#8736](https://github.com/paritytech/parity-ethereum/pull/8736)) +- Fix some nits using clippy ([#8731](https://github.com/paritytech/parity-ethereum/pull/8731)) +- Add 'interface' option to cli ([#8699](https://github.com/paritytech/parity-ethereum/pull/8699)) +- Remove unused function new_pow_test_spec ([#8735](https://github.com/paritytech/parity-ethereum/pull/8735)) +- Add a deadlock detection thread ([#8727](https://github.com/paritytech/parity-ethereum/pull/8727)) +- Fix local transactions policy. ([#8691](https://github.com/paritytech/parity-ethereum/pull/8691)) +- Shutdown the Snapshot Service early ([#8658](https://github.com/paritytech/parity-ethereum/pull/8658)) +- Network-devp2p: handle UselessPeer disconnect ([#8686](https://github.com/paritytech/parity-ethereum/pull/8686)) +- Fix compilation error on nightly rust ([#8707](https://github.com/paritytech/parity-ethereum/pull/8707)) +- Add a test for decoding corrupt data ([#8713](https://github.com/paritytech/parity-ethereum/pull/8713)) +- Update dev chain ([#8717](https://github.com/paritytech/parity-ethereum/pull/8717)) +- Remove unused imports ([#8722](https://github.com/paritytech/parity-ethereum/pull/8722)) +- Implement recursive Debug for Nodes in patrica_trie::TrieDB ([#8697](https://github.com/paritytech/parity-ethereum/pull/8697)) +- Parity: trim whitespace when parsing duration strings ([#8692](https://github.com/paritytech/parity-ethereum/pull/8692)) +- Set the request index to that of the current request ([#8683](https://github.com/paritytech/parity-ethereum/pull/8683)) +- Remove empty file ([#8705](https://github.com/paritytech/parity-ethereum/pull/8705)) +- Update mod.rs ([#8695](https://github.com/paritytech/parity-ethereum/pull/8695)) +- Use impl Future in the light client RPC helpers ([#8628](https://github.com/paritytech/parity-ethereum/pull/8628)) +- Fix cli signer ([#8682](https://github.com/paritytech/parity-ethereum/pull/8682)) +- Allow making direct RPC queries from the C API ([#8588](https://github.com/paritytech/parity-ethereum/pull/8588)) +- Remove the error when stopping the network ([#8671](https://github.com/paritytech/parity-ethereum/pull/8671)) +- Move connection_filter to the network crate ([#8674](https://github.com/paritytech/parity-ethereum/pull/8674)) +- Remove HostInfo::client_version() and secret() ([#8677](https://github.com/paritytech/parity-ethereum/pull/8677)) +- Refactor EIP150, EIP160 and EIP161 forks to be specified in CommonParams ([#8614](https://github.com/paritytech/parity-ethereum/pull/8614)) +- Parity: improve cli help and logging ([#8665](https://github.com/paritytech/parity-ethereum/pull/8665)) +- Updated tiny-keccak to 1.4.2 ([#8669](https://github.com/paritytech/parity-ethereum/pull/8669)) +- Remove the Keccak C library and use the pure Rust impl ([#8657](https://github.com/paritytech/parity-ethereum/pull/8657)) +- Remove HostInfo::next_nonce ([#8644](https://github.com/paritytech/parity-ethereum/pull/8644)) +- Fix not downloading old blocks ([#8642](https://github.com/paritytech/parity-ethereum/pull/8642)) +- Resumable warp-sync / Seed downloaded snapshots ([#8544](https://github.com/paritytech/parity-ethereum/pull/8544)) +- Don't open Browser post-install on Mac ([#8641](https://github.com/paritytech/parity-ethereum/pull/8641)) +- Changelog for 1.10.4-stable and 1.11.1-beta ([#8637](https://github.com/paritytech/parity-ethereum/pull/8637)) +- Typo ([#8640](https://github.com/paritytech/parity-ethereum/pull/8640)) +- Fork choice and metadata framework for Engine ([#8401](https://github.com/paritytech/parity-ethereum/pull/8401)) +- Check that the Android build doesn't dep on c++_shared ([#8538](https://github.com/paritytech/parity-ethereum/pull/8538)) +- Remove NetworkContext::io_channel() ([#8625](https://github.com/paritytech/parity-ethereum/pull/8625)) +- Fix light sync with initial validator-set contract ([#8528](https://github.com/paritytech/parity-ethereum/pull/8528)) +- Store morden db and keys in "path/to/parity/data/Morden" (ropsten uses "test", like before) ([#8621](https://github.com/paritytech/parity-ethereum/pull/8621)) +- ´main.rs´ typo ([#8629](https://github.com/paritytech/parity-ethereum/pull/8629)) +- Fix BlockReward contract "arithmetic operation overflow" ([#8611](https://github.com/paritytech/parity-ethereum/pull/8611)) +- Gitlab test script fixes ([#8573](https://github.com/paritytech/parity-ethereum/pull/8573)) +- Remove manually added text to the errors ([#8595](https://github.com/paritytech/parity-ethereum/pull/8595)) +- Fix account list double 0x display ([#8596](https://github.com/paritytech/parity-ethereum/pull/8596)) +- Typo: wrong indentation in kovan config ([#8610](https://github.com/paritytech/parity-ethereum/pull/8610)) +- Fix packet count when talking with PAR2 peers ([#8555](https://github.com/paritytech/parity-ethereum/pull/8555)) +- Use full qualified syntax for itertools::Itertools::flatten ([#8606](https://github.com/paritytech/parity-ethereum/pull/8606)) +- 2 tiny modification on snapshot ([#8601](https://github.com/paritytech/parity-ethereum/pull/8601)) +- Fix the mio test again ([#8602](https://github.com/paritytech/parity-ethereum/pull/8602)) +- Remove inject.js server-side injection for dapps ([#8539](https://github.com/paritytech/parity-ethereum/pull/8539)) +- Block_header can fail so return Result ([#8581](https://github.com/paritytech/parity-ethereum/pull/8581)) +- Block::decode() returns Result ([#8586](https://github.com/paritytech/parity-ethereum/pull/8586)) +- Fix compiler warning ([#8590](https://github.com/paritytech/parity-ethereum/pull/8590)) +- Fix Parity UI link ([#8600](https://github.com/paritytech/parity-ethereum/pull/8600)) +- Make mio optional in ethcore-io ([#8537](https://github.com/paritytech/parity-ethereum/pull/8537)) +- Attempt to fix intermittent test failures ([#8584](https://github.com/paritytech/parity-ethereum/pull/8584)) +- Changelog and Readme ([#8591](https://github.com/paritytech/parity-ethereum/pull/8591)) +- Added Dockerfile for alpine linux by @andresilva, closes [#3565](https://github.com/paritytech/parity-ethereum/issues/3565) ([#8587](https://github.com/paritytech/parity-ethereum/pull/8587)) +- Add whisper CLI to the pipelines ([#8578](https://github.com/paritytech/parity-ethereum/pull/8578)) +- Rename `whisper-cli binary` to `whisper` ([#8579](https://github.com/paritytech/parity-ethereum/pull/8579)) +- Changelog nit ([#8585](https://github.com/paritytech/parity-ethereum/pull/8585)) +- Remove unnecessary cloning in overwrite_with ([#8580](https://github.com/paritytech/parity-ethereum/pull/8580)) +- Handle socket address parsing errors ([#8545](https://github.com/paritytech/parity-ethereum/pull/8545)) +- Update CHANGELOG for 1.9, 1.10, and 1.11 ([#8556](https://github.com/paritytech/parity-ethereum/pull/8556)) +- Decoding headers can fail ([#8570](https://github.com/paritytech/parity-ethereum/pull/8570)) +- Refactoring `ethcore-sync` - Fixing warp-sync barrier ([#8543](https://github.com/paritytech/parity-ethereum/pull/8543)) +- Remove State::replace_backend ([#8569](https://github.com/paritytech/parity-ethereum/pull/8569)) +- Make trace-time publishable. ([#8568](https://github.com/paritytech/parity-ethereum/pull/8568)) +- Don't block sync when importing old blocks ([#8530](https://github.com/paritytech/parity-ethereum/pull/8530)) +- Trace precompiled contracts when the transfer value is not zero ([#8486](https://github.com/paritytech/parity-ethereum/pull/8486)) +- Parity as a library ([#8412](https://github.com/paritytech/parity-ethereum/pull/8412)) +- Rlp decode returns Result ([#8527](https://github.com/paritytech/parity-ethereum/pull/8527)) +- Node table sorting according to last contact data ([#8541](https://github.com/paritytech/parity-ethereum/pull/8541)) +- Keep all enacted blocks notify in order ([#8524](https://github.com/paritytech/parity-ethereum/pull/8524)) +- Ethcore, rpc, machine: refactor block reward application and tracing ([#8490](https://github.com/paritytech/parity-ethereum/pull/8490)) +- Consolidate crypto functionality in `ethcore-crypto`. ([#8432](https://github.com/paritytech/parity-ethereum/pull/8432)) +- Eip 145: Bitwise shifting instructions in EVM ([#8451](https://github.com/paritytech/parity-ethereum/pull/8451)) +- Remove expect ([#8536](https://github.com/paritytech/parity-ethereum/pull/8536)) +- Don't panic in import_block if invalid rlp ([#8522](https://github.com/paritytech/parity-ethereum/pull/8522)) +- Pass on storage keys tracing to handle the case when it is not modified ([#8491](https://github.com/paritytech/parity-ethereum/pull/8491)) +- Fetching logs by hash in blockchain database ([#8463](https://github.com/paritytech/parity-ethereum/pull/8463)) +- Transaction Pool improvements ([#8470](https://github.com/paritytech/parity-ethereum/pull/8470)) +- More changes for Android ([#8421](https://github.com/paritytech/parity-ethereum/pull/8421)) +- Enable WebAssembly and Byzantium for Ellaism ([#8520](https://github.com/paritytech/parity-ethereum/pull/8520)) +- Secretstore: merge two types of errors into single one + Error::is_non_fatal ([#8357](https://github.com/paritytech/parity-ethereum/pull/8357)) +- Hardware Wallet trait ([#8071](https://github.com/paritytech/parity-ethereum/pull/8071)) +- Directly return None if tracing is disabled ([#8504](https://github.com/paritytech/parity-ethereum/pull/8504)) +- Show imported messages for light client ([#8517](https://github.com/paritytech/parity-ethereum/pull/8517)) +- Remove unused dependency `bigint` ([#8505](https://github.com/paritytech/parity-ethereum/pull/8505)) +- `duration_ns: u64 -> duration: Duration` ([#8457](https://github.com/paritytech/parity-ethereum/pull/8457)) +- Return error if RLP size of transaction exceeds the limit ([#8473](https://github.com/paritytech/parity-ethereum/pull/8473)) +- Remove three old warp boot nodes. ([#8497](https://github.com/paritytech/parity-ethereum/pull/8497)) +- Update wasmi and pwasm-utils ([#8493](https://github.com/paritytech/parity-ethereum/pull/8493)) +- Update hardcodedSync for Ethereum, Kovan, and Ropsten ([#8489](https://github.com/paritytech/parity-ethereum/pull/8489)) +- Fix snap builds ([#8483](https://github.com/paritytech/parity-ethereum/pull/8483)) +- Bump master to 1.12 ([#8477](https://github.com/paritytech/parity-ethereum/pull/8477)) +- Don't require write lock when fetching status. ([#8481](https://github.com/paritytech/parity-ethereum/pull/8481)) +- Use rename_all for RichBlock and RichHeader serialization ([#8471](https://github.com/paritytech/parity-ethereum/pull/8471)) ## Previous releases -- [CHANGELOG-1.10](docs/CHANGELOG-1.10.md) (_stable_) +- [CHANGELOG-1.11](docs/CHANGELOG-1.11.md) (_stable_) +- [CHANGELOG-1.10](docs/CHANGELOG-1.10.md) (EOL: 2018-07-18) - [CHANGELOG-1.9](docs/CHANGELOG-1.9.md) (EOL: 2018-05-09) - [CHANGELOG-1.8](docs/CHANGELOG-1.8.md) (EOL: 2018-03-22) - [CHANGELOG-1.7](docs/CHANGELOG-1.7.md) (EOL: 2018-01-25) diff --git a/Cargo.lock b/Cargo.lock index 680b9606ec0cbbf164b282fbaf9463a2520e957e..54a05ba05bee2c4e4ce2fbb78ef289b3cbb0de3e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,8 +1,3 @@ -[[package]] -name = "adler32" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "aho-corasick" version = "0.6.4" @@ -22,7 +17,7 @@ version = "1.2.1" source = "git+https://github.com/paritytech/app-dirs-rs#0b37f9481ce29e9d5174ad185bca695b206368eb" dependencies = [ "ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "xdg 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -40,14 +35,6 @@ name = "assert_matches" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "aster" -version = "0.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "atty" version = "0.2.8" @@ -75,7 +62,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)", ] @@ -84,17 +71,12 @@ name = "base-x" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "base32" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "base64" version = "0.6.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)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -103,7 +85,7 @@ name = "base64" version = "0.9.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)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -112,9 +94,9 @@ name = "bincode" version = "0.8.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)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -135,11 +117,6 @@ name = "bitflags" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "bitflags" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "bitflags" version = "0.9.1" @@ -151,31 +128,29 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "bloomchain" -version = "0.2.0" +name = "blooms-db" +version = "0.1.0" dependencies = [ + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethbloom 0.5.0 (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)", + "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)", ] [[package]] name = "bn" version = "0.4.4" -source = "git+https://github.com/paritytech/bn#964b48fad5dffbaa124c2f10699e76faf5846c4e" +source = "git+https://github.com/paritytech/bn#2a71dbde5ca93451c8da2135767896a64483759e" dependencies = [ - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crunchy 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "build_const" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "byteorder" -version = "1.2.1" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -183,13 +158,13 @@ name = "bytes" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[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)", @@ -244,33 +219,33 @@ dependencies = [ ] [[package]] -name = "common-types" -version = "0.1.0" +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ethcore-bytes 0.1.0", - "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethjson 0.1.0", - "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.2", - "rlp 0.2.1", - "rlp_derive 0.1.0", - "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "conv" -version = "0.3.3" +name = "cmake" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "crc" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "common-types" +version = "0.1.0" dependencies = [ - "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethjson 0.1.0", + "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", + "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", + "rlp_derive 0.1.0", + "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -344,6 +319,11 @@ name = "crunchy" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "crunchy" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ct-logs" version = "0.2.0" @@ -362,11 +342,6 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "custom_derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "daemonize" version = "0.2.3" @@ -382,11 +357,11 @@ 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)", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "journaldb 0.1.0", + "journaldb 0.2.0", ] [[package]] @@ -396,7 +371,7 @@ 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)", "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -441,13 +416,21 @@ dependencies = [ "backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "error-chain" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "eth-secp256k1" 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)", ] @@ -459,7 +442,7 @@ dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.3.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 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 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)", "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -487,10 +470,10 @@ version = "1.12.0" dependencies = [ "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.2", + "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", "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)", ] @@ -503,7 +486,7 @@ dependencies = [ "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "fixed-hash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -512,19 +495,17 @@ name = "ethcore" version = "1.12.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bloomchain 0.2.0", + "blooms-db 0.1.0", "bn 0.4.4 (git+https://github.com/paritytech/bn)", - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "common-types 0.1.0", "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.12.0", "ethcore-bloom-journal 0.1.0", - "ethcore-bytes 0.1.0", - "ethcore-crypto 0.1.0", "ethcore-io 1.12.0", "ethcore-logger 1.12.0", "ethcore-miner 1.12.0", @@ -535,30 +516,34 @@ dependencies = [ "ethkey 0.3.0", "ethstore 0.2.0", "evm 0.1.0", - "fetch 0.1.0", + "fake-hardware-wallet 0.0.1", "hardware-wallet 1.12.0", - "hashdb 0.1.1", + "hashdb 0.2.0 (git+https://github.com/paritytech/parity-common)", "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", - "keccak-hash 0.1.2", - "kvdb 0.1.0", - "kvdb-memorydb 0.1.0", - "kvdb-rocksdb 0.1.0", + "journaldb 0.2.0", + "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", + "keccak-hasher 0.1.0", + "kvdb 0.1.0 (git+https://github.com/paritytech/parity-common)", + "kvdb-memorydb 0.1.0 (git+https://github.com/paritytech/parity-common)", + "kvdb-rocksdb 0.1.0 (git+https://github.com/paritytech/parity-common)", "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)", "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.1 (git+https://github.com/paritytech/parity-common)", "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-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", + "parity-crypto 0.1.0 (git+https://github.com/paritytech/parity-common)", "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.1 (git+https://github.com/paritytech/parity-common)", + "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", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", "rlp_compress 0.1.0", "rlp_derive 0.1.0", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -567,11 +552,10 @@ dependencies = [ "stop-guard 0.1.0", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "trace-time 0.1.0", - "trie-standardmap 0.1.0", - "triehash 0.1.0", + "trie-standardmap 0.1.0 (git+https://github.com/paritytech/parity-common)", + "triehash-ethereum 0.2.0", "unexpected 0.1.0", "using_queue 0.1.0", - "util-error 0.1.0", "vm 0.1.0", "wasm 0.1.0", ] @@ -583,21 +567,6 @@ dependencies = [ "siphasher 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "ethcore-bytes" -version = "0.1.0" - -[[package]] -name = "ethcore-crypto" -version = "0.1.0" -dependencies = [ - "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.12.1 (git+https://github.com/paritytech/ring)", - "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "ethcore-devtools" version = "1.12.0" @@ -611,7 +580,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)", @@ -622,35 +591,37 @@ name = "ethcore-light" version = "1.12.0" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.12.0", - "ethcore-bytes 0.1.0", "ethcore-io 1.12.0", "ethcore-network 1.12.0", "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 (git+https://github.com/paritytech/parity-common)", "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", - "kvdb 0.1.0", - "kvdb-memorydb 0.1.0", + "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", + "keccak-hasher 0.1.0", + "kvdb 0.1.0 (git+https://github.com/paritytech/parity-common)", + "kvdb-memorydb 0.1.0 (git+https://github.com/paritytech/parity-common)", "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.1 (git+https://github.com/paritytech/parity-common)", + "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "patricia-trie 0.2.1 (git+https://github.com/paritytech/parity-common)", + "patricia-trie-ethereum 0.1.0", + "plain_hasher 0.1.0 (git+https://github.com/paritytech/parity-common)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rlp 0.2.1", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", "rlp_derive 0.1.0", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "stats 0.1.0", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "triehash 0.1.0", + "triehash-ethereum 0.2.0", "vm 0.1.0", ] @@ -664,7 +635,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)", ] @@ -675,7 +646,7 @@ version = "1.12.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.12.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -685,17 +656,16 @@ dependencies = [ "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.2", + "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", "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", - "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rlp 0.2.1", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "trace-time 0.1.0", - "transaction-pool 1.12.0", + "transaction-pool 1.12.1", "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -704,14 +674,14 @@ name = "ethcore-network" version = "1.12.0" dependencies = [ "assert_matches 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-crypto 0.1.0", + "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-io 1.12.0", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rlp 0.2.1", + "parity-crypto 0.1.0 (git+https://github.com/paritytech/parity-common)", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", "snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)", ] @@ -722,9 +692,7 @@ dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "assert_matches 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-bytes 0.1.0", - "ethcore-crypto 0.1.0", + "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-io 1.12.0", "ethcore-logger 1.12.0", "ethcore-network 1.12.0", @@ -732,17 +700,19 @@ dependencies = [ "ethkey 0.3.0", "igd 0.7.0 (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-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", "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", + "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", + "parity-crypto 0.1.0 (git+https://github.com/paritytech/parity-common)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "path 0.1.1 (git+https://github.com/paritytech/parity-common)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rlp 0.2.1", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", "rust-crypto 0.2.36 (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 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 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)", "slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -755,13 +725,11 @@ dependencies = [ name = "ethcore-private-tx" version = "1.0.0" dependencies = [ - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.12.0", - "ethcore-bytes 0.1.0", - "ethcore-crypto 0.1.0", "ethcore-io 1.12.0", "ethcore-logger 1.12.0", "ethcore-miner 1.12.0", @@ -771,15 +739,18 @@ dependencies = [ "ethkey 0.3.0", "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.2", + "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", "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", + "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", + "parity-crypto 0.1.0 (git+https://github.com/paritytech/parity-common)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "patricia-trie 0.2.1 (git+https://github.com/paritytech/parity-common)", + "patricia-trie-ethereum 0.1.0", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", - "rlp 0.2.1", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", "rlp_derive 0.1.0", "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 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 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)", "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -790,13 +761,11 @@ dependencies = [ name = "ethcore-secretstore" version = "1.0.0" dependencies = [ - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.12.0", - "ethcore-bytes 0.1.0", - "ethcore-crypto 0.1.0", "ethcore-logger 1.12.0", "ethcore-sync 1.12.0", "ethcore-transaction 0.1.0", @@ -805,14 +774,16 @@ 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)", "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.2", - "kvdb 0.1.0", - "kvdb-rocksdb 0.1.0", + "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", + "kvdb 0.1.0 (git+https://github.com/paritytech/parity-common)", + "kvdb-rocksdb 0.1.0 (git+https://github.com/paritytech/parity-common)", "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)", + "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", + "parity-crypto 0.1.0 (git+https://github.com/paritytech/parity-common)", + "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 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 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)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -830,13 +801,13 @@ name = "ethcore-service" version = "0.1.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.12.0", "ethcore-io 1.12.0", "ethcore-private-tx 1.0.0", "ethcore-sync 1.12.0", - "kvdb 0.1.0", - "kvdb-rocksdb 0.1.0", + "kvdb 0.1.0 (git+https://github.com/paritytech/parity-common)", + "kvdb-rocksdb 0.1.0 (git+https://github.com/paritytech/parity-common)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "stop-guard 0.1.0", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -853,9 +824,9 @@ dependencies = [ "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-tcp-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", - "keccak-hash 0.1.2", + "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", "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)", ] @@ -866,7 +837,6 @@ version = "1.12.0" dependencies = [ "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.12.0", - "ethcore-bytes 0.1.0", "ethcore-io 1.12.0", "ethcore-light 1.12.0", "ethcore-network 1.12.0", @@ -875,22 +845,25 @@ 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 (git+https://github.com/paritytech/parity-common)", "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", - "kvdb 0.1.0", - "kvdb-memorydb 0.1.0", + "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", + "keccak-hasher 0.1.0", + "kvdb 0.1.0 (git+https://github.com/paritytech/parity-common)", + "kvdb-memorydb 0.1.0 (git+https://github.com/paritytech/parity-common)", "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", + "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "plain_hasher 0.1.0 (git+https://github.com/paritytech/parity-common)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rlp 0.2.1", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", "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)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "trace-time 0.1.0", - "triehash 0.1.0", + "triehash-ethereum 0.2.0", ] [[package]] @@ -902,8 +875,8 @@ dependencies = [ "ethkey 0.3.0", "evm 0.1.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.2", - "rlp 0.2.1", + "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "unexpected 0.1.0", ] @@ -918,7 +891,7 @@ dependencies = [ "ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "fixed-hash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "uint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -927,7 +900,7 @@ name = "ethereum-types-serialize" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -936,7 +909,7 @@ version = "0.1.0" dependencies = [ "ethereum-types 0.3.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 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 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)", ] @@ -945,18 +918,20 @@ dependencies = [ name = "ethkey" version = "0.3.0" dependencies = [ - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "edit-distance 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)", - "ethcore-crypto 0.1.0", "ethereum-types 0.3.2 (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)", "mem 0.1.0", + "parity-crypto 0.1.0 (git+https://github.com/paritytech/parity-common)", "parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.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.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -970,7 +945,7 @@ dependencies = [ "panic_hook 0.1.0", "parity-wordlist 1.2.0 (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 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -979,19 +954,19 @@ dependencies = [ name = "ethstore" version = "0.2.0" dependencies = [ - "dir 0.1.0", - "ethcore-crypto 0.1.0", + "dir 0.1.1", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "itertools 0.5.10 (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)", "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-crypto 0.1.0 (git+https://github.com/paritytech/parity-common)", "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)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 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)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1004,14 +979,14 @@ 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 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1023,11 +998,11 @@ dependencies = [ "bit-set 0.4.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)", - "keccak-hash 0.1.2", + "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", "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", ] @@ -1038,15 +1013,15 @@ version = "0.1.0" dependencies = [ "docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.12.0", - "ethcore-bytes 0.1.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "evm 0.1.0", "panic_hook 0.1.0", + "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", "pretty_assertions 0.1.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 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "vm 0.1.0", @@ -1061,6 +1036,14 @@ dependencies = [ "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fake-hardware-wallet" +version = "0.0.1" +dependencies = [ + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethkey 0.3.0", +] + [[package]] name = "fdlimit" version = "0.1.1" @@ -1075,11 +1058,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)", ] @@ -1100,18 +1083,20 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "flate2" -version = "1.0.1" +name = "fnv" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide_c_api 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] -name = "fnv" -version = "1.0.5" +name = "fs-swap" +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)", +] [[package]] name = "fuchsia-zircon" @@ -1141,14 +1126,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" @@ -1159,11 +1136,6 @@ name = "getopts" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "glob" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "globset" version = "0.2.1" @@ -1190,18 +1162,20 @@ 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)", "trezor-sys 1.0.0 (git+https://github.com/paritytech/trezor-sys)", ] [[package]] name = "hashdb" -version = "0.1.1" +version = "0.2.0" +source = "git+https://github.com/paritytech/parity-common#0045887fecd2fec39e56c962a0b27e2caf3b9474" 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]] @@ -1228,9 +1202,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "hidapi" version = "0.3.1" -source = "git+https://github.com/paritytech/hidapi-rs#70ec4bd1b755ec5dd32ad2be0c8345864147c8bc" +source = "git+https://github.com/paritytech/hidapi-rs#d4d323767d6f27cf5a3d73fbae0b0f2134d579bf" 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)", ] @@ -1345,32 +1319,32 @@ 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 (git+https://github.com/paritytech/parity-common)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.2", - "kvdb 0.1.0", - "kvdb-memorydb 0.1.0", + "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", + "keccak-hasher 0.1.0", + "kvdb 0.1.0 (git+https://github.com/paritytech/parity-common)", + "kvdb-memorydb 0.1.0 (git+https://github.com/paritytech/parity-common)", "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", - "rlp 0.2.1", - "util-error 0.1.0", + "memorydb 0.2.1 (git+https://github.com/paritytech/parity-common)", + "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "plain_hasher 0.1.0 (git+https://github.com/paritytech/parity-common)", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", ] [[package]] name = "jsonrpc-core" version = "8.0.1" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#06bec6ab682ec4ce16d7e7daf2612870c4272028" +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)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 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)", ] @@ -1378,7 +1352,7 @@ dependencies = [ [[package]] name = "jsonrpc-http-server" version = "8.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#06bec6ab682ec4ce16d7e7daf2612870c4272028" +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)", @@ -1391,7 +1365,7 @@ dependencies = [ [[package]] name = "jsonrpc-ipc-server" version = "8.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#06bec6ab682ec4ce16d7e7daf2612870c4272028" +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)", @@ -1403,27 +1377,27 @@ dependencies = [ [[package]] name = "jsonrpc-macros" version = "8.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#06bec6ab682ec4ce16d7e7daf2612870c4272028" +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)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "jsonrpc-pubsub" version = "8.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#06bec6ab682ec4ce16d7e7daf2612870c4272028" +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#06bec6ab682ec4ce16d7e7daf2612870c4272028" +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)", @@ -1436,25 +1410,25 @@ dependencies = [ [[package]] name = "jsonrpc-tcp-server" version = "8.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#06bec6ab682ec4ce16d7e7daf2612870c4272028" +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#06bec6ab682ec4ce16d7e7daf2612870c4272028" +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)", ] @@ -1462,9 +1436,19 @@ dependencies = [ [[package]] name = "keccak-hash" version = "0.1.2" +source = "git+https://github.com/paritytech/parity-common#0045887fecd2fec39e56c962a0b27e2caf3b9474" dependencies = [ "ethereum-types 0.3.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)", +] + +[[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 (git+https://github.com/paritytech/parity-common)", + "plain_hasher 0.1.0 (git+https://github.com/paritytech/parity-common)", "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1480,34 +1464,36 @@ dependencies = [ [[package]] name = "kvdb" version = "0.1.0" +source = "git+https://github.com/paritytech/parity-common#0045887fecd2fec39e56c962a0b27e2caf3b9474" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-bytes 0.1.0", + "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", ] [[package]] name = "kvdb-memorydb" version = "0.1.0" +source = "git+https://github.com/paritytech/parity-common#0045887fecd2fec39e56c962a0b27e2caf3b9474" dependencies = [ - "kvdb 0.1.0", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "kvdb 0.1.0 (git+https://github.com/paritytech/parity-common)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "kvdb-rocksdb" version = "0.1.0" +source = "git+https://github.com/paritytech/parity-common#0045887fecd2fec39e56c962a0b27e2caf3b9474" 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.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", + "kvdb 0.1.0 (git+https://github.com/paritytech/parity-common)", "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)", ] [[package]] @@ -1535,6 +1521,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" @@ -1550,7 +1545,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)", ] @@ -1574,6 +1569,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" @@ -1648,24 +1652,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memorydb" -version = "0.1.1" +version = "0.2.1" +source = "git+https://github.com/paritytech/parity-common#0045887fecd2fec39e56c962a0b27e2caf3b9474" 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 (git+https://github.com/paritytech/parity-common)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.2", - "plain_hasher 0.1.0", - "rlp 0.2.1", + "plain_hasher 0.1.0 (git+https://github.com/paritytech/parity-common)", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", ] [[package]] name = "migration-rocksdb" version = "0.1.0" dependencies = [ - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "kvdb 0.1.0", - "kvdb-rocksdb 0.1.0", + "kvdb 0.1.0 (git+https://github.com/paritytech/parity-common)", + "kvdb-rocksdb 0.1.0 (git+https://github.com/paritytech/parity-common)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "macros 0.1.0", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1690,26 +1692,6 @@ dependencies = [ "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "miniz_oxide" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -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)", - "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)", -] - [[package]] name = "mio" version = "0.6.14" @@ -1730,14 +1712,13 @@ dependencies = [ [[package]] name = "mio-named-pipes" -version = "0.1.4" -source = "git+https://github.com/alexcrichton/mio-named-pipes#9c1bbb985b74374d3b7eda76937279f8e977ef81" +version = "0.1.5" +source = "git+https://github.com/alexcrichton/mio-named-pipes#6ad80e67fe7993423b281bc13d307785ade05d37" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1761,11 +1742,11 @@ dependencies = [ ] [[package]] -name = "msdos_time" -version = "0.1.6" +name = "miow" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1815,46 +1796,18 @@ dependencies = [ "ethcore-network 1.12.0", "ethcore-network-devp2p 1.12.0", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "kvdb-memorydb 0.1.0", + "kvdb-memorydb 0.1.0 (git+https://github.com/paritytech/parity-common)", "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)", ] -[[package]] -name = "node-health" -version = "0.1.0" -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)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "ntp 0.3.1 (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)", - "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)", -] - [[package]] name = "nodrop" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "ntp" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "num" version = "0.1.42" @@ -1873,7 +1826,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1967,19 +1920,43 @@ dependencies = [ ] [[package]] -name = "parity" +name = "parity-bytes" +version = "0.1.0" +source = "git+https://github.com/paritytech/parity-common#0045887fecd2fec39e56c962a0b27e2caf3b9474" + +[[package]] +name = "parity-clib" version = "1.12.0" +dependencies = [ + "parity-ethereum 2.1.0", +] + +[[package]] +name = "parity-crypto" +version = "0.1.0" +source = "git+https://github.com/paritytech/parity-common#0045887fecd2fec39e56c962a0b27e2caf3b9474" +dependencies = [ + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.12.1 (git+https://github.com/paritytech/ring)", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parity-ethereum" +version = "2.1.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "blooms-db 0.1.0", "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", - "ethcore-bytes 0.1.0", "ethcore-io 1.12.0", "ethcore-light 1.12.0", "ethcore-logger 1.12.0", @@ -1997,20 +1974,19 @@ 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", - "kvdb-rocksdb 0.1.0", + "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", + "kvdb 0.1.0 (git+https://github.com/paritytech/parity-common)", + "kvdb-rocksdb 0.1.0 (git+https://github.com/paritytech/parity-common)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mem 0.1.0", "migration-rocksdb 0.1.0", "node-filter 1.12.0", - "node-health 0.1.0", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "panic_hook 0.1.0", - "parity-dapps 1.12.0", + "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", "parity-hash-fetch 1.12.0", "parity-ipfs-api 1.12.0", "parity-local-store 0.1.0", @@ -2018,20 +1994,20 @@ dependencies = [ "parity-rpc 1.12.0", "parity-rpc-client 1.4.0", "parity-updater 1.12.0", - "parity-version 1.12.0", + "parity-version 2.1.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 (git+https://github.com/paritytech/parity-common)", "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", - "rlp 0.2.1", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", "rpassword 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "rpc-cli 1.4.0", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 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)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2041,78 +2017,6 @@ dependencies = [ "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "parity-clib" -version = "1.12.0" -dependencies = [ - "parity 1.12.0", -] - -[[package]] -name = "parity-dapps" -version = "1.12.0" -dependencies = [ - "base32 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-bytes 0.1.0", - "ethcore-devtools 1.12.0", - "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fetch 0.1.0", - "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)", - "itertools 0.5.10 (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-http-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", - "keccak-hash 0.1.2", - "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)", - "mime_guess 2.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)", - "node-health 0.1.0", - "parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-hash-fetch 1.12.0", - "parity-reactor 0.1.0", - "parity-ui 1.12.0", - "parity-ui-deprecation 1.10.0", - "parity-version 1.12.0", - "parking_lot 0.5.4 (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)", - "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)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "zip 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-dapps-glue" -version = "1.9.1" -dependencies = [ - "aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.2.11 (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)", - "quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi_macros 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-dapps-glue" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.2.11 (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)", - "quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "parity-hash-fetch" version = "1.12.0" @@ -2120,19 +2024,19 @@ dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (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)", "fake-fetch 0.0.1", "fetch 0.1.0", "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)", "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.2", + "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "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-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", "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)", @@ -2144,12 +2048,12 @@ version = "1.12.0" dependencies = [ "cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.12.0", - "ethcore-bytes 0.1.0", "ethereum-types 0.3.2 (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-http-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "multihash 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rlp 0.2.1", + "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", "unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2161,11 +2065,11 @@ dependencies = [ "ethcore-io 1.12.0", "ethcore-transaction 0.1.0", "ethkey 0.3.0", - "kvdb 0.1.0", - "kvdb-memorydb 0.1.0", + "kvdb 0.1.0 (git+https://github.com/paritytech/parity-common)", + "kvdb-memorydb 0.1.0 (git+https://github.com/paritytech/parity-common)", "log 0.3.9 (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)", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 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)", ] @@ -2193,8 +2097,6 @@ dependencies = [ "cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.12.0", "ethcore 1.12.0", - "ethcore-bytes 0.1.0", - "ethcore-crypto 0.1.0", "ethcore-devtools 1.12.0", "ethcore-io 1.12.0", "ethcore-light 1.12.0", @@ -2209,6 +2111,7 @@ dependencies = [ "ethkey 0.3.0", "ethstore 0.2.0", "fake-fetch 0.0.1", + "fake-hardware-wallet 0.0.1", "fetch 0.1.0", "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)", @@ -2220,31 +2123,32 @@ dependencies = [ "jsonrpc-macros 8.0.0 (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)", "jsonrpc-ws-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", - "keccak-hash 0.1.2", - "kvdb-memorydb 0.1.0", + "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", + "kvdb-memorydb 0.1.0 (git+https://github.com/paritytech/parity-common)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "macros 0.1.0", "multihash 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "node-health 0.1.0", "order-stat 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", + "parity-crypto 0.1.0 (git+https://github.com/paritytech/parity-common)", "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", + "parity-version 2.1.0", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "patricia-trie 0.2.1 (git+https://github.com/paritytech/parity-common)", "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", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", "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)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 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)", "stats 0.1.0", "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)", "tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "transaction-pool 1.12.0", + "transaction-pool 1.12.1", "transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "vm 0.1.0", ] @@ -2256,12 +2160,12 @@ dependencies = [ "futures 0.1.21 (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-ws-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", - "keccak-hash 0.1.2", + "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", "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)", - "serde 1.0.37 (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.70 (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)", ] @@ -2269,12 +2173,12 @@ dependencies = [ [[package]] name = "parity-tokio-ipc" version = "0.1.5" -source = "git+https://github.com/nikvolf/parity-tokio-ipc#d6c5b3cfcc913a1b9cf0f0562a10b083ceb9fb7c" +source = "git+https://github.com/nikvolf/parity-tokio-ipc#2af3e5b6b746552d8181069a2c6be068377df1de" 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)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)", + "mio-named-pipes 0.1.5 (git+https://github.com/alexcrichton/mio-named-pipes)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2283,56 +2187,6 @@ dependencies = [ "tokio-uds 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "parity-ui" -version = "1.12.0" -dependencies = [ - "parity-ui-dev 1.9.0 (git+https://github.com/parity-js/shell.git?rev=eecaadcb9e421bce31e91680d14a20bbd38f92a2)", - "parity-ui-old-dev 1.9.0 (git+https://github.com/parity-js/dapp-wallet.git?rev=65deb02e7c007a0fd8aab0c089c93e3fd1de6f87)", - "parity-ui-old-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-10-wallet.git?rev=4b6f112412716cd05123d32eeb7fda448288a6c6)", - "parity-ui-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-10-shell.git?rev=bd25b41cd642c6b822d820dded3aa601a29aa079)", - "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-ui-deprecation" -version = "1.10.0" -dependencies = [ - "parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-ui-dev" -version = "1.9.0" -source = "git+https://github.com/parity-js/shell.git?rev=eecaadcb9e421bce31e91680d14a20bbd38f92a2#eecaadcb9e421bce31e91680d14a20bbd38f92a2" -dependencies = [ - "parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-ui-old-dev" -version = "1.9.0" -source = "git+https://github.com/parity-js/dapp-wallet.git?rev=65deb02e7c007a0fd8aab0c089c93e3fd1de6f87#65deb02e7c007a0fd8aab0c089c93e3fd1de6f87" -dependencies = [ - "parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-ui-old-precompiled" -version = "1.9.0" -source = "git+https://github.com/js-dist-paritytech/parity-master-1-10-wallet.git?rev=4b6f112412716cd05123d32eeb7fda448288a6c6#4b6f112412716cd05123d32eeb7fda448288a6c6" -dependencies = [ - "parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-ui-precompiled" -version = "1.9.0" -source = "git+https://github.com/js-dist-paritytech/parity-master-1-10-shell.git?rev=bd25b41cd642c6b822d820dded3aa601a29aa079#bd25b41cd642c6b822d820dded3aa601a29aa079" -dependencies = [ - "parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "parity-updater" version = "1.12.0" @@ -2341,17 +2195,17 @@ dependencies = [ "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.12.0", - "ethcore-bytes 0.1.0", "ethcore-sync 1.12.0", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.2", + "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", "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)", "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", "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", + "parity-version 2.1.0", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "path 0.1.1 (git+https://github.com/paritytech/parity-common)", "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)", @@ -2360,10 +2214,10 @@ dependencies = [ [[package]] name = "parity-version" -version = "1.12.0" +version = "2.1.0" dependencies = [ - "ethcore-bytes 0.1.0", - "rlp 0.2.1", + "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2372,12 +2226,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)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2385,8 +2237,7 @@ name = "parity-whisper" version = "0.1.0" dependencies = [ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-crypto 0.1.0", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-network 1.12.0", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", @@ -2397,10 +2248,11 @@ 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)", + "parity-crypto 0.1.0 (git+https://github.com/paritytech/parity-common)", + "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)", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 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)", "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2420,10 +2272,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)", ] @@ -2444,24 +2296,33 @@ dependencies = [ [[package]] name = "path" -version = "0.1.0" +version = "0.1.1" +source = "git+https://github.com/paritytech/parity-common#0045887fecd2fec39e56c962a0b27e2caf3b9474" [[package]] name = "patricia-trie" -version = "0.1.0" +version = "0.2.1" +source = "git+https://github.com/paritytech/parity-common#0045887fecd2fec39e56c962a0b27e2caf3b9474" dependencies = [ "elastic-array 0.10.0 (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", - "keccak-hash 0.1.2", + "hashdb 0.2.0 (git+https://github.com/paritytech/parity-common)", + "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "memorydb 0.1.1", + "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", "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)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hashdb 0.2.0 (git+https://github.com/paritytech/parity-common)", + "keccak-hasher 0.1.0", + "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", + "patricia-trie 0.2.1 (git+https://github.com/paritytech/parity-common)", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", ] [[package]] @@ -2516,16 +2377,13 @@ dependencies = [ [[package]] name = "plain_hasher" version = "0.1.0" +source = "git+https://github.com/paritytech/parity-common#0045887fecd2fec39e56c962a0b27e2caf3b9474" 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 (git+https://github.com/paritytech/parity-common)", ] -[[package]] -name = "podio" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "pretty_assertions" version = "0.1.2" @@ -2544,7 +2402,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)", ] @@ -2620,7 +2478,7 @@ dependencies = [ "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "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 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 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)", "vm 0.1.0", @@ -2629,49 +2487,17 @@ dependencies = [ [[package]] name = "pwasm-utils" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "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)", -] - -[[package]] -name = "quasi" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "quasi_codegen" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "quasi_macros" -version = "0.32.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (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]] name = "quick-error" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2701,6 +2527,23 @@ dependencies = [ "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rayon" version = "1.0.1" @@ -2719,12 +2562,12 @@ 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)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" -version = "0.1.31" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2732,7 +2575,7 @@ name = "redox_termios" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2760,7 +2603,7 @@ dependencies = [ "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.2", + "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", ] [[package]] @@ -2774,9 +2617,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)", @@ -2787,8 +2630,9 @@ dependencies = [ [[package]] name = "rlp" version = "0.2.1" +source = "git+https://github.com/paritytech/parity-common#0045887fecd2fec39e56c962a0b27e2caf3b9474" dependencies = [ - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2800,7 +2644,7 @@ version = "0.1.0" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rlp 0.2.1", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", ] [[package]] @@ -2808,7 +2652,7 @@ name = "rlp_derive" version = "0.1.0" dependencies = [ "quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rlp 0.2.1", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2827,7 +2671,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)", @@ -2946,7 +2790,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.37" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2974,7 +2818,7 @@ name = "serde_ignored" version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2985,7 +2829,7 @@ dependencies = [ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2995,10 +2839,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "shell32-sys" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3052,7 +2896,7 @@ dependencies = [ [[package]] name = "snappy" version = "0.1.0" -source = "git+https://github.com/paritytech/rust-snappy#40ac9a0d9fd613e7f38df800a11a589b7296da73" +source = "git+https://github.com/paritytech/rust-snappy#798408ffef8f86dd51481673aca10f5348d7491b" dependencies = [ "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)", @@ -3061,12 +2905,23 @@ dependencies = [ [[package]] name = "snappy-sys" version = "0.1.0" -source = "git+https://github.com/paritytech/rust-snappy#40ac9a0d9fd613e7f38df800a11a589b7296da73" +source = "git+https://github.com/paritytech/rust-snappy#798408ffef8f86dd51481673aca10f5348d7491b" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "socket2" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "stable_deref_trait" version = "1.0.0" @@ -3098,48 +2953,6 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "syntex" -version = "0.58.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syntex_errors" -version = "0.58.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syntex_pos" -version = "0.58.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syntex_syntax" -version = "0.58.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "take" version = "0.1.0" @@ -3166,16 +2979,7 @@ dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "term" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3195,7 +2999,7 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3213,7 +3017,7 @@ version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3241,7 +3045,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3320,7 +3124,7 @@ source = "git+https://github.com/nikvolf/tokio-named-pipes#0b9b728eaeb0a6673c287 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)", - "mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)", + "mio-named-pipes 0.1.5 (git+https://github.com/alexcrichton/mio-named-pipes)", "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)", ] @@ -3463,7 +3267,7 @@ name = "toml" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3475,9 +3279,9 @@ dependencies = [ [[package]] name = "transaction-pool" -version = "1.12.0" +version = "1.12.1" dependencies = [ - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "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)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3503,22 +3307,32 @@ dependencies = [ [[package]] name = "trie-standardmap" version = "0.1.0" +source = "git+https://github.com/paritytech/parity-common#0045887fecd2fec39e56c962a0b27e2caf3b9474" dependencies = [ - "ethcore-bytes 0.1.0", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.2", - "rlp 0.2.1", + "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", + "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", ] [[package]] name = "triehash" -version = "0.1.0" +version = "0.2.0" +source = "git+https://github.com/paritytech/parity-common#0045887fecd2fec39e56c962a0b27e2caf3b9474" 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)", - "keccak-hash 0.1.2", - "rlp 0.2.1", - "trie-standardmap 0.1.0", + "hashdb 0.2.0 (git+https://github.com/paritytech/parity-common)", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", +] + +[[package]] +name = "triehash-ethereum" +version = "0.2.0" +dependencies = [ + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "keccak-hasher 0.1.0", + "triehash 0.2.0 (git+https://github.com/paritytech/parity-common)", ] [[package]] @@ -3526,7 +3340,7 @@ name = "uint" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3575,11 +3389,6 @@ name = "unicode-width" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "unicode-xid" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unicode-xid" version = "0.1.0" @@ -3625,17 +3434,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.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "kvdb 0.1.0", - "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" @@ -3659,15 +3457,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vm" version = "0.1.0" dependencies = [ - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "common-types 0.1.0", - "ethcore-bytes 0.1.0", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", - "keccak-hash 0.1.2", + "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "patricia-trie 0.1.0", - "rlp 0.2.1", + "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", + "patricia-trie 0.2.1 (git+https://github.com/paritytech/parity-common)", + "patricia-trie-ethereum 0.1.0", + "rlp 0.2.1 (git+https://github.com/paritytech/parity-common)", ] [[package]] @@ -3679,26 +3478,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "wasm" version = "0.1.0" dependencies = [ - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-logger 1.12.0", "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)", + "byteorder 1.2.3 (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]] @@ -3733,7 +3532,7 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "panic_hook 0.1.0", "parity-whisper 0.1.0", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3771,7 +3570,7 @@ name = "ws" version = "0.7.5" source = "git+https://github.com/tomusdrw/ws-rs#f12d19c4c19422fc79af28a3181f598bc07ecd1e" dependencies = [ - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3812,50 +3611,34 @@ dependencies = [ "xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "zip" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "podio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", -] - [metadata] -"checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45" "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" "checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455" "checksum app_dirs 1.2.1 (git+https://github.com/paritytech/app-dirs-rs)" = "" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" "checksum assert_matches 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "664470abf00fae0f31c0eb6e1ca12d82961b2a2541ef898bc9dd51a9254d218b" -"checksum aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfdf7355d9db158df68f976ed030ab0f6578af811f5a7bb6dcf221ec24e0e0" "checksum atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "af80143d6f7608d746df1520709e5d141c96f240b0e62b0aa41bdfb53374d9d4" "checksum backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbbf59b1c43eefa8c3ede390fcc36820b4999f7914104015be25025e0d62af2" "checksum backtrace-sys 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "c63ea141ef8fdb10409d0f5daf30ac51f84ef43bff66f16627773d2a292cd189" "checksum base-x 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f59103b47307f76e03bef1633aec7fa9e29bfb5aa6daf5a334f94233c71f6c1" -"checksum base32 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1b9605ba46d61df0410d8ac686b0007add8172eba90e8e909c347856fe794d8c" "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" "checksum base64 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "229d032f1a99302697f10b27167ae6d03d49d032e6a8e2550e8d3fc13356d2b4" "checksum bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e103c8b299b28a9c6990458b7013dc4a8356a9b854c51b9883241f5866fac36e" "checksum bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c" "checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" "checksum bn 0.4.4 (git+https://github.com/paritytech/bn)" = "" -"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 byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9" "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" "checksum clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8f4a2b3bb7ef3c672d7c13d15613211d5a6976b6892c598b0fcb5d40765f19c2" -"checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" -"checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "95470235c31c726d72bf2e1f421adc1e65b9d561bf5529612cbe1a72da1467b3" "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-deque 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c1bdc73742c36f7f35ebcda81dbb33a7e0d33757d03a06d9ddca762712ec5ea2" @@ -3864,9 +3647,9 @@ dependencies = [ "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" "checksum crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d636a8b3bcc1b409d7ffd3facef8f21dcb4009626adbd0c5e6c4305c07253c7b" "checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" +"checksum crunchy 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c240f247c278fa08a6d4820a6a222bfc6e0d999e51ba67be94f44c905b2161f2" "checksum ct-logs 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "61cd11fb222fecf889f4531855c614548e92e8bd2eb178e35296885df5ee9a7c" "checksum ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)" = "" -"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 docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d8acd393692c503b168471874953a2531df0e9ab77d0b6bbc582395743300a4a" @@ -3876,6 +3659,7 @@ dependencies = [ "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 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)" = "" "checksum ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05e33a914b94b763f0a92333e4e5c95c095563f06ef7d6b295b3d3c2cf31e21f" "checksum ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "210c9e21d164c15b6ef64fe601e0e12a3c84a031d5ef558e38463e53edbd22ed" @@ -3886,18 +3670,17 @@ dependencies = [ "checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa" "checksum fixed-hash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18d6fd718fb4396e7a9c93ac59ba7143501467ca7a143c145b5555a571d5576" "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.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" "checksum globset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "464627f948c3190ae3d04b1bc6d7dca2f785bda0ac01278e6db129ad383dbeb6" "checksum hamming 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65043da274378d68241eb9a8f8f8aa54e349136f7b8e12f63e3ef44043cc30e1" +"checksum hashdb 0.2.0 (git+https://github.com/paritytech/parity-common)" = "" "checksum heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461" "checksum heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea04fa3ead4e05e51a7c806fc07271fdbde4e246a6c6d1efd52e72230b771b82" "checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" @@ -3921,17 +3704,23 @@ dependencies = [ "checksum jsonrpc-server-utils 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)" = "" "checksum jsonrpc-tcp-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)" = "" "checksum jsonrpc-ws-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)" = "" +"checksum keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)" = "" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum kvdb 0.1.0 (git+https://github.com/paritytech/parity-common)" = "" +"checksum kvdb-memorydb 0.1.0 (git+https://github.com/paritytech/parity-common)" = "" +"checksum kvdb-rocksdb 0.1.0 (git+https://github.com/paritytech/parity-common)" = "" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "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" @@ -3940,21 +3729,19 @@ dependencies = [ "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" +"checksum memorydb 0.2.1 (git+https://github.com/paritytech/parity-common)" = "" "checksum mime 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e3d709ffbb330e1566dc2f2a3c9b58a5ad4a381f740b810cd305dc3f089bc160" "checksum mime_guess 2.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "27a5e6679a0614e25adc14c6434ba84e41632b765a6d9cb2031a0cca682699ae" -"checksum miniz_oxide 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aaa2d3ad070f428fffbd7d3ca2ea20bb0d8cffe9024405c44e1840bc1418b398" -"checksum miniz_oxide_c_api 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "92d98fdbd6145645828069b37ea92ca3de225e000d80702da25c20d3584b38a5" "checksum mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "6d771e3ef92d58a8da8df7d6976bfca9371ed1de6619d9d5a5ce5b1f29b85bfe" -"checksum mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)" = "" +"checksum mio-named-pipes 0.1.5 (git+https://github.com/alexcrichton/mio-named-pipes)" = "" "checksum mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1731a873077147b626d89cc6c2a0db6288d607496c5d10c0cfcf3adc697ec673" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aad9dfe950c057b1bfe9c1f2aa51583a8468ef2a5baba2ebbe06d775efeb7729" +"checksum miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9224c91f82b3c47cf53dcf78dfaa20d6888fbcc5d272d5f2fcdf8a697f3c987d" "checksum multibase 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b9c35dac080fd6e16a99924c8dfdef0af89d797dd851adab25feaffacf7850d6" "checksum multihash 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d49add5f49eb08bfc4d01ff286b84a48f53d45314f165c2d6efe477222d24f3" "checksum nan-preserving-float 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34d4f00fcc2f4c9efa8cc971db0da9e28290e28e97af47585e48691ef10ff31f" "checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" -"checksum ntp 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "143149743832c6543b60a8ef2a26cd9122dfecec2b767158e852a7beecf6d7a0" "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" "checksum num-bigint 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "81b483ea42927c463e191802e7334556b48e7875297564c0e9951bd3a0ae53e3" "checksum num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f8d26da319fb45674985c78f1d1caf99aa4941f785d384a2ae36d0740bc3e2fe" @@ -3968,23 +3755,22 @@ dependencies = [ "checksum ordered-float 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "58d25b6c0e47b20d05226d288ff434940296e7e2f8b877975da32f862152241f" "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-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "261c025c67ba416e9fe63aa9b3236520ce3c74cfbe43590c9cdcec4ccc8180e4" +"checksum parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)" = "" +"checksum parity-crypto 0.1.0 (git+https://github.com/paritytech/parity-common)" = "" "checksum parity-tokio-ipc 0.1.5 (git+https://github.com/nikvolf/parity-tokio-ipc)" = "" -"checksum parity-ui-dev 1.9.0 (git+https://github.com/parity-js/shell.git?rev=eecaadcb9e421bce31e91680d14a20bbd38f92a2)" = "" -"checksum parity-ui-old-dev 1.9.0 (git+https://github.com/parity-js/dapp-wallet.git?rev=65deb02e7c007a0fd8aab0c089c93e3fd1de6f87)" = "" -"checksum parity-ui-old-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-10-wallet.git?rev=4b6f112412716cd05123d32eeb7fda448288a6c6)" = "" -"checksum parity-ui-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-10-shell.git?rev=bd25b41cd642c6b822d820dded3aa601a29aa079)" = "" -"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 path 0.1.1 (git+https://github.com/paritytech/parity-common)" = "" +"checksum patricia-trie 0.2.1 (git+https://github.com/paritytech/parity-common)" = "" "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" "checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc" "checksum phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d62594c0bb54c464f633175d502038177e90309daf2e0158be42ed5f023ce88f" "checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03" "checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2" -"checksum podio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e5422a1ee1bc57cc47ae717b0137314258138f38fd5f3cea083f43a9725383a0" +"checksum plain_hasher 0.1.0 (git+https://github.com/paritytech/parity-common)" = "" "checksum pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2412f3332a07c7a2a50168988dcc184f32180a9758ad470390e5f55e089f6b6e" "checksum primal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0e31b86efadeaeb1235452171a66689682783149a6249ff334a2c5d8218d00a4" "checksum primal-bit 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "686a64e2f50194c64942992af5799e6b6e8775b8f88c607d72ed0a2fd58b9b21" @@ -3994,22 +3780,22 @@ 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 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" -"checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4" +"checksum pwasm-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "90d2b3c5bf24275fc77db6b14ec00a7a085d8ff9d1c4215fb6f6263e8d7b01bc" +"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0ff51282f28dc1b53fd154298feaa2e77c5ea0dba68e1fd8b03b72fbe13d2a" "checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" +"checksum rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "12397506224b2f93e6664ffc4f664b29be8208e5157d3d90b44f09b5fae470ea" +"checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2" "checksum rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80e811e76f1dbf68abf87a759083d34600017fc4e10b6bd5ad84a700f9dba4b1" "checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8" -"checksum redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "8dde11f18c108289bef24469638a04dce49da56084f2d50618b226e47eb04509" +"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-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" "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 rlp 0.2.1 (git+https://github.com/paritytech/parity-common)" = "" "checksum rocksdb 0.4.5 (git+https://github.com/paritytech/rust-rocksdb)" = "" "checksum rocksdb-sys 0.3.0 (git+https://github.com/paritytech/rust-rocksdb)" = "" "checksum rpassword 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b273c91bd242ca03ad6d71c143b6f17a48790e61f21a6c78568fa2b6774a24a4" @@ -4026,13 +3812,13 @@ dependencies = [ "checksum sct 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1137b767bbe1c4d30656993bdd97422ed41255d9400b105d735f8c7d9e800632" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "d3bcee660dcde8f52c3765dd9ca5ee36b4bf35470a738eb0bd5a8752b0389645" +"checksum serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "0c3adf19c07af6d186d91dae8927b83b0553d07ca56cbf7f2f32560455c91920" "checksum serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "f1711ab8b208541fa8de00425f6a577d90f27bb60724d2bb5fd911314af9668f" "checksum serde_derive_internals 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "89b340a48245bc03ddba31d0ff1709c118df90edc6adabaca4aac77aea181cce" "checksum serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "190e9765dcedb56be63b6e0993a006c7e3b071a016a304736e4a315dc01fb142" "checksum serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c9db7266c7d63a4c4b7fe8719656ccdd51acf1bed6124b174f933b009fb10bcb" "checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c" -"checksum shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72f20b8f3c060374edb8046591ba28f62448c369ccbdc7b02075103fb3a9e38d" +"checksum shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ee04b46101f57121c9da2b151988283b6beb79b34f5bb29a58ee48cb695122c" "checksum siphasher 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "833011ca526bd88f16778d32c699d325a9ad302fa06381cd66f7be63351d3f6d" "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537" "checksum skeptic 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24ebf8a06f5f8bae61ae5bbc7af7aac4ef6907ae975130faba1199e5fe82256a" @@ -4043,18 +3829,14 @@ dependencies = [ "checksum smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8fcd03faf178110ab0334d74ca9631d77f94c8c11cc77fcb59538abf0025695d" "checksum snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "" "checksum snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "" +"checksum socket2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "06dc9f86ee48652b7c80f3d254e3b9accb67a928c562c64d10d7b016d3d98dab" "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" "checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59" -"checksum syntex 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a8f5e3aaa79319573d19938ea38d068056b826db9883a5d47f86c1cecc688f0e" -"checksum syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "867cc5c2d7140ae7eaad2ae9e8bf39cb18a67ca651b7834f88d46ca98faadb9c" -"checksum syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13ad4762fe52abc9f4008e85c4fb1b1fe3aa91ccb99ff4826a439c7c598e1047" -"checksum syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6e0e4dbae163dd98989464c23dd503161b338790640e11537686f2ef0f25c791" "checksum take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b157868d8ac1f56b64604539990685fa7611d8fa9e5476cf0c02cf34d32917c5" "checksum target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c63f48baada5c52e65a29eef93ab4f8982681b67f9e8d29c7b05abcfec2b9ffe" "checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" "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 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" @@ -4083,6 +3865,8 @@ 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 trie-standardmap 0.1.0 (git+https://github.com/paritytech/parity-common)" = "" +"checksum triehash 0.2.0 (git+https://github.com/paritytech/parity-common)" = "" "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" @@ -4090,7 +3874,6 @@ dependencies = [ "checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" "checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946" "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" -"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" @@ -4101,7 +3884,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" @@ -4114,4 +3897,3 @@ dependencies = [ "checksum xdg 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a66b7c2281ebde13cf4391d70d4c7e5946c3c25e72a7b859ca8f677dcd0b0c61" "checksum xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2" "checksum xmltree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9cfb54ca6b8f17d2377219ce485b134d53561b77e1393c7ea416f543a527431" -"checksum zip 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "10931e278527cea65682696481e6d840371d581079df529ebfee186e0eaad719" diff --git a/Cargo.toml b/Cargo.toml index 24649eff454b70ceefeb264e40d3da4bc446d42e..697afeab3ae3cd03d79dff37152deb111c02def8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,13 @@ [package] description = "Parity Ethereum client" -name = "parity" +name = "parity-ethereum" # NOTE Make sure to update util/version/Cargo.toml as well -version = "1.12.0" +version = "2.1.0" license = "GPL-3.0" authors = ["Parity Technologies "] [dependencies] +blooms-db = { path = "util/blooms-db" } log = "0.3" env_logger = "0.4" rustc-hex = "1.0" @@ -19,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" @@ -31,8 +32,8 @@ 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-bytes = { path = "util/bytes" } +ethcore = { path = "ethcore", features = ["parity"] } +parity-bytes = { git = "https://github.com/paritytech/parity-common" } ethcore-io = { path = "util/io" } ethcore-light = { path = "ethcore/light" } ethcore-logger = { path = "logger" } @@ -45,8 +46,7 @@ ethcore-transaction = { path = "ethcore/transaction" } ethereum-types = "0.3" node-filter = { path = "ethcore/node_filter" } ethkey = { path = "ethkey" } -node-health = { path = "dapps/node-health" } -rlp = { path = "util/rlp" } +rlp = { git = "https://github.com/paritytech/parity-common" } rpc-cli = { path = "rpc_cli" } parity-hash-fetch = { path = "hash-fetch" } parity-ipfs-api = { path = "ipfs" } @@ -57,17 +57,16 @@ parity-rpc-client = { path = "rpc_client" } parity-updater = { path = "updater" } parity-version = { path = "util/version" } parity-whisper = { path = "whisper" } -path = { path = "util/path" } +path = { git = "https://github.com/paritytech/parity-common" } dir = { path = "util/dir" } panic_hook = { path = "util/panic_hook" } -keccak-hash = { path = "util/hash" } +keccak-hash = { git = "https://github.com/paritytech/parity-common" } migration-rocksdb = { path = "util/migration-rocksdb" } -kvdb = { path = "util/kvdb" } -kvdb-rocksdb = { path = "util/kvdb-rocksdb" } +kvdb = { git = "https://github.com/paritytech/parity-common" } +kvdb-rocksdb = { git = "https://github.com/paritytech/parity-common" } journaldb = { path = "util/journaldb" } mem = { path = "util/mem" } -parity-dapps = { path = "dapps", optional = true } ethcore-secretstore = { path = "secret_store", optional = true } registrar = { path = "registrar" } @@ -88,17 +87,7 @@ winapi = { version = "0.3.4", features = ["winsock2", "winuser", "shellapi"] } daemonize = { git = "https://github.com/paritytech/daemonize" } [features] -default = ["ui-precompiled"] -ui = [ - "ui-enabled", - "parity-dapps/ui", -] -ui-precompiled = [ - "ui-enabled", - "parity-dapps/ui-precompiled", -] -ui-enabled = ["dapps"] -dapps = ["parity-dapps"] +miner-debug = ["ethcore/miner-debug"] json-tests = ["ethcore/json-tests"] test-heavy = ["ethcore/test-heavy"] evm-debug = ["ethcore/evm-debug"] @@ -107,6 +96,17 @@ slow-blocks = ["ethcore/slow-blocks"] secretstore = ["ethcore-secretstore"] final = ["parity-version/final"] deadlock_detection = ["parking_lot/deadlock_detection"] +# to create a memory profile (requires nightly rust), use e.g. +# `heaptrack /path/to/parity `, +# to visualize a memory profile, use `heaptrack_gui` +# or +# `valgrind --tool=massif /path/to/parity ` +# and `massif-visualizer` for visualization +memory_profiling = [] +# hardcode version number 1.3.7 of parity to force an update +# in order to manually test that parity fall-over to the local version +# in case of invalid or deprecated command line arguments are entered +test-updater = ["parity-updater/test-updater"] [lib] path = "parity/lib.rs" @@ -116,17 +116,13 @@ path = "parity/main.rs" name = "parity" [profile.dev] -panic = "abort" [profile.release] debug = false -lto = false -panic = "abort" [workspace] members = [ "chainspec", - "dapps/js-glue", "ethcore/wasm/run", "ethcore/types", "ethkey/cli", @@ -137,6 +133,9 @@ members = [ "transaction-pool", "whisper", "whisper/cli", + "util/triehash-ethereum", + "util/keccak-hasher", + "util/patricia-trie-ethereum", ] [patch.crates-io] diff --git a/README.md b/README.md index 8cba4205bdb75b88f5f83bf380dbdf37cd86cfca..9355cde7d224941557f1255b2d1f0ee493a4b925 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Parity - fast, light, and robust Ethereum client +## Parity-Ethereum - a fast, light, and robust EVM and WASM blockchain client -## [» Download the latest release «](https://github.com/paritytech/parity/releases/latest) +### [» Download the latest release «](https://github.com/paritytech/parity-ethereum/releases/latest) [![build status](https://gitlab.parity.io/parity/parity/badges/master/build.svg)](https://gitlab.parity.io/parity/parity/commits/master) [![codecov](https://codecov.io/gh/paritytech/parity/branch/master/graph/badge.svg)](https://codecov.io/gh/paritytech/parity) @@ -23,52 +23,50 @@ Official website: https://parity.io | Be sure to check out [our wiki](https://wi ---- -## About Parity +## About Parity-Ethereum -Parity's goal is to be the fastest, lightest, and most secure Ethereum client. We are developing Parity using the sophisticated and cutting-edge Rust programming language. Parity is licensed under the GPLv3, and can be used for all your Ethereum needs. +Parity-Ethereum's goal is to be the fastest, lightest, and most secure Ethereum client. We are developing Parity-Ethereum using the sophisticated and cutting-edge Rust programming language. Parity-Ethereum is licensed under the GPLv3, and can be used for all your Ethereum needs. -From Parity Ethereum client version 1.10.0, the User Interface (UI) is accessible in a separate application called Parity UI. To keep using the UI in the browser (deprecated), [follow these steps](https://wiki.parity.io/FAQ-Basic-Operations,-Configuration,-and-Synchronization#the-parity-ui-application-isnt-working-the-way-i-want). +By default, Parity-Ethereum will run a JSON-RPC HTTP server on `127.0.0.1:8545` and a Web-Sockets server on `127.0.0.1:8546`. This is fully configurable and supports a number of APIs. -By default, Parity will also run a JSONRPC server on `127.0.0.1:8545` and a websockets server on `127.0.0.1:8546`. This is fully configurable and supports a number of APIs. +If you run into problems while using Parity-Ethereum, feel free to file an issue in this repository or hop on our [Gitter](https://gitter.im/paritytech/parity) or [Riot](https://riot.im/app/#/group/+parity:matrix.parity.io) chat room to ask a question. We are glad to help! **For security-critical issues**, please refer to the security policy outlined in [SECURITY.md](SECURITY.md). -If you run into an issue while using Parity, feel free to file one in this repository or hop on our [Gitter](https://gitter.im/paritytech/parity) or [Riot](https://riot.im/app/#/group/+parity:matrix.parity.io) chat room to ask a question. We are glad to help! **For security-critical issues**, please refer to the security policy outlined in [SECURITY.MD](SECURITY.md). - -Parity's current beta-release is 1.11. You can download it at https://github.com/paritytech/parity/releases or follow the instructions below to build from source. +Parity-Ethereum's current beta-release is 2.0. You can download it at [the releases page](https://github.com/paritytech/parity-ethereum/releases) or follow the instructions below to build from source. Please, mind the [CHANGELOG.md](CHANGELOG.md) for a list of all changes between different versions. ---- ## Build dependencies -**Parity requires Rust version 1.26.0 to build** +**Parity-Ethereum requires Rust version 1.27.0 to build** We recommend installing Rust through [rustup](https://www.rustup.rs/). If you don't already have rustup, you can install it like this: - Linux: - ```bash - $ curl https://sh.rustup.rs -sSf | sh - ``` + ```bash + $ curl https://sh.rustup.rs -sSf | sh + ``` - Parity also requires `gcc`, `g++`, `libssl-dev`/`openssl`, `libudev-dev` and `pkg-config` packages to be installed. + Parity-Ethereum also requires `gcc`, `g++`, `libudev-dev`, `pkg-config`, `file`, `make`, and `cmake` packages to be installed. - OSX: - ```bash - $ curl https://sh.rustup.rs -sSf | sh - ``` + ```bash + $ curl https://sh.rustup.rs -sSf | sh + ``` - `clang` is required. It comes with Xcode command line tools or can be installed with homebrew. + `clang` is required. It comes with Xcode command line tools or can be installed with homebrew. - Windows Make sure you have Visual Studio 2015 with C++ support installed. Next, download and run the rustup installer from - https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe, start "VS2015 x64 Native Tools Command Prompt", and use the following command to install and set up the msvc toolchain: + https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe, start "VS2015 x64 Native Tools Command Prompt", and use the following command to install and set up the msvc toolchain: ```bash - $ rustup default stable-x86_64-pc-windows-msvc + $ rustup default stable-x86_64-pc-windows-msvc ``` Once you have rustup installed, then you need to install: * [Perl](https://www.perl.org) * [Yasm](http://yasm.tortall.net) -Make sure that these binaries are in your `PATH`. After that you should be able to build parity from source. +Make sure that these binaries are in your `PATH`. After that you should be able to build Parity-Ethereum from source. ---- @@ -97,12 +95,12 @@ sudo snap install parity --edge ## Build from source ```bash -# download Parity code -$ git clone https://github.com/paritytech/parity -$ cd parity +# download Parity-Ethereum code +$ git clone https://github.com/paritytech/parity-ethereum +$ cd parity-ethereum # build in release mode -$ cargo build --release +$ cargo build --release --features final ``` This will produce an executable in the `./target/release` subdirectory. @@ -147,22 +145,22 @@ The one-line installer always defaults to the latest beta release. To install a bash <(curl https://get.parity.io -L) -r stable ``` -## Start Parity +## Start Parity-Ethereum ### Manually -To start Parity manually, just run +To start Parity-Ethereum manually, just run ```bash $ ./target/release/parity ``` -and Parity will begin syncing the Ethereum blockchain. +and Parity-Ethereum will begin syncing the Ethereum blockchain. ### Using systemd service file -To start Parity as a regular user using systemd init: +To start Parity-Ethereum as a regular user using systemd init: 1. Copy `./scripts/parity.service` to your systemd user directory (usually `~/.config/systemd/user`). -2. To configure Parity, write a `/etc/parity/config.toml` config file, see [Configuring Parity](https://paritytech.github.io/wiki/Configuring-Parity) for details. +2. To configure Parity-Ethereum, write a `/etc/parity/config.toml` config file, see [Configuring Parity-Ethereum](https://paritytech.github.io/wiki/Configuring-Parity) for details. diff --git a/chainspec/src/main.rs b/chainspec/src/main.rs index bcef53f3f09835d2e8483ea983f8c7fc055079af..708d74b503da4ed93b0113f9aa2b9f3a4d05b310 100644 --- a/chainspec/src/main.rs +++ b/chainspec/src/main.rs @@ -1,3 +1,19 @@ +// 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 . + extern crate serde_json; extern crate serde_ignored; extern crate ethjson; diff --git a/dapps/Cargo.toml b/dapps/Cargo.toml deleted file mode 100644 index a7ce5a54893be17979d3e86165e6072a8bfd1c41..0000000000000000000000000000000000000000 --- a/dapps/Cargo.toml +++ /dev/null @@ -1,49 +0,0 @@ -[package] -description = "Parity Dapps crate" -name = "parity-dapps" -version = "1.12.0" -license = "GPL-3.0" -authors = ["Parity Technologies "] - -[lib] - -[dependencies] -base32 = "0.3" -futures = "0.1" -futures-cpupool = "0.1" -linked-hash-map = "0.5" -log = "0.3" -parity-dapps-glue = "1.9" -parking_lot = "0.5" -mime_guess = "2.0.0-alpha.2" -rand = "0.4" -rustc-hex = "1.0" -serde = "1.0" -serde_derive = "1.0" -serde_json = "1.0" -unicase = "1.4" -zip = { version = "0.3", default-features = false, features = ["deflate"] } -itertools = "0.5" - -jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } -jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } - -ethcore-bytes = { path = "../util/bytes" } -ethereum-types = "0.3" -fetch = { path = "../util/fetch" } -node-health = { path = "./node-health" } -parity-hash-fetch = { path = "../hash-fetch" } -parity-reactor = { path = "../util/reactor" } -parity-ui = { path = "./ui" } -parity-ui-deprecation = { path = "./ui-deprecation" } -keccak-hash = { path = "../util/hash" } -parity-version = { path = "../util/version" } -registrar = { path = "../registrar" } - -[dev-dependencies] -env_logger = "0.4" -ethcore-devtools = { path = "../devtools" } - -[features] -ui = ["parity-ui/no-precompiled-js"] -ui-precompiled = ["parity-ui/use-precompiled-js"] diff --git a/dapps/js-glue/Cargo.toml b/dapps/js-glue/Cargo.toml deleted file mode 100644 index efe92bbda6ae02357ce7bee0b1bfc2d6e8557b43..0000000000000000000000000000000000000000 --- a/dapps/js-glue/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -description = "Base Package for all Parity built-in dapps" -name = "parity-dapps-glue" -version = "1.9.1" -license = "GPL-3.0" -authors = ["Parity Technologies "] -build = "build.rs" - -[build-dependencies] -quasi_codegen = { version = "0.32", optional = true } -syntex = { version = "0.58", optional = true } - -[dependencies] -glob = { version = "0.2.11" } -mime_guess = { version = "2.0.0-alpha.2" } -aster = { version = "0.41", default-features = false } -quasi = { version = "0.32", default-features = false } -quasi_macros = { version = "0.32", optional = true } -syntex = { version = "0.58", optional = true } -syntex_syntax = { version = "0.58", optional = true } - -[features] -default = ["with-syntex"] -nightly = ["quasi_macros"] -with-syntex = ["quasi/with-syntex", "quasi_codegen", "quasi_codegen/with-syntex", "syntex", "syntex_syntax"] -use-precompiled-js = [] - - diff --git a/dapps/js-glue/README.md b/dapps/js-glue/README.md deleted file mode 100644 index 3363da9b222e6d36156bc7a68eb8803e00bbceb1..0000000000000000000000000000000000000000 --- a/dapps/js-glue/README.md +++ /dev/null @@ -1,65 +0,0 @@ -# Parity Dapps (JS-glue) - -Code generator to simplify creating a built-in Parity Dapp - -# How to create new builtin Dapp. -1. Clone this repository. - - ```bash - $ git clone https://github.com/paritytech/parity.git - ``` - -1. Create a new directory for your Dapp. (`./myapp`) - - ```bash - $ mkdir -p ./parity/dapps/myapp/src/web - ``` - -1. Copy your frontend files to `./dapps/myapp/src/web` (bundled ones) - - ```bash - $ cp -r ./myapp-src/* ./parity/dapps/myapp/src/web - ``` - -1. Instead of creating `web3` in your app. Load (as the first script tag in `head`): - - ```html - - ``` - - The `inject.js` script will create global `web3` instance with proper provider that should be used by your dapp. - -1. Create `./parity/dapps/myapp/Cargo.toml` with you apps details. See example here: [parity-status Cargo.toml](https://github.com/paritytech/parity-ui/blob/master/status/Cargo.toml). - - ```bash - $ git clone https://github.com/paritytech/parity-ui.git - $ cd ./parity-ui/ - $ cp ./home/Cargo.toml ../parity/dapps/myapp/Cargo.toml - $ cp ./home/build.rs ../parity/dapps/myapp/build.rs - $ cp ./home/src/lib.rs ../parity/dapps/myapp/src/lib.rs - $ cp ./home/src/lib.rs.in ../parity/dapps/myapp/src/lib.rs.in - # And edit the details of your app - $ vim ../parity/dapps/myapp/Cargo.toml # Edit the details - $ vim ./parity/dapps/myapp/src/lib.rs.in # Edit the details - ``` -# How to include your Dapp into `Parity`? -1. Edit `dapps/Cargo.toml` and add dependency to your application (it can be optional) - - ```toml - # Use git repo and version - parity-dapps-myapp = { path="./myapp" } - ``` - -1. Edit `dapps/src/apps.rs` and add your application to `all_pages` (if it's optional you need to specify two functions - see `parity-dapps-wallet` example) - -1. Compile parity. - - ```bash - $ cargo build --release # While inside `parity` - ``` - -1. Commit the results. - - ```bash - $ git add myapp && git commit -am "My first Parity Dapp". - ``` diff --git a/dapps/js-glue/build.rs b/dapps/js-glue/build.rs deleted file mode 100644 index 442abf7dfba6404c05fbf2923dbe67346457b1b1..0000000000000000000000000000000000000000 --- a/dapps/js-glue/build.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2015-2017 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 . - - -#[cfg(feature = "with-syntex")] -mod inner { - extern crate syntex; - extern crate quasi_codegen; - - use std::env; - use std::path::Path; - - pub fn main() { - let out_dir = env::var_os("OUT_DIR").unwrap(); - - let src = Path::new("src/lib.rs.in"); - let dst = Path::new(&out_dir).join("lib.rs"); - - quasi_codegen::expand(&src, &dst).unwrap(); - } -} - -#[cfg(not(feature = "with-syntex"))] -mod inner { - pub fn main() {} -} - -fn main() { - inner::main(); -} diff --git a/dapps/js-glue/src/build.rs b/dapps/js-glue/src/build.rs deleted file mode 100644 index 31f27306a9defa591550af7d097ab4278dafe69a..0000000000000000000000000000000000000000 --- a/dapps/js-glue/src/build.rs +++ /dev/null @@ -1,65 +0,0 @@ - -#[cfg(feature = "with-syntex")] -pub mod inner { - use syntex; - use codegen; - use syntax::{ast, fold}; - use std::env; - use std::path::Path; - - fn strip_attributes(krate: ast::Crate) -> ast::Crate { - /// Helper folder that strips the serde attributes after the extensions have been expanded. - struct StripAttributeFolder; - - impl fold::Folder for StripAttributeFolder { - fn fold_attribute(&mut self, attr: ast::Attribute) -> Option { - if &*attr.value.name.as_str() == "webapp" { - return None; - } - - Some(attr) - } - - fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { - fold::noop_fold_mac(mac, self) - } - } - - fold::Folder::fold_crate(&mut StripAttributeFolder, krate) - } - - pub fn register(reg: &mut syntex::Registry) { - reg.add_attr("feature(custom_derive)"); - reg.add_attr("feature(custom_attribute)"); - - reg.add_decorator("derive_WebAppFiles", codegen::expand_webapp_implementation); - reg.add_post_expansion_pass(strip_attributes); - } - - pub fn generate() { - let out_dir = env::var_os("OUT_DIR").unwrap(); - let mut registry = syntex::Registry::new(); - register(&mut registry); - - let src = Path::new("src/lib.rs.in"); - let dst = Path::new(&out_dir).join("lib.rs"); - - registry.expand("", &src, &dst).unwrap(); - } -} - -#[cfg(not(feature = "with-syntex"))] -pub mod inner { - use codegen; - - pub fn register(reg: &mut rustc_plugin::Registry) { - reg.register_syntax_extension( - syntax::parse::token::intern("derive_WebAppFiles"), - syntax::ext::base::MultiDecorator( - Box::new(codegen::expand_webapp_implementation))); - - reg.register_attribute("webapp".to_owned(), AttributeType::Normal); - } - - pub fn generate() {} -} diff --git a/dapps/js-glue/src/codegen.rs b/dapps/js-glue/src/codegen.rs deleted file mode 100644 index c6e948820fce03ed2baabc734ddbe0bf94a7b7bf..0000000000000000000000000000000000000000 --- a/dapps/js-glue/src/codegen.rs +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2015-2017 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 . - -extern crate aster; -extern crate glob; -extern crate mime_guess; - -use self::mime_guess::guess_mime_type; -use std::path::{self, Path, PathBuf}; -use std::ops::Deref; - -use syntax::attr; -use syntax::ast::{self, MetaItem, Item}; -use syntax::codemap::Span; -use syntax::ext::base::{Annotatable, ExtCtxt}; -use syntax::print::pprust::lit_to_string; -use syntax::symbol::InternedString; - -pub fn expand_webapp_implementation( - cx: &mut ExtCtxt, - span: Span, - meta_item: &MetaItem, - annotatable: &Annotatable, - push: &mut FnMut(Annotatable) -) { - let item = match *annotatable { - Annotatable::Item(ref item) => item, - _ => { - cx.span_err(meta_item.span, "`#[derive(WebAppFiles)]` may only be applied to struct implementations"); - return; - }, - }; - let builder = aster::AstBuilder::new().span(span); - implement_webapp(cx, &builder, item, push); -} - -fn implement_webapp(cx: &ExtCtxt, builder: &aster::AstBuilder, item: &Item, push: &mut FnMut(Annotatable)) { - let static_files_dir = extract_path(cx, item); - - let src = Path::new("src"); - let static_files = { - let mut buf = src.to_path_buf(); - buf.push(static_files_dir.deref()); - buf - }; - - let search_location = { - let mut buf = static_files.to_path_buf(); - buf.push("**"); - buf.push("*"); - buf - }; - - let files = glob::glob(search_location.to_str().expect("Valid UTF8 path")) - .expect("The sources directory is missing.") - .collect::, glob::GlobError>>() - .expect("There should be no error when reading a list of files."); - - let statements = files - .iter() - .filter(|path_buf| path_buf.is_file()) - .map(|path_buf| { - let path = path_buf.as_path(); - let filename = path.file_name().and_then(|s| s.to_str()).expect("Only UTF8 paths."); - let mime_type = guess_mime_type(filename).to_string(); - let file_path = as_uri(path.strip_prefix(&static_files).ok().expect("Prefix is always there, cause it's absolute path;qed")); - let file_path_in_source = path.to_str().expect("Only UTF8 paths."); - - let path_lit = builder.expr().str(file_path.as_str()); - let mime_lit = builder.expr().str(mime_type.as_str()); - let web_path_lit = builder.expr().str(file_path_in_source); - let separator_lit = builder.expr().str(path::MAIN_SEPARATOR.to_string().as_str()); - let concat_id = builder.id("concat!"); - let env_id = builder.id("env!"); - let macro_id = builder.id("include_bytes!"); - - let content = quote_expr!( - cx, - $macro_id($concat_id($env_id("CARGO_MANIFEST_DIR"), $separator_lit, $web_path_lit)) - ); - quote_stmt!( - cx, - files.insert($path_lit, File { path: $path_lit, content_type: $mime_lit, content: $content }); - ).expect("The statement is always ok, because it just uses literals.") - }).collect::>(); - - let type_name = item.ident; - - let files_impl = quote_item!(cx, - impl $type_name { - #[allow(unused_mut)] - fn files() -> ::std::collections::HashMap<&'static str, File> { - let mut files = ::std::collections::HashMap::new(); - $statements - files - } - } - ).unwrap(); - - push(Annotatable::Item(files_impl)); -} - -fn extract_path(cx: &ExtCtxt, item: &Item) -> String { - for meta_items in item.attrs.iter().filter_map(webapp_meta_items) { - for meta_item in meta_items { - let is_path = &*meta_item.name.as_str() == "path"; - match meta_item.node { - ast::MetaItemKind::NameValue(ref lit) if is_path => { - if let Some(s) = get_str_from_lit(cx, lit) { - return s.deref().to_owned(); - } - }, - _ => {}, - } - } - } - - // default - "web".to_owned() -} - -fn webapp_meta_items(attr: &ast::Attribute) -> Option> { - let is_webapp = &*attr.value.name.as_str() == "webapp"; - match attr.value.node { - ast::MetaItemKind::List(ref items) if is_webapp => { - attr::mark_used(&attr); - Some( - items.iter() - .map(|item| item.node.clone()) - .filter_map(|item| match item { - ast::NestedMetaItemKind::MetaItem(item) => Some(item), - _ => None, - }) - .collect() - ) - } - _ => None - } -} - -fn get_str_from_lit(cx: &ExtCtxt, lit: &ast::Lit) -> Option { - match lit.node { - ast::LitKind::Str(ref s, _) => Some(s.clone().as_str()), - _ => { - cx.span_err( - lit.span, - &format!("webapp annotation path must be a string, not `{}`", - lit_to_string(lit) - ) - ); - return None; - } - } -} - -fn as_uri(path: &Path) -> String { - let mut s = String::new(); - for component in path.iter() { - s.push_str(component.to_str().expect("Only UTF-8 filenames are supported.")); - s.push('/'); - } - s[0..s.len()-1].into() -} - -#[test] -fn should_convert_path_separators_on_all_platforms() { - // given - let p = { - let mut p = PathBuf::new(); - p.push("web"); - p.push("src"); - p.push("index.html"); - p - }; - - // when - let path = as_uri(&p); - - // then - assert_eq!(path, "web/src/index.html".to_owned()); -} diff --git a/dapps/js-glue/src/js.rs b/dapps/js-glue/src/js.rs deleted file mode 100644 index d1d1cdda9139dc3a8307a42904ecd8185fd3b6b0..0000000000000000000000000000000000000000 --- a/dapps/js-glue/src/js.rs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2015-2017 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 . - -#![cfg_attr(feature="use-precompiled-js", allow(dead_code))] -#![cfg_attr(feature="use-precompiled-js", allow(unused_imports))] - -use std::fmt; -use std::process::Command; - -#[cfg(not(windows))] -mod platform { - use std::process::Command; - - pub static NPM_CMD: &'static str = "npm"; - pub fn handle_cmd(cmd: &mut Command) -> &mut Command { - cmd - } -} - -#[cfg(windows)] -mod platform { - use std::process::{Command, Stdio}; - - pub static NPM_CMD: &'static str = "cmd.exe"; - // NOTE [ToDr] For some reason on windows - // The command doesn't have %~dp0 set properly - // and it cannot load globally installed node.exe - pub fn handle_cmd(cmd: &mut Command) -> &mut Command { - cmd.stdin(Stdio::null()) - .arg("/c") - .arg("npm.cmd") - } -} - -fn die(s: &'static str, e: T) -> ! { - panic!("Error: {}: {:?}", s, e); -} - -#[cfg(feature = "use-precompiled-js")] -pub fn test(_path: &str) { -} -#[cfg(feature = "use-precompiled-js")] -pub fn build(_path: &str, _dest: &str) { -} - -#[cfg(not(feature = "use-precompiled-js"))] -pub fn build(path: &str, dest: &str) { - let child = platform::handle_cmd(&mut Command::new(platform::NPM_CMD)) - .arg("install") - .arg("--no-progress") - .current_dir(path) - .status() - .unwrap_or_else(|e| die("Installing node.js dependencies with npm", e)); - assert!(child.success(), "There was an error installing dependencies."); - - let child = platform::handle_cmd(&mut Command::new(platform::NPM_CMD)) - .arg("run") - .arg("build") - .env("NODE_ENV", "production") - .env("BUILD_DEST", dest) - .current_dir(path) - .status() - .unwrap_or_else(|e| die("Building JS code", e)); - assert!(child.success(), "There was an error build JS code."); -} - -#[cfg(not(feature = "use-precompiled-js"))] -pub fn test(path: &str) { - let child = Command::new(platform::NPM_CMD) - .arg("run") - .arg("test") - .current_dir(path) - .status() - .unwrap_or_else(|e| die("Running test command", e)); - assert!(child.success(), "There was an error while running JS tests."); -} diff --git a/dapps/js-glue/src/lib.rs b/dapps/js-glue/src/lib.rs deleted file mode 100644 index 143dd1fc8bf7b650befa986b17c6041bbeb6ffa0..0000000000000000000000000000000000000000 --- a/dapps/js-glue/src/lib.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2015-2017 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 . - - -#![cfg_attr(not(feature = "with-syntex"), feature(rustc_private, plugin))] -#![cfg_attr(not(feature = "with-syntex"), plugin(quasi_macros))] - -#[cfg(feature = "with-syntex")] -extern crate syntex; - -#[cfg(feature = "with-syntex")] -extern crate syntex_syntax as syntax; - -#[cfg(feature = "with-syntex")] -include!(concat!(env!("OUT_DIR"), "/lib.rs")); - -#[cfg(not(feature = "with-syntex"))] -#[macro_use] -extern crate syntax; - -#[cfg(not(feature = "with-syntex"))] -extern crate rustc_plugin; - -#[cfg(not(feature = "with-syntex"))] -include!("lib.rs.in"); diff --git a/dapps/js-glue/src/lib.rs.in b/dapps/js-glue/src/lib.rs.in deleted file mode 100644 index 99a253013d1388d048a8401f675b1bc6f5aeea00..0000000000000000000000000000000000000000 --- a/dapps/js-glue/src/lib.rs.in +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2015-2017 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 . - -extern crate quasi; - -mod codegen; -mod build; -pub mod js; -pub use build::inner::generate; - -use std::default::Default; - -#[derive(Clone)] -pub struct File { - pub path: &'static str, - pub content: &'static [u8], - // TODO: use strongly-typed MIME. - pub content_type: &'static str, -} - -#[derive(Clone, Debug)] -pub struct Info { - pub name: &'static str, - pub version: &'static str, - pub author: &'static str, - pub description: &'static str, - pub icon_url: &'static str, -} - -pub trait WebApp : Default + Send + Sync { - fn file(&self, path: &str) -> Option<&File>; - fn info(&self) -> Info; -} diff --git a/dapps/node-health/Cargo.toml b/dapps/node-health/Cargo.toml deleted file mode 100644 index 5688c8f76a106d9e19cc6159395d940e98289331..0000000000000000000000000000000000000000 --- a/dapps/node-health/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "node-health" -description = "Node's health status" -version = "0.1.0" -license = "GPL-3.0" -authors = ["Parity Technologies "] - -[dependencies] -futures = "0.1" -futures-cpupool = "0.1" -log = "0.3" -ntp = "0.3.0" -parking_lot = "0.5" -serde = "1.0" -serde_derive = "1.0" -time = "0.1.35" - -parity-reactor = { path = "../../util/reactor" } diff --git a/dapps/node-health/src/health.rs b/dapps/node-health/src/health.rs deleted file mode 100644 index ab300a4a771f1b5a5d1086a2e22e75926bd9b580..0000000000000000000000000000000000000000 --- a/dapps/node-health/src/health.rs +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Reporting node's health. - -use std::sync::Arc; -use std::time::Duration; -use futures::Future; -use futures::sync::oneshot; -use types::{HealthInfo, HealthStatus, Health}; -use time::{TimeChecker, MAX_DRIFT}; -use parity_reactor::Remote; -use parking_lot::Mutex; -use {SyncStatus}; - -const TIMEOUT: Duration = Duration::from_secs(5); -const PROOF: &str = "Only one closure is invoked."; - -/// A struct enabling you to query for node's health. -#[derive(Debug, Clone)] -pub struct NodeHealth { - sync_status: Arc, - time: TimeChecker, - remote: Remote, -} - -impl NodeHealth { - /// Creates new `NodeHealth`. - pub fn new(sync_status: Arc, time: TimeChecker, remote: Remote) -> Self { - NodeHealth { sync_status, time, remote, } - } - - /// Query latest health report. - pub fn health(&self) -> Box + Send> { - trace!(target: "dapps", "Checking node health."); - // Check timediff - let sync_status = self.sync_status.clone(); - let time = self.time.time_drift(); - let (tx, rx) = oneshot::channel(); - let tx = Arc::new(Mutex::new(Some(tx))); - let tx2 = tx.clone(); - self.remote.spawn_with_timeout( - move |_| time.then(move |result| { - let _ = tx.lock().take().expect(PROOF).send(Ok(result)); - Ok(()) - }), - TIMEOUT, - move || { - let _ = tx2.lock().take().expect(PROOF).send(Err(())); - }, - ); - - Box::new(rx.map_err(|err| { - warn!(target: "dapps", "Health request cancelled: {:?}", err); - }).and_then(move |time| { - // Check peers - let peers = { - let (connected, max) = sync_status.peers(); - let (status, message) = match connected { - 0 => { - (HealthStatus::Bad, "You are not connected to any peers. There is most likely some network issue. Fix connectivity.".into()) - }, - 1 => (HealthStatus::NeedsAttention, "You are connected to only one peer. Your node might not be reliable. Check your network connection.".into()), - _ => (HealthStatus::Ok, "".into()), - }; - HealthInfo { status, message, details: (connected, max) } - }; - - // Check sync - let sync = { - let is_syncing = sync_status.is_major_importing(); - let (status, message) = if is_syncing { - (HealthStatus::NeedsAttention, "Your node is still syncing, the values you see might be outdated. Wait until it's fully synced.".into()) - } else { - (HealthStatus::Ok, "".into()) - }; - HealthInfo { status, message, details: is_syncing } - }; - - // Check time - let time = { - let (status, message, details) = match time { - Ok(Ok(diff)) if diff < MAX_DRIFT && diff > -MAX_DRIFT => { - (HealthStatus::Ok, "".into(), diff) - }, - Ok(Ok(diff)) => { - (HealthStatus::Bad, format!( - "Your clock is not in sync. Detected difference is too big for the protocol to work: {}ms. Synchronize your clock.", - diff, - ), diff) - }, - Ok(Err(err)) => { - (HealthStatus::NeedsAttention, format!( - "Unable to reach time API: {}. Make sure that your clock is synchronized.", - err, - ), 0) - }, - Err(_) => { - (HealthStatus::NeedsAttention, "Time API request timed out. Make sure that the clock is synchronized.".into(), 0) - }, - }; - - HealthInfo { status, message, details, } - }; - - Ok(Health { peers, sync, time}) - })) - } -} diff --git a/dapps/node-health/src/lib.rs b/dapps/node-health/src/lib.rs deleted file mode 100644 index b0eb133ee38c933f2ef9c992937e9851cb01b243..0000000000000000000000000000000000000000 --- a/dapps/node-health/src/lib.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Node Health status reporting. - -#![warn(missing_docs)] - -extern crate futures; -extern crate futures_cpupool; -extern crate ntp; -extern crate time as time_crate; -extern crate parity_reactor; -extern crate parking_lot; - -#[macro_use] -extern crate log; -#[macro_use] -extern crate serde_derive; - -mod health; -mod time; -mod types; - -pub use futures_cpupool::CpuPool; -pub use health::NodeHealth; -pub use types::{Health, HealthInfo, HealthStatus}; -pub use time::{TimeChecker, Error}; - -/// Indicates sync status -pub trait SyncStatus: ::std::fmt::Debug + Send + Sync { - /// Returns true if there is a major sync happening. - fn is_major_importing(&self) -> bool; - - /// Returns number of connected and ideal peers. - fn peers(&self) -> (usize, usize); -} diff --git a/dapps/node-health/src/time.rs b/dapps/node-health/src/time.rs deleted file mode 100644 index c3da050a47fddc63d4403ed1a03c4e1957933d62..0000000000000000000000000000000000000000 --- a/dapps/node-health/src/time.rs +++ /dev/null @@ -1,357 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Periodically checks node's time drift using [SNTP](https://tools.ietf.org/html/rfc1769). -//! -//! An NTP packet is sent to the server with a local timestamp, the server then completes the packet, yielding the -//! following timestamps: -//! -//! Timestamp Name ID When Generated -//! ------------------------------------------------------------ -//! Originate Timestamp T1 time request sent by client -//! Receive Timestamp T2 time request received at server -//! Transmit Timestamp T3 time reply sent by server -//! Destination Timestamp T4 time reply received at client -//! -//! The drift is defined as: -//! -//! drift = ((T2 - T1) + (T3 - T4)) / 2. -//! - -use std::io; -use std::{fmt, mem, time}; -use std::collections::VecDeque; -use std::sync::atomic::{self, AtomicUsize}; -use std::sync::Arc; - -use futures::{self, Future}; -use futures::future::{self, IntoFuture}; -use futures_cpupool::{CpuPool, CpuFuture}; -use ntp; -use parking_lot::RwLock; -use time_crate::{Duration, Timespec}; - -/// Time checker error. -#[derive(Debug, Clone, PartialEq)] -pub enum Error { - /// No servers are currently available for a query. - NoServersAvailable, - /// There was an error when trying to reach the NTP server. - Ntp(String), - /// IO error when reading NTP response. - Io(String), -} - -impl fmt::Display for Error { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - use self::Error::*; - - match *self { - NoServersAvailable => write!(fmt, "No NTP servers available"), - Ntp(ref err) => write!(fmt, "NTP error: {}", err), - Io(ref err) => write!(fmt, "Connection Error: {}", err), - } - } -} - -impl From for Error { - fn from(err: io::Error) -> Self { Error::Io(format!("{}", err)) } -} - -impl From for Error { - fn from(err: ntp::errors::Error) -> Self { Error::Ntp(format!("{}", err)) } -} - -/// NTP time drift checker. -pub trait Ntp { - /// Returned Future. - type Future: IntoFuture; - - /// Returns the current time drift. - fn drift(&self) -> Self::Future; -} - -const SERVER_MAX_POLL_INTERVAL_SECS: u64 = 60; -#[derive(Debug)] -struct Server { - pub address: String, - next_call: RwLock, - failures: AtomicUsize, -} - -impl Server { - pub fn is_available(&self) -> bool { - *self.next_call.read() < time::Instant::now() - } - - pub fn report_success(&self) { - self.failures.store(0, atomic::Ordering::SeqCst); - self.update_next_call(1) - } - - pub fn report_failure(&self) { - let errors = self.failures.fetch_add(1, atomic::Ordering::SeqCst); - self.update_next_call(1 << errors) - } - - fn update_next_call(&self, delay: usize) { - *self.next_call.write() = time::Instant::now() + time::Duration::from_secs(delay as u64 * SERVER_MAX_POLL_INTERVAL_SECS); - } -} - -impl> From for Server { - fn from(t: T) -> Self { - Server { - address: t.as_ref().to_owned(), - next_call: RwLock::new(time::Instant::now()), - failures: Default::default(), - } - } -} - -/// NTP client using the SNTP algorithm for calculating drift. -#[derive(Clone)] -pub struct SimpleNtp { - addresses: Vec>, - pool: CpuPool, -} - -impl fmt::Debug for SimpleNtp { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f - .debug_struct("SimpleNtp") - .field("addresses", &self.addresses) - .finish() - } -} - -impl SimpleNtp { - fn new>(addresses: &[T], pool: CpuPool) -> SimpleNtp { - SimpleNtp { - addresses: addresses.iter().map(Server::from).map(Arc::new).collect(), - pool: pool, - } - } -} - -impl Ntp for SimpleNtp { - type Future = future::Either< - CpuFuture, - future::FutureResult, - >; - - fn drift(&self) -> Self::Future { - use self::future::Either::{A, B}; - - let server = self.addresses.iter().find(|server| server.is_available()); - server.map(|server| { - let server = server.clone(); - A(self.pool.spawn_fn(move || { - debug!(target: "dapps", "Fetching time from {}.", server.address); - - match ntp::request(&server.address) { - Ok(packet) => { - let dest_time = ::time_crate::now_utc().to_timespec(); - let orig_time = Timespec::from(packet.orig_time); - let recv_time = Timespec::from(packet.recv_time); - let transmit_time = Timespec::from(packet.transmit_time); - - let drift = ((recv_time - orig_time) + (transmit_time - dest_time)) / 2; - - server.report_success(); - Ok(drift) - }, - Err(err) => { - server.report_failure(); - Err(err.into()) - }, - } - })) - }).unwrap_or_else(|| B(future::err(Error::NoServersAvailable))) - } -} - -// NOTE In a positive scenario first results will be seen after: -// MAX_RESULTS * UPDATE_TIMEOUT_INCOMPLETE_SECS seconds. -const MAX_RESULTS: usize = 4; -const UPDATE_TIMEOUT_OK_SECS: u64 = 6 * 60 * 60; -const UPDATE_TIMEOUT_WARN_SECS: u64 = 15 * 60; -const UPDATE_TIMEOUT_ERR_SECS: u64 = 60; -const UPDATE_TIMEOUT_INCOMPLETE_SECS: u64 = 10; - -/// Maximal valid time drift. -pub const MAX_DRIFT: i64 = 10_000; - -type BoxFuture = Box + Send>; - -#[derive(Debug, Clone)] -/// A time checker. -pub struct TimeChecker { - ntp: N, - last_result: Arc>)>>, -} - -impl TimeChecker { - /// Creates new time checker given the NTP server address. - pub fn new>(ntp_addresses: &[T], pool: CpuPool) -> Self { - let last_result = Arc::new(RwLock::new( - // Assume everything is ok at the very beginning. - (time::Instant::now(), vec![Ok(0)].into()) - )); - - let ntp = SimpleNtp::new(ntp_addresses, pool); - - TimeChecker { - ntp, - last_result, - } - } -} - -impl TimeChecker where ::Future: Send + 'static { - /// Updates the time - pub fn update(&self) -> BoxFuture { - trace!(target: "dapps", "Updating time from NTP."); - let last_result = self.last_result.clone(); - Box::new(self.ntp.drift().into_future().then(move |res| { - let res = res.map(|d| d.num_milliseconds()); - - if let Err(Error::NoServersAvailable) = res { - debug!(target: "dapps", "No NTP servers available. Selecting an older result."); - return select_result(last_result.read().1.iter()); - } - - // Update the results. - let mut results = mem::replace(&mut last_result.write().1, VecDeque::new()); - let has_all_results = results.len() >= MAX_RESULTS; - let valid_till = time::Instant::now() + time::Duration::from_secs( - match res { - Ok(time) if has_all_results && time < MAX_DRIFT => UPDATE_TIMEOUT_OK_SECS, - Ok(_) if has_all_results => UPDATE_TIMEOUT_WARN_SECS, - Err(_) if has_all_results => UPDATE_TIMEOUT_ERR_SECS, - _ => UPDATE_TIMEOUT_INCOMPLETE_SECS, - } - ); - - trace!(target: "dapps", "New time drift received: {:?}", res); - // Push the result. - results.push_back(res); - while results.len() > MAX_RESULTS { - results.pop_front(); - } - - // Select a response and update last result. - let res = select_result(results.iter()); - *last_result.write() = (valid_till, results); - res - })) - } - - /// Returns a current time drift or error if last request to NTP server failed. - pub fn time_drift(&self) -> BoxFuture { - // return cached result - { - let res = self.last_result.read(); - if res.0 > time::Instant::now() { - return Box::new(futures::done(select_result(res.1.iter()))); - } - } - // or update and return result - self.update() - } -} - -fn select_result<'a, T: Iterator>>(results: T) -> Result { - let mut min = None; - for res in results { - min = Some(match (min.take(), res) { - (Some(Ok(min)), &Ok(ref new)) => Ok(::std::cmp::min(min, *new)), - (Some(Ok(old)), &Err(_)) => Ok(old), - (_, ref new) => (*new).clone(), - }) - } - - min.unwrap_or_else(|| Err(Error::Ntp("NTP server unavailable.".into()))) -} - -#[cfg(test)] -mod tests { - use std::sync::Arc; - use std::cell::{Cell, RefCell}; - use std::time::Instant; - use time::Duration; - use futures::{future, Future}; - use super::{Ntp, TimeChecker, Error}; - use parking_lot::RwLock; - - #[derive(Clone)] - struct FakeNtp(RefCell>, Cell); - impl FakeNtp { - fn new() -> FakeNtp { - FakeNtp( - RefCell::new(vec![Duration::milliseconds(150)]), - Cell::new(0)) - } - } - - impl Ntp for FakeNtp { - type Future = future::FutureResult; - - fn drift(&self) -> Self::Future { - self.1.set(self.1.get() + 1); - future::ok(self.0.borrow_mut().pop().expect("Unexpected call to drift().")) - } - } - - fn time_checker() -> TimeChecker { - let last_result = Arc::new(RwLock::new( - (Instant::now(), vec![Err(Error::Ntp("NTP server unavailable".into()))].into()) - )); - - TimeChecker { - ntp: FakeNtp::new(), - last_result: last_result, - } - } - - #[test] - fn should_fetch_time_on_start() { - // given - let time = time_checker(); - - // when - let diff = time.time_drift().wait().unwrap(); - - // then - assert_eq!(diff, 150); - assert_eq!(time.ntp.1.get(), 1); - } - - #[test] - fn should_not_fetch_twice_if_timeout_has_not_passed() { - // given - let time = time_checker(); - - // when - let diff1 = time.time_drift().wait().unwrap(); - let diff2 = time.time_drift().wait().unwrap(); - - // then - assert_eq!(diff1, 150); - assert_eq!(diff2, 150); - assert_eq!(time.ntp.1.get(), 1); - } -} diff --git a/dapps/node-health/src/types.rs b/dapps/node-health/src/types.rs deleted file mode 100644 index ae883a626b9ecf99b18c6d2f768ce820952f6901..0000000000000000000000000000000000000000 --- a/dapps/node-health/src/types.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Base health types. - -/// Health API endpoint status. -#[derive(Debug, PartialEq, Serialize)] -pub enum HealthStatus { - /// Everything's OK. - #[serde(rename = "ok")] - Ok, - /// Node health need attention - /// (the issue is not critical, but may need investigation) - #[serde(rename = "needsAttention")] - NeedsAttention, - /// There is something bad detected with the node. - #[serde(rename = "bad")] - Bad, -} - -/// Represents a single check in node health. -/// Cointains the status of that check and apropriate message and details. -#[derive(Debug, PartialEq, Serialize)] -#[serde(deny_unknown_fields)] -pub struct HealthInfo { - /// Check status. - pub status: HealthStatus, - /// Human-readable message. - pub message: String, - /// Technical details of the check. - pub details: T, -} - -/// Node Health status. -#[derive(Debug, PartialEq, Serialize)] -#[serde(deny_unknown_fields)] -pub struct Health { - /// Status of peers. - pub peers: HealthInfo<(usize, usize)>, - /// Sync status. - pub sync: HealthInfo, - /// Time diff info. - pub time: HealthInfo, -} diff --git a/dapps/res/gavcoin.zip b/dapps/res/gavcoin.zip deleted file mode 100644 index 3ced8c5c1d8cf7d23d2f0db1b60fc4443b970e31..0000000000000000000000000000000000000000 Binary files a/dapps/res/gavcoin.zip and /dev/null differ diff --git a/dapps/src/api/api.rs b/dapps/src/api/api.rs deleted file mode 100644 index a9f9af293b0e0acad5780706214a15556f3ae3af..0000000000000000000000000000000000000000 --- a/dapps/src/api/api.rs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2015-2017 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 . - -use std::sync::Arc; - -use hyper::{Method, StatusCode}; - -use api::response; -use apps::fetcher::Fetcher; -use endpoint::{Endpoint, Request, Response, EndpointPath}; -use futures::{future, Future}; -use node_health::{NodeHealth, HealthStatus}; - -#[derive(Clone)] -pub struct RestApi { - fetcher: Arc, - health: NodeHealth, -} - -impl Endpoint for RestApi { - fn respond(&self, mut path: EndpointPath, req: Request) -> Response { - if let Method::Options = *req.method() { - return Box::new(future::ok(response::empty())); - } - - let endpoint = path.app_params.get(0).map(String::to_owned); - let hash = path.app_params.get(1).map(String::to_owned); - - // at this point path.app_id contains 'api', adjust it to the hash properly, otherwise - // we will try and retrieve 'api' as the hash when doing the /api/content route - if let Some(ref hash) = hash { - path.app_id = hash.to_owned(); - } - - trace!(target: "dapps", "Handling /api request: {:?}/{:?}", endpoint, hash); - match endpoint.as_ref().map(String::as_str) { - Some("ping") => Box::new(future::ok(response::ping(req))), - Some("health") => self.health(), - Some("content") => self.resolve_content(hash.as_ref().map(String::as_str), path, req), - _ => Box::new(future::ok(response::not_found())), - } - } -} - -impl RestApi { - pub fn new( - fetcher: Arc, - health: NodeHealth, - ) -> Box { - Box::new(RestApi { - fetcher, - health, - }) - } - - fn resolve_content(&self, hash: Option<&str>, path: EndpointPath, req: Request) -> Response { - trace!(target: "dapps", "Resolving content: {:?} from path: {:?}", hash, path); - match hash { - Some(hash) if self.fetcher.contains(hash) => { - self.fetcher.respond(path, req) - }, - _ => Box::new(future::ok(response::not_found())), - } - } - - fn health(&self) -> Response { - Box::new(self.health.health() - .then(|health| { - let status = match health { - Ok(ref health) => { - if [&health.peers.status, &health.sync.status].iter().any(|x| *x != &HealthStatus::Ok) { - StatusCode::PreconditionFailed // HTTP 412 - } else { - StatusCode::Ok // HTTP 200 - } - }, - _ => StatusCode::ServiceUnavailable, // HTTP 503 - }; - - Ok(response::as_json(status, &health).into()) - }) - ) - } -} diff --git a/dapps/src/api/mod.rs b/dapps/src/api/mod.rs deleted file mode 100644 index 4ffb9f791a72a43a666ee2a2ab30e7aa469d10e3..0000000000000000000000000000000000000000 --- a/dapps/src/api/mod.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015-2017 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 . - -//! REST API - -mod api; -mod response; -mod types; - -pub use self::api::RestApi; diff --git a/dapps/src/api/response.rs b/dapps/src/api/response.rs deleted file mode 100644 index c8d25c14450060896a2224f9cd0351d4b7b03fa7..0000000000000000000000000000000000000000 --- a/dapps/src/api/response.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2015-2017 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 . - -use serde::Serialize; -use serde_json; -use hyper::{self, mime, StatusCode}; - -use handlers::{ContentHandler, EchoHandler}; - -pub fn empty() -> hyper::Response { - ContentHandler::ok("".into(), mime::TEXT_PLAIN).into() -} - -pub fn as_json(status: StatusCode, val: &T) -> hyper::Response { - let json = serde_json::to_string(val) - .expect("serialization to string is infallible; qed"); - ContentHandler::new(status, json, mime::APPLICATION_JSON).into() -} - -pub fn ping(req: hyper::Request) -> hyper::Response { - EchoHandler::new(req).into() -} - -pub fn not_found() -> hyper::Response { - as_json(StatusCode::NotFound, &::api::types::ApiError { - code: "404".into(), - title: "Not Found".into(), - detail: "Resource you requested has not been found.".into(), - }) -} diff --git a/dapps/src/api/types.rs b/dapps/src/api/types.rs deleted file mode 100644 index 6beca3b5867d8418c9b11f8cf37366eb11fea0c1..0000000000000000000000000000000000000000 --- a/dapps/src/api/types.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2015-2017 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 . - -/// A structure representing any error in REST API. -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct ApiError { - /// Error code. - pub code: String, - /// Human-readable error summary. - pub title: String, - /// More technical error details. - pub detail: String, -} diff --git a/dapps/src/apps/app.rs b/dapps/src/apps/app.rs deleted file mode 100644 index c75346124c72bbe10bd518cc4905ffe8c187c57b..0000000000000000000000000000000000000000 --- a/dapps/src/apps/app.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2015-2017 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 . - -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct App { - pub id: Option, - pub name: String, - pub description: String, - pub version: String, - pub author: String, - #[serde(rename="iconUrl")] - pub icon_url: String, - #[serde(rename="localUrl")] - pub local_url: Option, - #[serde(rename="allowJsEval")] - pub allow_js_eval: Option, -} - -impl App { - pub fn with_id(&self, id: &str) -> Self { - let mut app = self.clone(); - app.id = Some(id.into()); - app - } -} diff --git a/dapps/src/apps/cache.rs b/dapps/src/apps/cache.rs deleted file mode 100644 index c81d4d9af9daf70ec956fe9d134cb66b1181699c..0000000000000000000000000000000000000000 --- a/dapps/src/apps/cache.rs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Fetchable Dapps support. - -use std::fs; - -use linked_hash_map::LinkedHashMap; -use page::local; -use handlers::FetchControl; - -pub enum ContentStatus { - Fetching(FetchControl), - Ready(local::Dapp), -} - -#[derive(Default)] -pub struct ContentCache { - cache: LinkedHashMap, -} - -impl ContentCache { - pub fn insert(&mut self, content_id: String, status: ContentStatus) -> Option { - self.cache.insert(content_id, status) - } - - pub fn remove(&mut self, content_id: &str) -> Option { - self.cache.remove(content_id) - } - - pub fn get(&mut self, content_id: &str) -> Option<&mut ContentStatus> { - self.cache.get_refresh(content_id) - } - - pub fn clear_garbage(&mut self, expected_size: usize) -> Vec<(String, ContentStatus)> { - let len = self.cache.len(); - - if len <= expected_size { - return Vec::new(); - } - - let mut removed = Vec::with_capacity(len - expected_size); - - while self.cache.len() > expected_size { - let entry = self.cache.pop_front().expect("expected_size bounded at 0, len is greater; qed"); - - match entry.1 { - ContentStatus::Fetching(ref fetch) => { - trace!(target: "dapps", "Aborting {} because of limit.", entry.0); - // Mark as aborted - fetch.abort() - }, - ContentStatus::Ready(ref endpoint) => { - trace!(target: "dapps", "Removing {} because of limit.", entry.0); - // Remove path (dir or file) - let res = fs::remove_dir_all(&endpoint.path()).or_else(|_| fs::remove_file(&endpoint.path())); - if let Err(e) = res { - warn!(target: "dapps", "Unable to remove dapp/content from cache: {:?}", e); - } - } - } - - removed.push(entry); - } - removed - } - - #[cfg(test)] - pub fn len(&self) -> usize { - self.cache.len() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn only_keys(data: Vec<(String, ContentStatus)>) -> Vec { - data.into_iter().map(|x| x.0).collect() - } - - #[test] - fn should_remove_least_recently_used() { - // given - let mut cache = ContentCache::default(); - cache.insert("a".into(), ContentStatus::Fetching(Default::default())); - cache.insert("b".into(), ContentStatus::Fetching(Default::default())); - cache.insert("c".into(), ContentStatus::Fetching(Default::default())); - - // when - let res = cache.clear_garbage(2); - - // then - assert_eq!(cache.len(), 2); - assert_eq!(only_keys(res), vec!["a"]); - } - - #[test] - fn should_update_lru_if_accessed() { - // given - let mut cache = ContentCache::default(); - cache.insert("a".into(), ContentStatus::Fetching(Default::default())); - cache.insert("b".into(), ContentStatus::Fetching(Default::default())); - cache.insert("c".into(), ContentStatus::Fetching(Default::default())); - - // when - cache.get("a"); - let res = cache.clear_garbage(2); - - // then - assert_eq!(cache.len(), 2); - assert_eq!(only_keys(res), vec!["b"]); - } - -} diff --git a/dapps/src/apps/fetcher/installers.rs b/dapps/src/apps/fetcher/installers.rs deleted file mode 100644 index 5bde5cf9993a3abcd08f8c035869fbedf1e8f619..0000000000000000000000000000000000000000 --- a/dapps/src/apps/fetcher/installers.rs +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright 2015-2017 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 . - -use zip; -use std::{fs, fmt}; -use std::io::{self, Read, Write}; -use std::path::PathBuf; -use ethereum_types::H256; -use fetch; -use futures_cpupool::CpuPool; -use hash::keccak_pipe; -use mime_guess::Mime; - -use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest, serialize_manifest, Manifest}; -use handlers::{ContentValidator, ValidatorResponse}; -use page::{local, PageCache}; -use Embeddable; - -type OnDone = Box) + Send>; - -fn write_response_and_check_hash( - id: &str, - mut content_path: PathBuf, - filename: &str, - response: fetch::Response -) -> Result<(fs::File, PathBuf), ValidationError> { - // try to parse id - let id = id.parse().map_err(|_| ValidationError::InvalidContentId)?; - - // check if content exists - if content_path.exists() { - warn!(target: "dapps", "Overwriting existing content at 0x{:?}", id); - fs::remove_dir_all(&content_path)? - } - - // create directory - fs::create_dir_all(&content_path)?; - - // append filename - content_path.push(filename); - - // Now write the response - let mut file = io::BufWriter::new(fs::File::create(&content_path)?); - let mut reader = io::BufReader::new(fetch::BodyReader::new(response)); - let hash = keccak_pipe(&mut reader, &mut file)?; - let mut file = file.into_inner()?; - file.flush()?; - - // Validate hash - if id == hash { - // The writing above changed the file Read position, which we need later. So we just create a new file handle - // here. - Ok((fs::File::open(&content_path)?, content_path)) - } else { - Err(ValidationError::HashMismatch { - expected: id, - got: hash, - }) - } -} - -pub struct Content { - id: String, - mime: Mime, - content_path: PathBuf, - on_done: OnDone, - pool: CpuPool, -} - -impl Content { - pub fn new(id: String, mime: Mime, content_path: PathBuf, on_done: OnDone, pool: CpuPool) -> Self { - Content { - id, - mime, - content_path, - on_done, - pool, - } - } -} - -impl ContentValidator for Content { - type Error = ValidationError; - - fn validate_and_install(self, response: fetch::Response) -> Result { - let pool = self.pool; - let id = self.id.clone(); - let mime = self.mime; - let validate = move |content_path: PathBuf| { - // Create dir - let (_, content_path) = write_response_and_check_hash(&id, content_path, &id, response)?; - - Ok(local::Dapp::single_file(pool, content_path, mime, PageCache::Enabled)) - }; - - // Prepare path for a file - let content_path = self.content_path.join(&self.id); - // Make sure to always call on_done (even in case of errors)! - let result = validate(content_path.clone()); - // remove the file if there was an error - if result.is_err() { - // Ignore errors since the file might not exist - let _ = fs::remove_dir_all(&content_path); - } - (self.on_done)(result.as_ref().ok().cloned()); - result.map(ValidatorResponse::Local) - } -} - -pub struct Dapp { - id: String, - dapps_path: PathBuf, - on_done: OnDone, - embeddable_on: Embeddable, - pool: CpuPool, -} - -impl Dapp { - pub fn new(id: String, dapps_path: PathBuf, on_done: OnDone, embeddable_on: Embeddable, pool: CpuPool) -> Self { - Dapp { - id, - dapps_path, - on_done, - embeddable_on, - pool, - } - } - - fn find_manifest(zip: &mut zip::ZipArchive) -> Result<(Manifest, PathBuf), ValidationError> { - for i in 0..zip.len() { - let mut file = zip.by_index(i)?; - - if !file.name().ends_with(MANIFEST_FILENAME) { - continue; - } - - // try to read manifest - let mut manifest = String::new(); - let manifest = file - .read_to_string(&mut manifest).ok() - .and_then(|_| deserialize_manifest(manifest).ok()); - - if let Some(manifest) = manifest { - let mut manifest_location = PathBuf::from(file.name()); - manifest_location.pop(); // get rid of filename - return Ok((manifest, manifest_location)); - } - } - - Err(ValidationError::ManifestNotFound) - } -} - -impl ContentValidator for Dapp { - type Error = ValidationError; - - fn validate_and_install(self, response: fetch::Response) -> Result { - let id = self.id.clone(); - let pool = self.pool; - let embeddable_on = self.embeddable_on; - let validate = move |dapp_path: PathBuf| { - let (file, zip_path) = write_response_and_check_hash(&id, dapp_path.clone(), &format!("{}.zip", id), response)?; - trace!(target: "dapps", "Opening dapp bundle at {:?}", zip_path); - // Unpack archive - let mut zip = zip::ZipArchive::new(file)?; - // First find manifest file - let (mut manifest, manifest_dir) = Self::find_manifest(&mut zip)?; - // Overwrite id to match hash - manifest.id = Some(id); - - // Unpack zip - for i in 0..zip.len() { - let mut file = zip.by_index(i)?; - let is_dir = file.name().chars().rev().next() == Some('/'); - - let file_path = PathBuf::from(file.name()); - let location_in_manifest_base = file_path.strip_prefix(&manifest_dir); - // Create files that are inside manifest directory - if let Ok(location_in_manifest_base) = location_in_manifest_base { - let p = dapp_path.join(location_in_manifest_base); - // Check if it's a directory - if is_dir { - fs::create_dir_all(p)?; - } else { - let mut target = fs::File::create(p)?; - io::copy(&mut file, &mut target)?; - } - } - } - - // Remove zip - fs::remove_file(&zip_path)?; - - // Write manifest - let manifest_str = serialize_manifest(&manifest).map_err(ValidationError::ManifestSerialization)?; - let manifest_path = dapp_path.join(MANIFEST_FILENAME); - let mut manifest_file = fs::File::create(manifest_path)?; - manifest_file.write_all(manifest_str.as_bytes())?; - // Create endpoint - let endpoint = local::Dapp::new(pool, dapp_path, manifest.into(), PageCache::Enabled, embeddable_on); - Ok(endpoint) - }; - - // Prepare directory for dapp - let target = self.dapps_path.join(&self.id); - // Validate the dapp - let result = validate(target.clone()); - // remove the file if there was an error - if result.is_err() { - // Ignore errors since the file might not exist - let _ = fs::remove_dir_all(&target); - } - (self.on_done)(result.as_ref().ok().cloned()); - result.map(ValidatorResponse::Local) - } -} - -#[derive(Debug)] -pub enum ValidationError { - Io(io::Error), - Zip(zip::result::ZipError), - InvalidContentId, - ManifestNotFound, - ManifestSerialization(String), - HashMismatch { expected: H256, got: H256, }, -} - -impl fmt::Display for ValidationError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match *self { - ValidationError::Io(ref io) => write!(f, "Unexpected IO error occured: {:?}", io), - ValidationError::Zip(ref zip) => write!(f, "Unable to read ZIP archive: {:?}", zip), - ValidationError::InvalidContentId => write!(f, "ID is invalid. It should be 256 bits keccak hash of content."), - ValidationError::ManifestNotFound => write!(f, "Downloaded Dapp bundle did not contain valid manifest.json file."), - ValidationError::ManifestSerialization(ref err) => { - write!(f, "There was an error during Dapp Manifest serialization: {:?}", err) - }, - ValidationError::HashMismatch { ref expected, ref got } => { - write!(f, "Hash of downloaded content did not match. Expected:{:?}, Got:{:?}.", expected, got) - }, - } - } -} - -impl From for ValidationError { - fn from(err: io::Error) -> Self { - ValidationError::Io(err) - } -} - -impl From for ValidationError { - fn from(err: zip::result::ZipError) -> Self { - ValidationError::Zip(err) - } -} - -impl From>> for ValidationError { - fn from(err: io::IntoInnerError>) -> Self { - ValidationError::Io(err.into()) - } -} diff --git a/dapps/src/apps/fetcher/mod.rs b/dapps/src/apps/fetcher/mod.rs deleted file mode 100644 index 8ed3024fdf2a1c0b7dffb2972c1de1d32194f86c..0000000000000000000000000000000000000000 --- a/dapps/src/apps/fetcher/mod.rs +++ /dev/null @@ -1,344 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Fetchable Dapps support. -//! Manages downloaded (cached) Dapps and downloads them when necessary. -//! Uses `URLHint` to resolve addresses into Dapps bundle file location. - -mod installers; - -use std::{fs, env}; -use std::path::PathBuf; -use std::sync::Arc; -use futures::{future, Future}; -use futures_cpupool::CpuPool; -use fetch::{Client as FetchClient, Fetch}; -use hash_fetch::urlhint::{URLHintContract, URLHint, URLHintResult}; - -use hyper::StatusCode; - -use ethereum_types::H256; -use {Embeddable, SyncStatus, random_filename}; -use parking_lot::Mutex; -use page::local; -use handlers::{ContentHandler, ContentFetcherHandler}; -use endpoint::{self, Endpoint, EndpointPath}; -use apps::cache::{ContentCache, ContentStatus}; - -/// Limit of cached dapps/content -const MAX_CACHED_DAPPS: usize = 20; - -pub trait Fetcher: Endpoint + 'static { - fn contains(&self, content_id: &str) -> bool; -} - -pub struct ContentFetcher { - cache_path: PathBuf, - resolver: R, - cache: Arc>, - sync: Arc, - embeddable_on: Embeddable, - fetch: F, - pool: CpuPool, - only_content: bool, -} - -impl Drop for ContentFetcher { - fn drop(&mut self) { - // Clear cache path - let _ = fs::remove_dir_all(&self.cache_path); - } -} - -impl ContentFetcher { - pub fn new( - resolver: R, - sync: Arc, - fetch: F, - pool: CpuPool, - ) -> Self { - let mut cache_path = env::temp_dir(); - cache_path.push(random_filename()); - - ContentFetcher { - cache_path, - resolver, - sync, - cache: Arc::new(Mutex::new(ContentCache::default())), - embeddable_on: None, - fetch, - pool, - only_content: true, - } - } - - pub fn allow_dapps(mut self, dapps: bool) -> Self { - self.only_content = !dapps; - self - } - - pub fn embeddable_on(mut self, embeddable_on: Embeddable) -> Self { - self.embeddable_on = embeddable_on; - self - } - - fn not_found(embeddable: Embeddable) -> endpoint::Response { - Box::new(future::ok(ContentHandler::error( - StatusCode::NotFound, - "Resource Not Found", - "Requested resource was not found.", - None, - embeddable, - ).into())) - } - - fn still_syncing(embeddable: Embeddable) -> endpoint::Response { - Box::new(future::ok(ContentHandler::error( - StatusCode::ServiceUnavailable, - "Sync In Progress", - "Your node is still syncing. We cannot resolve any content before it's fully synced.", - Some("Refresh"), - embeddable, - ).into())) - } - - fn dapps_disabled(address: Embeddable) -> endpoint::Response { - Box::new(future::ok(ContentHandler::error( - StatusCode::ServiceUnavailable, - "Network Dapps Not Available", - "This interface doesn't support network dapps for security reasons.", - None, - address, - ).into())) - } - - #[cfg(test)] - fn set_status(&self, content_id: &str, status: ContentStatus) { - self.cache.lock().insert(content_id.to_owned(), status); - } - - // resolve contract call synchronously. - // TODO: port to futures-based hyper and make it all async. - fn resolve(&self, content_id: H256) -> Option { - self.resolver.resolve(content_id) - .wait() - .unwrap_or_else(|e| { warn!("Error resolving content-id: {}", e); None }) - } -} - -impl Fetcher for ContentFetcher { - fn contains(&self, content_id: &str) -> bool { - { - let mut cache = self.cache.lock(); - // Check if we already have the app - if cache.get(content_id).is_some() { - return true; - } - } - // fallback to resolver - if let Ok(content_id) = content_id.parse() { - // if there is content or we are syncing return true - self.sync.is_major_importing() || self.resolve(content_id).is_some() - } else { - false - } - } -} - -impl Endpoint for ContentFetcher { - fn respond(&self, path: EndpointPath, req: endpoint::Request) -> endpoint::Response { - let mut cache = self.cache.lock(); - let content_id = path.app_id.clone(); - - let (new_status, handler) = { - let status = cache.get(&content_id); - match status { - // Just serve the content - Some(&mut ContentStatus::Ready(ref endpoint)) => { - (None, endpoint.to_response(&path)) - }, - // Content is already being fetched - Some(&mut ContentStatus::Fetching(ref fetch_control)) if !fetch_control.is_deadline_reached() => { - trace!(target: "dapps", "Content fetching in progress. Waiting..."); - (None, fetch_control.to_response(path)) - }, - // We need to start fetching the content - _ => { - trace!(target: "dapps", "Content unavailable. Fetching... {:?}", content_id); - let content_hex = content_id.parse().expect("to_handler is called only when `contains` returns true."); - let content = self.resolve(content_hex); - - let cache = self.cache.clone(); - let id = content_id.clone(); - let on_done = move |result: Option| { - let mut cache = cache.lock(); - match result { - Some(endpoint) => cache.insert(id.clone(), ContentStatus::Ready(endpoint)), - // In case of error - None => cache.remove(&id), - }; - }; - - match content { - // Don't serve dapps if we are still syncing (but serve content) - Some(URLHintResult::Dapp(_)) if self.sync.is_major_importing() => { - (None, Self::still_syncing(self.embeddable_on.clone())) - }, - Some(URLHintResult::Dapp(_)) if self.only_content => { - (None, Self::dapps_disabled(self.embeddable_on.clone())) - }, - Some(content) => { - let handler = match content { - URLHintResult::Dapp(dapp) => { - ContentFetcherHandler::new( - req.method(), - &dapp.url(), - path, - installers::Dapp::new( - content_id.clone(), - self.cache_path.clone(), - Box::new(on_done), - self.embeddable_on.clone(), - self.pool.clone(), - ), - self.embeddable_on.clone(), - self.fetch.clone(), - self.pool.clone(), - ) - }, - URLHintResult::GithubDapp(content) => { - ContentFetcherHandler::new( - req.method(), - &content.url, - path, - installers::Dapp::new( - content_id.clone(), - self.cache_path.clone(), - Box::new(on_done), - self.embeddable_on.clone(), - self.pool.clone(), - ), - self.embeddable_on.clone(), - self.fetch.clone(), - self.pool.clone(), - ) - }, - URLHintResult::Content(content) => { - ContentFetcherHandler::new( - req.method(), - &content.url, - path, - installers::Content::new( - content_id.clone(), - content.mime, - self.cache_path.clone(), - Box::new(on_done), - self.pool.clone(), - ), - self.embeddable_on.clone(), - self.fetch.clone(), - self.pool.clone(), - ) - }, - }; - - (Some(ContentStatus::Fetching(handler.fetch_control())), Box::new(handler) as endpoint::Response) - }, - None if self.sync.is_major_importing() => { - (None, Self::still_syncing(self.embeddable_on.clone())) - }, - None => { - // This may happen when sync status changes in between - // `contains` and `to_handler` - (None, Self::not_found(self.embeddable_on.clone())) - }, - } - }, - } - }; - - if let Some(status) = new_status { - cache.clear_garbage(MAX_CACHED_DAPPS); - cache.insert(content_id, status); - } - - handler - } -} - -#[cfg(test)] -mod tests { - use std::env; - use std::sync::Arc; - use fetch::Client; - use futures::{future, Future}; - use hash_fetch::urlhint::{URLHint, URLHintResult}; - use ethereum_types::H256; - - use apps::cache::ContentStatus; - use endpoint::EndpointInfo; - use page::local; - use super::{ContentFetcher, Fetcher}; - use {SyncStatus}; - - #[derive(Clone)] - struct FakeResolver; - impl URLHint for FakeResolver { - fn resolve(&self, _id: H256) -> Box, Error = String> + Send> { - Box::new(future::ok(None)) - } - } - - #[derive(Debug)] - struct FakeSync(bool); - impl SyncStatus for FakeSync { - fn is_major_importing(&self) -> bool { self.0 } - fn peers(&self) -> (usize, usize) { (0, 5) } - } - - #[test] - fn should_true_if_contains_the_app() { - // given - let pool = ::futures_cpupool::CpuPool::new(1); - let path = env::temp_dir(); - let fetcher = ContentFetcher::new( - FakeResolver, - Arc::new(FakeSync(false)), - Client::new().unwrap(), - pool.clone(), - ).allow_dapps(true); - - let handler = local::Dapp::new(pool, path, EndpointInfo { - id: None, - name: "fake".into(), - description: "".into(), - version: "".into(), - author: "".into(), - icon_url: "".into(), - local_url: Some("".into()), - allow_js_eval: None, - }, Default::default(), None); - - // when - fetcher.set_status("test", ContentStatus::Ready(handler)); - fetcher.set_status("test2", ContentStatus::Fetching(Default::default())); - - // then - assert_eq!(fetcher.contains("test"), true); - assert_eq!(fetcher.contains("test2"), true); - assert_eq!(fetcher.contains("test3"), false); - } -} diff --git a/dapps/src/apps/fs.rs b/dapps/src/apps/fs.rs deleted file mode 100644 index 3d93a2fae1a372221d3520bcfa82d16c158deafa..0000000000000000000000000000000000000000 --- a/dapps/src/apps/fs.rs +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2015-2017 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 . - -use std::collections::BTreeMap; -use std::io; -use std::io::Read; -use std::fs; -use std::path::{Path, PathBuf}; -use futures_cpupool::CpuPool; - -use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest}; -use endpoint::{Endpoint, EndpointInfo}; -use page::{local, PageCache}; -use Embeddable; - -struct LocalDapp { - id: String, - path: PathBuf, - info: EndpointInfo, -} - -/// Tries to find and read manifest file in given `path` to extract `EndpointInfo` -/// If manifest is not found sensible default `EndpointInfo` is returned based on given `name`. -fn read_manifest(name: &str, mut path: PathBuf) -> EndpointInfo { - path.push(MANIFEST_FILENAME); - - fs::File::open(path.clone()) - .map_err(|e| format!("{:?}", e)) - .and_then(|mut f| { - // Reat file - let mut s = String::new(); - f.read_to_string(&mut s).map_err(|e| format!("{:?}", e))?; - // Try to deserialize manifest - deserialize_manifest(s) - }) - .unwrap_or_else(|e| { - warn!(target: "dapps", "Cannot read manifest file at: {:?}. Error: {:?}", path, e); - - EndpointInfo { - id: None, - name: name.into(), - description: name.into(), - version: "0.0.0".into(), - author: "?".into(), - icon_url: "icon.png".into(), - local_url: None, - allow_js_eval: Some(false), - } - }) -} - -/// Returns Dapp Id and Local Dapp Endpoint for given filesystem path. -/// Parses the path to extract last component (for name). -/// `None` is returned when path is invalid or non-existent. -pub fn local_endpoint>(path: P, embeddable: Embeddable, pool: CpuPool) -> Option<(String, Box)> { - let path = path.as_ref().to_owned(); - path.canonicalize().ok().and_then(|path| { - let name = path.file_name().and_then(|name| name.to_str()); - name.map(|name| { - let dapp = local_dapp(name.into(), path.clone()); - (dapp.id, Box::new(local::Dapp::new( - pool.clone(), dapp.path, dapp.info, PageCache::Disabled, embeddable.clone()) - )) - }) - }) -} - - -fn local_dapp(name: String, path: PathBuf) -> LocalDapp { - // try to get manifest file - let info = read_manifest(&name, path.clone()); - LocalDapp { - id: name, - path: path, - info: info, - } -} - -/// Returns endpoints for Local Dapps found for given filesystem path. -/// Scans the directory and collects `local::Dapp`. -pub fn local_endpoints>(dapps_path: P, embeddable: Embeddable, pool: CpuPool) -> BTreeMap> { - let mut pages = BTreeMap::>::new(); - for dapp in local_dapps(dapps_path.as_ref()) { - pages.insert( - dapp.id, - Box::new(local::Dapp::new(pool.clone(), dapp.path, dapp.info, PageCache::Disabled, embeddable.clone())) - ); - } - pages -} - - -fn local_dapps(dapps_path: &Path) -> Vec { - let files = fs::read_dir(dapps_path); - if let Err(e) = files { - warn!(target: "dapps", "Unable to load local dapps from: {}. Reason: {:?}", dapps_path.display(), e); - return vec![]; - } - - let files = files.expect("Check is done earlier"); - files.map(|dir| { - let entry = dir?; - let file_type = entry.file_type()?; - - // skip files - if file_type.is_file() { - return Err(io::Error::new(io::ErrorKind::NotFound, "Not a file")); - } - - // take directory name and path - entry.file_name().into_string() - .map(|name| (name, entry.path())) - .map_err(|e| { - info!(target: "dapps", "Unable to load dapp: {:?}. Reason: {:?}", entry.path(), e); - io::Error::new(io::ErrorKind::NotFound, "Invalid name") - }) - }) - .filter_map(|m| { - if let Err(ref e) = m { - debug!(target: "dapps", "Ignoring local dapp: {:?}", e); - } - m.ok() - }) - .map(|(name, path)| local_dapp(name, path)) - .collect() -} diff --git a/dapps/src/apps/manifest.rs b/dapps/src/apps/manifest.rs deleted file mode 100644 index e320482195da5c1feb093ef29368fb1390054869..0000000000000000000000000000000000000000 --- a/dapps/src/apps/manifest.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2015-2017 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 . - -use serde_json; -pub use apps::App as Manifest; - -pub const MANIFEST_FILENAME: &'static str = "manifest.json"; - -pub fn deserialize_manifest(manifest: String) -> Result { - let mut manifest = serde_json::from_str::(&manifest).map_err(|e| format!("{:?}", e))?; - if manifest.id.is_none() { - return Err("App 'id' is missing.".into()); - } - manifest.allow_js_eval = Some(manifest.allow_js_eval.unwrap_or(false)); - - Ok(manifest) -} - -pub fn serialize_manifest(manifest: &Manifest) -> Result { - serde_json::to_string_pretty(manifest).map_err(|e| format!("{:?}", e)) -} diff --git a/dapps/src/apps/mod.rs b/dapps/src/apps/mod.rs deleted file mode 100644 index 21947b928bf65e1fdebafc480a83377cb44712b6..0000000000000000000000000000000000000000 --- a/dapps/src/apps/mod.rs +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2015-2017 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 . - -use std::path::PathBuf; -use std::sync::Arc; - -use endpoint::{Endpoints, Endpoint}; -use futures_cpupool::CpuPool; -use page; -use proxypac::ProxyPac; -use web::Web; -use fetch::Fetch; -use {WebProxyTokens, ParentFrameSettings}; - -mod app; -mod cache; -mod ui; -pub mod fs; -pub mod fetcher; -pub mod manifest; - -pub use self::app::App; - -pub const HOME_PAGE: &'static str = "home"; -pub const RPC_PATH: &'static str = "rpc"; -pub const API_PATH: &'static str = "api"; -pub const UTILS_PATH: &'static str = "parity-utils"; -pub const WEB_PATH: &'static str = "web"; -pub const URL_REFERER: &'static str = "__referer="; - -pub fn utils(pool: CpuPool) -> Box { - Box::new(page::builtin::Dapp::new(pool, ::parity_ui::App::default())) -} - -pub fn ui(pool: CpuPool) -> Box { - Box::new(page::builtin::Dapp::with_fallback_to_index(pool, ::parity_ui::App::default())) -} - -pub fn ui_deprecation(pool: CpuPool) -> Box { - Box::new(page::builtin::Dapp::with_fallback_to_index(pool, ::parity_ui_deprecation::App::default())) -} - -pub fn ui_redirection(embeddable: Option) -> Box { - Box::new(ui::Redirection::new(embeddable)) -} - -pub fn all_endpoints( - dapps_path: PathBuf, - extra_dapps: Vec, - dapps_domain: &str, - embeddable: Option, - web_proxy_tokens: Arc, - fetch: F, - pool: CpuPool, -) -> (Vec, Endpoints) { - // fetch fs dapps at first to avoid overwriting builtins - let mut pages = fs::local_endpoints(dapps_path.clone(), embeddable.clone(), pool.clone()); - let local_endpoints: Vec = pages.keys().cloned().collect(); - for path in extra_dapps { - if let Some((id, endpoint)) = fs::local_endpoint(path.clone(), embeddable.clone(), pool.clone()) { - pages.insert(id, endpoint); - } else { - warn!(target: "dapps", "Ignoring invalid dapp at {}", path.display()); - } - } - - // NOTE [ToDr] Dapps will be currently embeded on 8180 - pages.insert( - "ui".into(), - Box::new(page::builtin::Dapp::new_safe_to_embed(pool.clone(), ::parity_ui::App::default(), embeddable.clone())) - ); - // old version - pages.insert( - "v1".into(), - Box::new({ - let mut page = page::builtin::Dapp::new_safe_to_embed(pool.clone(), ::parity_ui::old::App::default(), embeddable.clone()); - // allow JS eval on old Wallet - page.allow_js_eval(); - page - }) - ); - pages.insert( - "proxy".into(), - ProxyPac::boxed(embeddable.clone(), dapps_domain.to_owned()) - ); - pages.insert( - WEB_PATH.into(), - Web::boxed(embeddable.clone(), web_proxy_tokens.clone(), fetch.clone(), pool.clone()) - ); - - (local_endpoints, pages) -} diff --git a/dapps/src/apps/ui.rs b/dapps/src/apps/ui.rs deleted file mode 100644 index 39da14e5b97509e918e821b702152ae51c8904db..0000000000000000000000000000000000000000 --- a/dapps/src/apps/ui.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2015-2017 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 . - -//! UI redirections - -use hyper::StatusCode; -use futures::future; - -use endpoint::{Endpoint, Request, Response, EndpointPath}; -use {handlers, Embeddable}; - -/// Redirection to UI server. -pub struct Redirection { - embeddable_on: Embeddable, -} - -impl Redirection { - pub fn new( - embeddable_on: Embeddable, - ) -> Self { - Redirection { - embeddable_on, - } - } -} - -impl Endpoint for Redirection { - fn respond(&self, _path: EndpointPath, req: Request) -> Response { - Box::new(future::ok(if let Some(ref frame) = self.embeddable_on { - trace!(target: "dapps", "Redirecting to signer interface."); - let protocol = req.uri().scheme().unwrap_or("http"); - handlers::Redirection::new(format!("{}://{}:{}", protocol, &frame.host, frame.port)).into() - } else { - trace!(target: "dapps", "Signer disabled, returning 404."); - handlers::ContentHandler::error( - StatusCode::NotFound, - "404 Not Found", - "Your homepage is not available when Trusted Signer is disabled.", - Some("You can still access dapps by writing a correct address, though. Re-enable Signer to get your homepage back."), - None, - ).into() - })) - } -} diff --git a/dapps/src/endpoint.rs b/dapps/src/endpoint.rs deleted file mode 100644 index fd05445c2a240105073eb1dd7f283f79174b299a..0000000000000000000000000000000000000000 --- a/dapps/src/endpoint.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2015-2017 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 . - -//! URL Endpoint traits - -use std::collections::BTreeMap; - -use futures::Future; -use hyper; - -#[derive(Debug, PartialEq, Default, Clone)] -pub struct EndpointPath { - pub app_id: String, - pub app_params: Vec, - pub query: Option, - pub host: String, - pub port: u16, - pub using_dapps_domains: bool, -} - -impl EndpointPath { - pub fn has_no_params(&self) -> bool { - self.app_params.is_empty() || self.app_params.iter().all(|x| x.is_empty()) - } -} - -pub type EndpointInfo = ::apps::App; -pub type Endpoints = BTreeMap>; -pub type Response = Box + Send>; -pub type Request = hyper::Request; - -pub trait Endpoint : Send + Sync { - fn info(&self) -> Option<&EndpointInfo> { None } - - fn respond(&self, path: EndpointPath, req: Request) -> Response; -} diff --git a/dapps/src/error_tpl.html b/dapps/src/error_tpl.html deleted file mode 100644 index c6b4db0e7f5508b33a3cd349c414a99c65a84fd5..0000000000000000000000000000000000000000 --- a/dapps/src/error_tpl.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - {title} - - - -
-
-
-

{title}

-

{message}

-

{details}

-
-
- {version} -
- - diff --git a/dapps/src/handlers/content.rs b/dapps/src/handlers/content.rs deleted file mode 100644 index c7eccf474e44daae2904f0d656ff8d1be09f6e00..0000000000000000000000000000000000000000 --- a/dapps/src/handlers/content.rs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Simple Content Handler - -use hyper::{self, mime, header}; -use hyper::StatusCode; - -use parity_version::version; - -use handlers::add_security_headers; -use Embeddable; - -#[derive(Debug, Clone)] -pub struct ContentHandler { - code: StatusCode, - content: String, - mimetype: mime::Mime, - safe_to_embed_on: Embeddable, -} - -impl ContentHandler { - pub fn ok(content: String, mimetype: mime::Mime) -> Self { - Self::new(StatusCode::Ok, content, mimetype) - } - - pub fn html(code: StatusCode, content: String, embeddable_on: Embeddable) -> Self { - Self::new_embeddable(code, content, mime::TEXT_HTML, embeddable_on) - } - - pub fn error( - code: StatusCode, - title: &str, - message: &str, - details: Option<&str>, - embeddable_on: Embeddable, - ) -> Self { - Self::html(code, format!( - include_str!("../error_tpl.html"), - title=title, - message=message, - details=details.unwrap_or_else(|| ""), - version=version(), - ), embeddable_on) - } - - pub fn new(code: StatusCode, content: String, mimetype: mime::Mime) -> Self { - Self::new_embeddable(code, content, mimetype, None) - } - - pub fn new_embeddable( - code: StatusCode, - content: String, - mimetype: mime::Mime, - safe_to_embed_on: Embeddable, - ) -> Self { - ContentHandler { - code, - content, - mimetype, - safe_to_embed_on, - } - } -} - -impl Into for ContentHandler { - fn into(self) -> hyper::Response { - let mut res = hyper::Response::new() - .with_status(self.code) - .with_header(header::ContentType(self.mimetype)) - .with_body(self.content); - add_security_headers(&mut res.headers_mut(), self.safe_to_embed_on, false); - res - } -} diff --git a/dapps/src/handlers/echo.rs b/dapps/src/handlers/echo.rs deleted file mode 100644 index 375f047906fea1e065743adfa8440a11a7c97a04..0000000000000000000000000000000000000000 --- a/dapps/src/handlers/echo.rs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Echo Handler - -use hyper::{self, header}; - -use handlers::add_security_headers; - -#[derive(Debug)] -pub struct EchoHandler { - request: hyper::Request, -} - -impl EchoHandler { - pub fn new(request: hyper::Request) -> Self { - EchoHandler { - request, - } - } -} - -impl Into for EchoHandler { - fn into(self) -> hyper::Response { - let content_type = self.request.headers().get().cloned(); - let mut res = hyper::Response::new() - .with_header(content_type.unwrap_or(header::ContentType::json())) - .with_body(self.request.body()); - - add_security_headers(res.headers_mut(), None, false); - res - } -} diff --git a/dapps/src/handlers/fetch.rs b/dapps/src/handlers/fetch.rs deleted file mode 100644 index 1408d634dbb8f306281f6f6a2ff093c0d0a93586..0000000000000000000000000000000000000000 --- a/dapps/src/handlers/fetch.rs +++ /dev/null @@ -1,373 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Hyper Server Handler that fetches a file during a request (proxy). - -use std::{fmt, mem}; -use std::sync::Arc; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::time::{Instant, Duration}; -use fetch::{self, Fetch}; -use futures::sync::oneshot; -use futures::{self, Future}; -use futures_cpupool::CpuPool; -use hyper::{self, StatusCode}; -use parking_lot::Mutex; - -use endpoint::{self, EndpointPath}; -use handlers::{ContentHandler, StreamingHandler}; -use page::local; -use {Embeddable}; - -const FETCH_TIMEOUT: Duration = Duration::from_secs(300); - -pub enum ValidatorResponse { - Local(local::Dapp), - Streaming(StreamingHandler), -} - -pub trait ContentValidator: Sized + Send + 'static { - type Error: fmt::Debug + fmt::Display; - - fn validate_and_install(self, fetch::Response) -> Result; -} - -#[derive(Debug, Clone)] -pub struct FetchControl { - abort: Arc, - listeners: Arc>>>, - deadline: Instant, -} - -impl Default for FetchControl { - fn default() -> Self { - FetchControl { - abort: Arc::new(AtomicBool::new(false)), - listeners: Arc::new(Mutex::new(Vec::new())), - deadline: Instant::now() + FETCH_TIMEOUT, - } - } -} - -impl FetchControl { - pub fn is_deadline_reached(&self) -> bool { - self.deadline < Instant::now() - } - - pub fn abort(&self) { - self.abort.store(true, Ordering::SeqCst); - } - - pub fn to_response(&self, path: EndpointPath) -> endpoint::Response { - let (tx, receiver) = oneshot::channel(); - self.listeners.lock().push(tx); - - Box::new(WaitingHandler { - path, - state: WaitState::Waiting(receiver), - }) - } - - fn notify WaitResult>(&self, status: F) { - let mut listeners = self.listeners.lock(); - for sender in listeners.drain(..) { - trace!(target: "dapps", "Resuming request waiting for content..."); - if let Err(_) = sender.send(status()) { - trace!(target: "dapps", "Waiting listener notification failed."); - } - } - } - - fn set_status(&self, status: &FetchState) { - match *status { - FetchState::Error(ref handler) => self.notify(|| WaitResult::Error(handler.clone())), - FetchState::Done(ref endpoint, _) => self.notify(|| WaitResult::Done(endpoint.clone())), - FetchState::Streaming(_) => self.notify(|| WaitResult::NonAwaitable), - FetchState::InProgress(_) => {}, - FetchState::Empty => {}, - } - } -} - - -enum WaitState { - Waiting(oneshot::Receiver), - Done(endpoint::Response), -} - -#[derive(Debug)] -enum WaitResult { - Error(ContentHandler), - Done(local::Dapp), - NonAwaitable, -} - -pub struct WaitingHandler { - path: EndpointPath, - state: WaitState, -} - -impl Future for WaitingHandler { - type Item = hyper::Response; - type Error = hyper::Error; - - fn poll(&mut self) -> futures::Poll { - loop { - let new_state = match self.state { - WaitState::Waiting(ref mut receiver) => { - let result = try_ready!(receiver.poll().map_err(|_| hyper::Error::Timeout)); - - match result { - WaitResult::Error(handler) => { - return Ok(futures::Async::Ready(handler.into())); - }, - WaitResult::NonAwaitable => { - let errors = Errors { embeddable_on: None }; - return Ok(futures::Async::Ready(errors.streaming().into())); - }, - WaitResult::Done(endpoint) => { - WaitState::Done(endpoint.to_response(&self.path).into()) - }, - } - }, - WaitState::Done(ref mut response) => { - return response.poll() - }, - }; - - self.state = new_state; - } - } -} - -#[derive(Debug, Clone)] -struct Errors { - embeddable_on: Embeddable, -} - -impl Errors { - fn streaming(&self) -> ContentHandler { - ContentHandler::error( - StatusCode::BadGateway, - "Streaming Error", - "This content is being streamed in other place.", - None, - self.embeddable_on.clone(), - ) - } - - fn download_error(&self, e: E) -> ContentHandler { - ContentHandler::error( - StatusCode::BadGateway, - "Download Error", - "There was an error when fetching the content.", - Some(&format!("{:?}", e)), - self.embeddable_on.clone(), - ) - } - - fn invalid_content(&self, e: E) -> ContentHandler { - ContentHandler::error( - StatusCode::BadGateway, - "Invalid Dapp", - "Downloaded bundle does not contain a valid content.", - Some(&format!("{:?}", e)), - self.embeddable_on.clone(), - ) - } - - fn timeout_error(&self) -> ContentHandler { - ContentHandler::error( - StatusCode::GatewayTimeout, - "Download Timeout", - &format!("Could not fetch content within {} seconds.", FETCH_TIMEOUT.as_secs()), - None, - self.embeddable_on.clone(), - ) - } - - fn method_not_allowed(&self) -> ContentHandler { - ContentHandler::error( - StatusCode::MethodNotAllowed, - "Method Not Allowed", - "Only GET requests are allowed.", - None, - self.embeddable_on.clone(), - ) - } -} - -enum FetchState { - Error(ContentHandler), - InProgress(Box + Send>), - Streaming(hyper::Response), - Done(local::Dapp, endpoint::Response), - Empty, -} - -impl fmt::Debug for FetchState { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - use self::FetchState::*; - - write!(fmt, "FetchState(")?; - match *self { - Error(ref error) => write!(fmt, "error: {:?}", error), - InProgress(_) => write!(fmt, "in progress"), - Streaming(ref res) => write!(fmt, "streaming: {:?}", res), - Done(ref endpoint, _) => write!(fmt, "done: {:?}", endpoint), - Empty => write!(fmt, "?"), - }?; - write!(fmt, ")") - } -} - -#[derive(Debug)] -pub struct ContentFetcherHandler { - fetch_control: FetchControl, - status: FetchState, - errors: Errors, -} - -impl ContentFetcherHandler { - pub fn fetch_control(&self) -> FetchControl { - self.fetch_control.clone() - } - - pub fn new( - method: &hyper::Method, - url: &str, - path: EndpointPath, - installer: H, - embeddable_on: Embeddable, - fetch: F, - pool: CpuPool, - ) -> Self { - let fetch_control = FetchControl::default(); - let errors = Errors { embeddable_on }; - - // Validation of method - let status = match *method { - // Start fetching content - hyper::Method::Get => { - trace!(target: "dapps", "Fetching content from: {:?}", url); - FetchState::InProgress(Self::fetch_content( - pool, - fetch, - url, - fetch_control.abort.clone(), - path, - errors.clone(), - installer, - )) - }, - // or return error - _ => FetchState::Error(errors.method_not_allowed()), - }; - - ContentFetcherHandler { - fetch_control, - status, - errors, - } - } - - fn fetch_content( - pool: CpuPool, - fetch: F, - url: &str, - abort: Arc, - path: EndpointPath, - errors: Errors, - installer: H, - ) -> Box + Send> { - // Start fetching the content - let pool2 = pool.clone(); - let future = fetch.get(url, abort.into()).then(move |result| { - trace!(target: "dapps", "Fetching content finished. Starting validation: {:?}", result); - Ok(match result { - Ok(response) => match installer.validate_and_install(response) { - Ok(ValidatorResponse::Local(endpoint)) => { - trace!(target: "dapps", "Validation OK. Returning response."); - let response = endpoint.to_response(&path); - FetchState::Done(endpoint, response) - }, - Ok(ValidatorResponse::Streaming(stream)) => { - trace!(target: "dapps", "Validation OK. Streaming response."); - let (reading, response) = stream.into_response(); - pool.spawn(reading).forget(); - FetchState::Streaming(response) - }, - Err(e) => { - trace!(target: "dapps", "Error while validating content: {:?}", e); - FetchState::Error(errors.invalid_content(e)) - }, - }, - Err(e) => { - warn!(target: "dapps", "Unable to fetch content: {:?}", e); - FetchState::Error(errors.download_error(e)) - }, - }) - }); - - // make sure to run within fetch thread pool. - Box::new(pool2.spawn(future)) - } -} - -impl Future for ContentFetcherHandler { - type Item = hyper::Response; - type Error = hyper::Error; - - fn poll(&mut self) -> futures::Poll { - loop { - trace!(target: "dapps", "Polling status: {:?}", self.status); - self.status = match mem::replace(&mut self.status, FetchState::Empty) { - FetchState::Error(error) => { - return Ok(futures::Async::Ready(error.into())); - }, - FetchState::Streaming(response) => { - return Ok(futures::Async::Ready(response)); - }, - any => any, - }; - - let status = match self.status { - // Request may time out - FetchState::InProgress(_) if self.fetch_control.is_deadline_reached() => { - trace!(target: "dapps", "Fetching dapp failed because of timeout."); - FetchState::Error(self.errors.timeout_error()) - }, - FetchState::InProgress(ref mut receiver) => { - // Check if there is a response - trace!(target: "dapps", "Polling streaming response."); - try_ready!(receiver.poll().map_err(|err| { - warn!(target: "dapps", "Error while fetching response: {:?}", err); - hyper::Error::Timeout - })) - }, - FetchState::Done(_, ref mut response) => { - return response.poll() - }, - FetchState::Empty => panic!("Future polled twice."), - _ => unreachable!(), - }; - - trace!(target: "dapps", "New status: {:?}", status); - self.fetch_control.set_status(&status); - self.status = status; - } - } -} diff --git a/dapps/src/handlers/mod.rs b/dapps/src/handlers/mod.rs deleted file mode 100644 index f78f46c76471d0e11236290c44f723af41aef6f8..0000000000000000000000000000000000000000 --- a/dapps/src/handlers/mod.rs +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Hyper handlers implementations. - -mod content; -mod echo; -mod fetch; -mod reader; -mod redirect; -mod streaming; - -pub use self::content::ContentHandler; -pub use self::echo::EchoHandler; -pub use self::fetch::{ContentFetcherHandler, ContentValidator, FetchControl, ValidatorResponse}; -pub use self::reader::Reader; -pub use self::redirect::Redirection; -pub use self::streaming::StreamingHandler; - -use std::iter; -use itertools::Itertools; -use hyper::header; -use {apps, address, Embeddable}; - -/// Adds security-related headers to the Response. -pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embeddable, allow_js_eval: bool) { - headers.set_raw("X-XSS-Protection", "1; mode=block"); - headers.set_raw("X-Content-Type-Options", "nosniff"); - - // Embedding header: - if let None = embeddable_on { - headers.set_raw("X-Frame-Options", "SAMEORIGIN"); - } - - // Content Security Policy headers - headers.set_raw("Content-Security-Policy", String::new() - // Restrict everything to the same origin by default. - + "default-src 'self';" - // Allow connecting to WS servers and HTTP(S) servers. - // We could be more restrictive and allow only RPC server URL. - + "connect-src http: https: ws: wss:;" - // Allow framing any content from HTTP(S). - // Again we could only allow embedding from RPC server URL. - // (deprecated) - + "frame-src 'self' http: https:;" - // Allow framing and web workers from HTTP(S). - + "child-src 'self' http: https:;" - // We allow data: blob: and HTTP(s) images. - // We could get rid of wildcarding HTTP and only allow RPC server URL. - // (http required for local dapps icons) - + "img-src 'self' 'unsafe-inline' data: blob: http: https:;" - // Allow style from data: blob: and HTTPS. - + "style-src 'self' 'unsafe-inline' data: blob: https:;" - // Allow fonts from data: and HTTPS. - + "font-src 'self' data: https:;" - // Disallow objects - + "object-src 'none';" - // Allow scripts - + { - let script_src = embeddable_on.as_ref() - .map(|e| e.extra_script_src.iter() - .map(|&(ref host, port)| address(host, port)) - .join(" ") - ).unwrap_or_default(); - let eval = if allow_js_eval { " 'unsafe-eval'" } else { "" }; - - &format!( - "script-src 'self' {}{};", - script_src, - eval - ) - } - // Same restrictions as script-src with additional - // blob: that is required for camera access (worker) - + "worker-src 'self' https: blob:;" - // Run in sandbox mode (although it's not fully safe since we allow same-origin and script) - + "sandbox allow-same-origin allow-forms allow-modals allow-popups allow-presentation allow-scripts;" - // Disallow submitting forms from any dapps - + "form-action 'none';" - // Never allow mixed content - + "block-all-mixed-content;" - // Specify if the site can be embedded. - + &match embeddable_on { - Some(ref embed) => { - let std = address(&embed.host, embed.port); - let proxy = format!("{}.{}", apps::HOME_PAGE, embed.dapps_domain); - let domain = format!("*.{}:{}", embed.dapps_domain, embed.port); - - let mut ancestors = vec![std, domain, proxy] - .into_iter() - .chain(embed.extra_embed_on - .iter() - .map(|&(ref host, port)| address(host, port)) - ); - - let ancestors = if embed.host == "127.0.0.1" { - let localhost = address("localhost", embed.port); - ancestors.chain(iter::once(localhost)).join(" ") - } else { - ancestors.join(" ") - }; - - format!("frame-ancestors {};", ancestors) - }, - None => format!("frame-ancestors 'self';"), - } - ); -} diff --git a/dapps/src/handlers/reader.rs b/dapps/src/handlers/reader.rs deleted file mode 100644 index 85a351c7b0c934f832d33cc038a3aa1351f44f0d..0000000000000000000000000000000000000000 --- a/dapps/src/handlers/reader.rs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2015-2017 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 . - -//! A chunk-producing io::Read wrapper. - -use std::io::{self, Read}; - -use futures::{self, sink, Sink, Future}; -use futures::sync::mpsc; -use hyper; - -type Sender = mpsc::Sender>; - -const MAX_CHUNK_SIZE: usize = 32 * 1024; - -/// A Reader is essentially a stream of `hyper::Chunks`. -/// The chunks are read from given `io::Read` instance. -/// -/// Unfortunately `hyper` doesn't allow you to pass `Stream` -/// directly to the response, so you need to create -/// a `Body::pair()` and send over chunks using `sink::Send`. -/// Also `Chunks` need to take `Vec` by value, so we need -/// to allocate it for each chunk being sent. -pub struct Reader { - buffer: [u8; MAX_CHUNK_SIZE], - content: io::BufReader, - sending: sink::Send, -} - -impl Reader { - pub fn pair(content: R, initial: Vec) -> (Self, hyper::Body) { - let (tx, rx) = hyper::Body::pair(); - let reader = Reader { - buffer: [0; MAX_CHUNK_SIZE], - content: io::BufReader::new(content), - sending: tx.send(Ok(initial.into())), - }; - - (reader, rx) - } -} - -impl Future for Reader { - type Item = (); - type Error = (); - - fn poll(&mut self) -> futures::Poll { - loop { - let next = try_ready!(self.sending.poll().map_err(|err| { - warn!(target: "dapps", "Unable to send next chunk: {:?}", err); - })); - - self.sending = match self.content.read(&mut self.buffer) { - Ok(0) => return Ok(futures::Async::Ready(())), - Ok(read) => next.send(Ok(self.buffer[..read].to_vec().into())), - Err(err) => next.send(Err(hyper::Error::Io(err))), - } - } - } -} diff --git a/dapps/src/handlers/redirect.rs b/dapps/src/handlers/redirect.rs deleted file mode 100644 index cb1eda2dd555706effa224f83af19916adf99b94..0000000000000000000000000000000000000000 --- a/dapps/src/handlers/redirect.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2015-2017 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 . - -//! HTTP Redirection hyper handler - -use hyper::{self, header, StatusCode}; - -#[derive(Clone)] -pub struct Redirection { - to_url: String -} - -impl Redirection { - pub fn new>(url: T) -> Self { - Redirection { - to_url: url.into() - } - } -} - -impl Into for Redirection { - fn into(self) -> hyper::Response { - // Don't use `MovedPermanently` here to prevent browser from caching the redirections. - hyper::Response::new() - .with_status(StatusCode::Found) - .with_header(header::Location::new(self.to_url)) - } -} diff --git a/dapps/src/handlers/streaming.rs b/dapps/src/handlers/streaming.rs deleted file mode 100644 index 269e4c5d2a730a57d4a024543857ac23b5b2901f..0000000000000000000000000000000000000000 --- a/dapps/src/handlers/streaming.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Content Stream Response - -use std::io; -use hyper::{self, header, mime, StatusCode}; - -use handlers::{add_security_headers, Reader}; -use Embeddable; - -pub struct StreamingHandler { - initial: Vec, - content: R, - status: StatusCode, - mimetype: mime::Mime, - safe_to_embed_on: Embeddable, -} - -impl StreamingHandler { - pub fn new(content: R, status: StatusCode, mimetype: mime::Mime, safe_to_embed_on: Embeddable) -> Self { - StreamingHandler { - initial: Vec::new(), - content, - status, - mimetype, - safe_to_embed_on, - } - } - - pub fn set_initial_content(&mut self, content: &str) { - self.initial = content.as_bytes().to_vec(); - } - - pub fn into_response(self) -> (Reader, hyper::Response) { - let (reader, body) = Reader::pair(self.content, self.initial); - let mut res = hyper::Response::new() - .with_status(self.status) - .with_header(header::ContentType(self.mimetype)) - .with_body(body); - add_security_headers(&mut res.headers_mut(), self.safe_to_embed_on, false); - - (reader, res) - } -} diff --git a/dapps/src/lib.rs b/dapps/src/lib.rs deleted file mode 100644 index c4e244b251d1eb225cf4167af2c95ad1966c9506..0000000000000000000000000000000000000000 --- a/dapps/src/lib.rs +++ /dev/null @@ -1,340 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Ethcore Webapplications for Parity -#![warn(missing_docs)] - -extern crate base32; -extern crate futures_cpupool; -extern crate itertools; -extern crate linked_hash_map; -extern crate mime_guess; -extern crate parking_lot; -extern crate rand; -extern crate rustc_hex; -extern crate serde; -extern crate serde_json; -extern crate unicase; -extern crate zip; - -extern crate jsonrpc_http_server; - -extern crate ethcore_bytes as bytes; -extern crate ethereum_types; -extern crate fetch; -extern crate node_health; -extern crate parity_dapps_glue as parity_dapps; -extern crate parity_hash_fetch as hash_fetch; -extern crate parity_ui; -extern crate parity_ui_deprecation; -extern crate keccak_hash as hash; -extern crate parity_version; -extern crate registrar; - -#[macro_use] -extern crate futures; -#[macro_use] -extern crate log; -#[macro_use] -extern crate serde_derive; - -#[cfg(test)] -extern crate env_logger; -#[cfg(test)] -extern crate ethcore_devtools as devtools; -#[cfg(test)] -extern crate jsonrpc_core; -#[cfg(test)] -extern crate parity_reactor; - -mod endpoint; -mod apps; -mod page; -mod router; -mod handlers; -mod api; -mod proxypac; -mod web; -#[cfg(test)] -mod tests; - -use std::collections::HashMap; -use std::mem; -use std::path::PathBuf; -use std::sync::Arc; -use futures_cpupool::CpuPool; -use jsonrpc_http_server::{self as http, hyper, Origin}; -use parking_lot::RwLock; - -use fetch::Fetch; -use node_health::NodeHealth; - -pub use registrar::{RegistrarClient, Asynchronous}; -pub use node_health::SyncStatus; - - -/// Validates Web Proxy tokens -pub trait WebProxyTokens: Send + Sync { - /// Should return a domain allowed to be accessed by this token or `None` if the token is not valid - fn domain(&self, token: &str) -> Option; -} - -impl WebProxyTokens for F where F: Fn(String) -> Option + Send + Sync { - fn domain(&self, token: &str) -> Option { self(token.to_owned()) } -} - -/// Current supported endpoints. -#[derive(Default, Clone)] -pub struct Endpoints { - local_endpoints: Arc>>, - endpoints: Arc>, - dapps_path: PathBuf, - embeddable: Option, - pool: Option, -} - -impl Endpoints { - /// Returns a current list of app endpoints. - pub fn list(&self) -> Vec { - self.endpoints.read().iter().filter_map(|(ref k, ref e)| { - e.info().map(|ref info| info.with_id(k)) - }).collect() - } - - /// Check for any changes in the local dapps folder and update. - pub fn refresh_local_dapps(&self) { - let pool = match self.pool.as_ref() { - None => return, - Some(pool) => pool, - }; - let new_local = apps::fs::local_endpoints(&self.dapps_path, self.embeddable.clone(), pool.clone()); - let old_local = mem::replace(&mut *self.local_endpoints.write(), new_local.keys().cloned().collect()); - let (_, to_remove): (_, Vec<_>) = old_local - .into_iter() - .partition(|k| new_local.contains_key(&k.clone())); - - let mut endpoints = self.endpoints.write(); - // remove the dead dapps - for k in to_remove { - endpoints.remove(&k); - } - // new dapps to be added - for (k, v) in new_local { - if !endpoints.contains_key(&k) { - endpoints.insert(k, v); - } - } - } -} - -/// Dapps server as `jsonrpc-http-server` request middleware. -pub struct Middleware { - endpoints: Endpoints, - router: router::Router, -} - -impl Middleware { - /// Get local endpoints handle. - pub fn endpoints(&self) -> &Endpoints { - &self.endpoints - } - - /// Creates new middleware for UI server. - pub fn ui( - pool: CpuPool, - health: NodeHealth, - dapps_domain: &str, - registrar: Arc>, - sync_status: Arc, - fetch: F, - info_page_only: bool, - ) -> Self { - let content_fetcher = Arc::new(apps::fetcher::ContentFetcher::new( - hash_fetch::urlhint::URLHintContract::new(registrar), - sync_status.clone(), - fetch.clone(), - pool.clone(), - ).embeddable_on(None).allow_dapps(false)); - - if info_page_only { - let mut special = HashMap::default(); - special.insert(router::SpecialEndpoint::Home, Some(apps::ui_deprecation(pool.clone()))); - - return Middleware { - endpoints: Default::default(), - router: router::Router::new( - content_fetcher, - None, - special, - None, - dapps_domain.to_owned(), - ), - } - } - - let special = { - let mut special = special_endpoints( - pool.clone(), - health, - content_fetcher.clone(), - ); - special.insert(router::SpecialEndpoint::Home, Some(apps::ui(pool.clone()))); - special - }; - let router = router::Router::new( - content_fetcher, - None, - special, - None, - dapps_domain.to_owned(), - ); - - Middleware { - endpoints: Default::default(), - router: router, - } - } - - /// Creates new Dapps server middleware. - pub fn dapps( - pool: CpuPool, - health: NodeHealth, - ui_address: Option<(String, u16)>, - extra_embed_on: Vec<(String, u16)>, - extra_script_src: Vec<(String, u16)>, - dapps_path: PathBuf, - extra_dapps: Vec, - dapps_domain: &str, - registrar: Arc>, - sync_status: Arc, - web_proxy_tokens: Arc, - fetch: F, - ) -> Self { - let embeddable = as_embeddable(ui_address, extra_embed_on, extra_script_src, dapps_domain); - let content_fetcher = Arc::new(apps::fetcher::ContentFetcher::new( - hash_fetch::urlhint::URLHintContract::new(registrar), - sync_status.clone(), - fetch.clone(), - pool.clone(), - ).embeddable_on(embeddable.clone()).allow_dapps(true)); - let (local_endpoints, endpoints) = apps::all_endpoints( - dapps_path.clone(), - extra_dapps, - dapps_domain, - embeddable.clone(), - web_proxy_tokens, - fetch.clone(), - pool.clone(), - ); - let endpoints = Endpoints { - endpoints: Arc::new(RwLock::new(endpoints)), - dapps_path, - local_endpoints: Arc::new(RwLock::new(local_endpoints)), - embeddable: embeddable.clone(), - pool: Some(pool.clone()), - }; - - let special = { - let mut special = special_endpoints( - pool.clone(), - health, - content_fetcher.clone(), - ); - special.insert( - router::SpecialEndpoint::Home, - Some(apps::ui_redirection(embeddable.clone())), - ); - special - }; - - let router = router::Router::new( - content_fetcher, - Some(endpoints.clone()), - special, - embeddable, - dapps_domain.to_owned(), - ); - - Middleware { - endpoints, - router, - } - } -} - -impl http::RequestMiddleware for Middleware { - fn on_request(&self, req: hyper::Request) -> http::RequestMiddlewareAction { - self.router.on_request(req) - } -} - -fn special_endpoints( - pool: CpuPool, - health: NodeHealth, - content_fetcher: Arc, -) -> HashMap>> { - let mut special = HashMap::new(); - special.insert(router::SpecialEndpoint::Rpc, None); - special.insert(router::SpecialEndpoint::Utils, Some(apps::utils(pool))); - special.insert(router::SpecialEndpoint::Api, Some(api::RestApi::new( - content_fetcher, - health, - ))); - special -} - -fn address(host: &str, port: u16) -> String { - format!("{}:{}", host, port) -} - -fn as_embeddable( - ui_address: Option<(String, u16)>, - extra_embed_on: Vec<(String, u16)>, - extra_script_src: Vec<(String, u16)>, - dapps_domain: &str, -) -> Option { - ui_address.map(|(host, port)| ParentFrameSettings { - host, - port, - extra_embed_on, - extra_script_src, - dapps_domain: dapps_domain.to_owned(), - }) -} - -/// Random filename -fn random_filename() -> String { - use ::rand::Rng; - let mut rng = ::rand::OsRng::new().unwrap(); - rng.gen_ascii_chars().take(12).collect() -} - -type Embeddable = Option; - -/// Parent frame host and port allowed to embed the content. -#[derive(Debug, Clone)] -pub struct ParentFrameSettings { - /// Hostname - pub host: String, - /// Port - pub port: u16, - /// Additional URLs the dapps can be embedded on. - pub extra_embed_on: Vec<(String, u16)>, - /// Additional URLs the dapp scripts can be loaded from. - pub extra_script_src: Vec<(String, u16)>, - /// Dapps Domain (web3.site) - pub dapps_domain: String, -} diff --git a/dapps/src/page/builtin.rs b/dapps/src/page/builtin.rs deleted file mode 100644 index 150cfe8642cd8734bdb8e1fdde419cd2418a168a..0000000000000000000000000000000000000000 --- a/dapps/src/page/builtin.rs +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright 2015-2017 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 . - -use std::io; -use futures::future; -use futures_cpupool::CpuPool; -use hyper::mime::{self, Mime}; -use itertools::Itertools; -use parity_dapps::{WebApp, Info}; - -use endpoint::{Endpoint, EndpointInfo, EndpointPath, Request, Response}; -use page::{handler, PageCache}; -use Embeddable; - -pub struct Dapp { - /// futures cpu pool - pool: CpuPool, - /// Content of the files - app: T, - /// Safe to be loaded in frame by other origin. (use wisely!) - safe_to_embed_on: Embeddable, - info: EndpointInfo, - fallback_to_index_html: bool, -} - -impl Dapp { - /// Creates new `Dapp` for builtin (compile time) Dapp. - pub fn new(pool: CpuPool, app: T) -> Self { - let info = app.info(); - Dapp { - pool, - app, - safe_to_embed_on: None, - info: EndpointInfo::from(info), - fallback_to_index_html: false, - } - } - - /// Creates a new `Dapp` for builtin (compile time) Dapp. - /// Instead of returning 404 this endpoint will always server index.html. - pub fn with_fallback_to_index(pool: CpuPool, app: T) -> Self { - let info = app.info(); - Dapp { - pool, - app, - safe_to_embed_on: None, - info: EndpointInfo::from(info), - fallback_to_index_html: true, - } - } - - /// Creates new `Dapp` which can be safely used in iframe - /// even from different origin. It might be dangerous (clickjacking). - /// Use wisely! - pub fn new_safe_to_embed(pool: CpuPool, app: T, address: Embeddable) -> Self { - let info = app.info(); - Dapp { - pool, - app, - safe_to_embed_on: address, - info: EndpointInfo::from(info), - fallback_to_index_html: false, - } - } - - /// Allow the dapp to use `unsafe-eval` to run JS. - pub fn allow_js_eval(&mut self) { - self.info.allow_js_eval = Some(true); - } -} - -impl Endpoint for Dapp { - fn info(&self) -> Option<&EndpointInfo> { - Some(&self.info) - } - - fn respond(&self, path: EndpointPath, _req: Request) -> Response { - trace!(target: "dapps", "Builtin file path: {:?}", path); - let file_path = if path.has_no_params() { - "index.html".to_owned() - } else { - path.app_params.into_iter().filter(|x| !x.is_empty()).join("/") - }; - trace!(target: "dapps", "Builtin file: {:?}", file_path); - - let file = { - let file = |path| self.app.file(path).map(|file| { - let content_type = match file.content_type.parse() { - Ok(mime) => mime, - Err(_) => { - warn!(target: "dapps", "invalid MIME type: {}", file.content_type); - mime::TEXT_HTML - }, - }; - BuiltinFile { - content_type, - content: io::Cursor::new(file.content), - } - }); - let res = file(&file_path); - if self.fallback_to_index_html { - res.or_else(|| file("index.html")) - } else { - res - } - }; - - let (reader, response) = handler::PageHandler { - file, - cache: PageCache::Disabled, - safe_to_embed_on: self.safe_to_embed_on.clone(), - allow_js_eval: self.info.allow_js_eval.clone().unwrap_or(false), - }.into_response(); - - self.pool.spawn(reader).forget(); - - Box::new(future::ok(response)) - } -} - -impl From for EndpointInfo { - fn from(info: Info) -> Self { - EndpointInfo { - id: None, - name: info.name.into(), - description: info.description.into(), - author: info.author.into(), - icon_url: info.icon_url.into(), - local_url: None, - version: info.version.into(), - allow_js_eval: None, - } - } -} - - -struct BuiltinFile { - content_type: Mime, - content: io::Cursor<&'static [u8]>, -} - -impl handler::DappFile for BuiltinFile { - type Reader = io::Cursor<&'static [u8]>; - - fn content_type(&self) -> &Mime { - &self.content_type - } - - fn into_reader(self) -> Self::Reader { - self.content - } -} diff --git a/dapps/src/page/handler.rs b/dapps/src/page/handler.rs deleted file mode 100644 index 687c8e1e52cf7da5f77b37f7bbda6a37b23b3cc4..0000000000000000000000000000000000000000 --- a/dapps/src/page/handler.rs +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2015-2017 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 . - -use std::io; -use std::time::{Duration, SystemTime}; -use hyper::{self, header, StatusCode}; -use hyper::mime::{Mime}; - -use handlers::{Reader, ContentHandler, add_security_headers}; -use {Embeddable}; - -/// Represents a file that can be sent to client. -/// Implementation should keep track of bytes already sent internally. -pub trait DappFile { - /// A reader type returned by this file. - type Reader: io::Read; - - /// Returns a content-type of this file. - fn content_type(&self) -> &Mime; - - /// Convert this file into io::Read instance. - fn into_reader(self) -> Self::Reader where Self: Sized; -} - -/// Defines what cache headers should be appended to returned resources. -#[derive(Debug, Copy, Clone, PartialEq)] -pub enum PageCache { - Enabled, - Disabled, -} - -impl Default for PageCache { - fn default() -> Self { - PageCache::Disabled - } -} - -/// A handler for a single webapp. -/// Resolves correct paths and serves as a plumbing code between -/// hyper server and dapp. -pub struct PageHandler { - /// File currently being served - pub file: Option, - /// Flag indicating if the file can be safely embeded (put in iframe). - pub safe_to_embed_on: Embeddable, - /// Cache settings for this page. - pub cache: PageCache, - /// Allow JS unsafe-eval. - pub allow_js_eval: bool, -} - -impl PageHandler { - pub fn into_response(self) -> (Option>, hyper::Response) { - let file = match self.file { - None => return (None, ContentHandler::error( - StatusCode::NotFound, - "File not found", - "Requested file has not been found.", - None, - self.safe_to_embed_on, - ).into()), - Some(file) => file, - }; - - let mut res = hyper::Response::new() - .with_status(StatusCode::Ok); - - // headers - { - let mut headers = res.headers_mut(); - - if let PageCache::Enabled = self.cache { - let validity_secs = 365u32 * 24 * 3600; - let validity = Duration::from_secs(validity_secs as u64); - headers.set(header::CacheControl(vec![ - header::CacheDirective::Public, - header::CacheDirective::MaxAge(validity_secs), - ])); - headers.set(header::Expires(header::HttpDate::from(SystemTime::now() + validity))); - } - - headers.set(header::ContentType(file.content_type().to_owned())); - - add_security_headers(&mut headers, self.safe_to_embed_on, self.allow_js_eval); - } - - let (reader, body) = Reader::pair(file.into_reader(), Vec::new()); - res.set_body(body); - (Some(reader), res) - } -} diff --git a/dapps/src/page/local.rs b/dapps/src/page/local.rs deleted file mode 100644 index a1746efcd2172f5f82ee896a8bccffc2d2ef99d3..0000000000000000000000000000000000000000 --- a/dapps/src/page/local.rs +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2015-2017 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 . - -use mime_guess; -use std::{fs, fmt}; -use std::path::{Path, PathBuf}; -use futures::{future}; -use futures_cpupool::CpuPool; -use page::handler::{self, PageCache}; -use endpoint::{Endpoint, EndpointInfo, EndpointPath, Request, Response}; -use hyper::mime::Mime; -use Embeddable; - -#[derive(Clone)] -pub struct Dapp { - pool: CpuPool, - path: PathBuf, - mime: Option, - info: Option, - cache: PageCache, - embeddable_on: Embeddable, -} - -impl fmt::Debug for Dapp { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("Dapp") - .field("path", &self.path) - .field("mime", &self.mime) - .field("info", &self.info) - .field("cache", &self.cache) - .field("embeddable_on", &self.embeddable_on) - .finish() - } -} - -impl Dapp { - pub fn new(pool: CpuPool, path: PathBuf, info: EndpointInfo, cache: PageCache, embeddable_on: Embeddable) -> Self { - Dapp { - pool, - path, - mime: None, - info: Some(info), - cache, - embeddable_on, - } - } - - pub fn single_file(pool: CpuPool, path: PathBuf, mime: Mime, cache: PageCache) -> Self { - Dapp { - pool, - path, - mime: Some(mime), - info: None, - cache, - embeddable_on: None, - } - } - - pub fn path(&self) -> PathBuf { - self.path.clone() - } - - fn get_file(&self, path: &EndpointPath) -> Option { - if let Some(ref mime) = self.mime { - return LocalFile::from_path(&self.path, mime.to_owned()); - } - - let mut file_path = self.path.to_owned(); - - if path.has_no_params() { - file_path.push("index.html"); - } else { - for part in &path.app_params { - file_path.push(part); - } - } - - let mime = mime_guess::guess_mime_type(&file_path); - LocalFile::from_path(&file_path, mime) - } - - - pub fn to_response(&self, path: &EndpointPath) -> Response { - let (reader, response) = handler::PageHandler { - file: self.get_file(path), - cache: self.cache, - safe_to_embed_on: self.embeddable_on.clone(), - allow_js_eval: self.info.as_ref().and_then(|x| x.allow_js_eval).unwrap_or(false), - }.into_response(); - - self.pool.spawn(reader).forget(); - - Box::new(future::ok(response)) - } -} - -impl Endpoint for Dapp { - fn info(&self) -> Option<&EndpointInfo> { - self.info.as_ref() - } - - fn respond(&self, path: EndpointPath, _req: Request) -> Response { - self.to_response(&path) - } -} - -struct LocalFile { - content_type: Mime, - file: fs::File, -} - -impl LocalFile { - fn from_path>(path: P, content_type: Mime) -> Option { - trace!(target: "dapps", "Local file: {:?}", path.as_ref()); - // Check if file exists - fs::File::open(&path).ok().map(|file| { - LocalFile { - content_type, - file, - } - }) - } -} - -impl handler::DappFile for LocalFile { - type Reader = fs::File; - - fn content_type(&self) -> &Mime { - &self.content_type - } - - fn into_reader(self) -> Self::Reader { - self.file - } -} diff --git a/dapps/src/page/mod.rs b/dapps/src/page/mod.rs deleted file mode 100644 index 420707bfe1955513d59dd8299c72d3638b1345c4..0000000000000000000000000000000000000000 --- a/dapps/src/page/mod.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015-2017 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 . - - -pub mod builtin; -pub mod local; -mod handler; - -pub use self::handler::PageCache; - diff --git a/dapps/src/proxypac.rs b/dapps/src/proxypac.rs deleted file mode 100644 index 85ac11423a11ed4525ab80f2e19af88c184c8da9..0000000000000000000000000000000000000000 --- a/dapps/src/proxypac.rs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Serving ProxyPac file - -use apps::HOME_PAGE; -use endpoint::{Endpoint, Request, Response, EndpointPath}; -use futures::future; -use handlers::ContentHandler; -use hyper::mime; -use {address, Embeddable}; - -pub struct ProxyPac { - embeddable: Embeddable, - dapps_domain: String, -} - -impl ProxyPac { - pub fn boxed(embeddable: Embeddable, dapps_domain: String) -> Box { - Box::new(ProxyPac { embeddable, dapps_domain }) - } -} - -impl Endpoint for ProxyPac { - fn respond(&self, path: EndpointPath, _req: Request) -> Response { - let ui = self.embeddable - .as_ref() - .map(|ref parent| address(&parent.host, parent.port)) - .unwrap_or_else(|| format!("{}:{}", path.host, path.port)); - - let content = format!( -r#" -function FindProxyForURL(url, host) {{ - if (shExpMatch(host, "{0}.{1}")) - {{ - return "PROXY {4}"; - }} - - if (shExpMatch(host, "*.{1}")) - {{ - return "PROXY {2}:{3}"; - }} - - return "DIRECT"; -}} -"#, - HOME_PAGE, self.dapps_domain, path.host, path.port, ui); - - Box::new(future::ok( - ContentHandler::ok(content, mime::TEXT_JAVASCRIPT).into() - )) - } -} - - diff --git a/dapps/src/router.rs b/dapps/src/router.rs deleted file mode 100644 index d5f46470493a232986e43fdeff49aee9e5659d7c..0000000000000000000000000000000000000000 --- a/dapps/src/router.rs +++ /dev/null @@ -1,417 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Router implementation -//! Dispatch requests to proper application. - -use std::sync::Arc; -use std::collections::HashMap; - -use futures::future; -use hyper::{self, header, Uri}; -use jsonrpc_http_server as http; - -use apps; -use apps::fetcher::Fetcher; -use endpoint::{self, Endpoint, EndpointPath}; -use Endpoints; -use handlers; -use Embeddable; - -/// Special endpoints are accessible on every domain (every dapp) -#[derive(Debug, PartialEq, Hash, Eq)] -pub enum SpecialEndpoint { - Rpc, - Api, - Utils, - Home, - None, -} - -enum Response { - Some(endpoint::Response), - None(hyper::Request), -} - -/// An endpoint router. -/// Dispatches the request to particular Endpoint by requested uri/path. -pub struct Router { - endpoints: Option, - fetch: Arc, - special: HashMap>>, - embeddable_on: Embeddable, - dapps_domain: String, -} - -impl Router { - fn resolve_request(&self, req: hyper::Request, refresh_dapps: bool) -> (bool, Response) { - // Choose proper handler depending on path / domain - let endpoint = extract_endpoint(req.uri(), req.headers().get(), &self.dapps_domain); - let referer = extract_referer_endpoint(&req, &self.dapps_domain); - let is_utils = endpoint.1 == SpecialEndpoint::Utils; - let is_get_request = *req.method() == hyper::Method::Get; - let is_head_request = *req.method() == hyper::Method::Head; - let has_dapp = |dapp: &str| self.endpoints - .as_ref() - .map_or(false, |endpoints| endpoints.endpoints.read().contains_key(dapp)); - - trace!(target: "dapps", "Routing request to {:?}. Details: {:?}", req.uri(), req); - debug!(target: "dapps", "Handling endpoint request: {:?}, referer: {:?}", endpoint, referer); - - (is_utils, match (endpoint.0, endpoint.1, referer) { - // Handle invalid web requests that we can recover from - (ref path, SpecialEndpoint::None, Some(ref referer)) - if referer.app_id == apps::WEB_PATH - && has_dapp(apps::WEB_PATH) - && !is_web_endpoint(path) - => - { - let token = referer.app_params.get(0).map(String::as_str).unwrap_or(""); - let requested = req.uri().path(); - let query = req.uri().query().map_or_else(String::new, |query| format!("?{}", query)); - let redirect_url = format!("/{}/{}{}{}", apps::WEB_PATH, token, requested, query); - trace!(target: "dapps", "Redirecting to correct web request: {:?}", redirect_url); - Response::Some(Box::new(future::ok( - handlers::Redirection::new(redirect_url).into() - ))) - }, - // First check special endpoints - (ref path, ref endpoint, _) if self.special.contains_key(endpoint) => { - trace!(target: "dapps", "Resolving to special endpoint."); - let special = self.special.get(endpoint).expect("special known to contain key; qed"); - match *special { - Some(ref special) => Response::Some(special.respond(path.clone().unwrap_or_default(), req)), - None => Response::None(req), - } - }, - // Then delegate to dapp - (Some(ref path), _, _) if has_dapp(&path.app_id) => { - trace!(target: "dapps", "Resolving to local/builtin dapp."); - Response::Some(self.endpoints - .as_ref() - .expect("endpoints known to be set; qed") - .endpoints - .read() - .get(&path.app_id) - .expect("endpoints known to contain key; qed") - .respond(path.clone(), req)) - }, - // Try to resolve and fetch the dapp - (Some(ref path), _, _) if self.fetch.contains(&path.app_id) => { - trace!(target: "dapps", "Resolving to fetchable content."); - Response::Some(self.fetch.respond(path.clone(), req)) - }, - // 404 for non-existent content (only if serving endpoints and not homepage) - (Some(ref path), _, _) - if (is_get_request || is_head_request) - && self.endpoints.is_some() - && path.app_id != apps::HOME_PAGE - => - { - trace!(target: "dapps", "Resolving to 404."); - if refresh_dapps { - debug!(target: "dapps", "Refreshing dapps and re-trying."); - self.endpoints.as_ref().map(|endpoints| endpoints.refresh_local_dapps()); - return self.resolve_request(req, false); - } else { - Response::Some(Box::new(future::ok(handlers::ContentHandler::error( - hyper::StatusCode::NotFound, - "404 Not Found", - "Requested content was not found.", - None, - self.embeddable_on.clone(), - ).into()))) - } - }, - // Any other GET|HEAD requests to home page. - _ if (is_get_request || is_head_request) && self.special.contains_key(&SpecialEndpoint::Home) => { - trace!(target: "dapps", "Resolving to home page."); - let special = self.special.get(&SpecialEndpoint::Home).expect("special known to contain key; qed"); - match *special { - Some(ref special) => { - let mut endpoint = EndpointPath::default(); - endpoint.app_params = req.uri().path().split('/').map(str::to_owned).collect(); - Response::Some(special.respond(endpoint, req)) - }, - None => Response::None(req), - } - }, - // RPC by default - _ if self.special.contains_key(&SpecialEndpoint::Rpc) => { - trace!(target: "dapps", "Resolving to RPC call."); - Response::None(req) - }, - // 404 otherwise - _ => { - Response::Some(Box::new(future::ok(handlers::ContentHandler::error( - hyper::StatusCode::NotFound, - "404 Not Found", - "Requested content was not found.", - None, - self.embeddable_on.clone(), - ).into()))) - }, - }) - } -} - -impl http::RequestMiddleware for Router { - fn on_request(&self, req: hyper::Request) -> http::RequestMiddlewareAction { - let is_origin_set = req.headers().get::().is_some(); - let (is_utils, response) = self.resolve_request(req, self.endpoints.is_some()); - match response { - Response::Some(response) => http::RequestMiddlewareAction::Respond { - should_validate_hosts: !is_utils, - response, - }, - Response::None(request) => http::RequestMiddlewareAction::Proceed { - should_continue_on_invalid_cors: !is_origin_set, - request, - }, - } - } -} - -impl Router { - pub fn new( - content_fetcher: Arc, - endpoints: Option, - special: HashMap>>, - embeddable_on: Embeddable, - dapps_domain: String, - ) -> Self { - Router { - endpoints: endpoints, - fetch: content_fetcher, - special: special, - embeddable_on: embeddable_on, - dapps_domain: format!(".{}", dapps_domain), - } - } -} - -fn is_web_endpoint(path: &Option) -> bool { - match *path { - Some(ref path) if path.app_id == apps::WEB_PATH => true, - _ => false, - } -} - -fn extract_referer_endpoint(req: &hyper::Request, dapps_domain: &str) -> Option { - let referer = req.headers().get::(); - - let url = referer.and_then(|referer| referer.parse().ok()); - url.and_then(|url| { - extract_url_referer_endpoint(&url, dapps_domain).or_else(|| { - extract_endpoint(&url, None, dapps_domain).0 - }) - }) -} - -fn extract_url_referer_endpoint(url: &Uri, dapps_domain: &str) -> Option { - let query = url.query(); - match query { - Some(query) if query.starts_with(apps::URL_REFERER) => { - let scheme = url.scheme().unwrap_or("http"); - let host = url.host().unwrap_or("unknown"); - let port = default_port(url, None); - let referer_url = format!("{}://{}:{}/{}", scheme, host, port, &query[apps::URL_REFERER.len()..]); - debug!(target: "dapps", "Recovering referer from query parameter: {}", referer_url); - - if let Some(referer_url) = referer_url.parse().ok() { - extract_endpoint(&referer_url, None, dapps_domain).0 - } else { - None - } - }, - _ => None, - } -} - -fn extract_endpoint(url: &Uri, extra_host: Option<&header::Host>, dapps_domain: &str) -> (Option, SpecialEndpoint) { - fn special_endpoint(path: &[&str]) -> SpecialEndpoint { - if path.len() <= 1 { - return SpecialEndpoint::None; - } - - match path[0].as_ref() { - apps::RPC_PATH => SpecialEndpoint::Rpc, - apps::API_PATH => SpecialEndpoint::Api, - apps::UTILS_PATH => SpecialEndpoint::Utils, - apps::HOME_PAGE => SpecialEndpoint::Home, - _ => SpecialEndpoint::None, - } - } - - let port = default_port(url, extra_host.as_ref().and_then(|h| h.port())); - let host = url.host().or_else(|| extra_host.as_ref().map(|h| h.hostname())); - let query = url.query().map(str::to_owned); - let mut path_segments = url.path().split('/').skip(1).collect::>(); - trace!( - target: "dapps", - "Extracting endpoint from: {:?} (dapps: {}). Got host {:?}:{} with path {:?}", - url, dapps_domain, host, port, path_segments - ); - match host { - Some(host) if host.ends_with(dapps_domain) => { - let id = &host[0..(host.len() - dapps_domain.len())]; - let special = special_endpoint(&path_segments); - - // remove special endpoint id from params - if special != SpecialEndpoint::None { - path_segments.remove(0); - } - - let (app_id, app_params) = if let Some(split) = id.rfind('.') { - let (params, id) = id.split_at(split); - path_segments.insert(0, params); - (id[1..].to_owned(), path_segments) - } else { - (id.to_owned(), path_segments) - }; - - (Some(EndpointPath { - app_id, - app_params: app_params.into_iter().map(Into::into).collect(), - query, - host: host.to_owned(), - port, - using_dapps_domains: true, - }), special) - }, - Some(host) if path_segments.len() > 1 => { - let special = special_endpoint(&path_segments); - let id = path_segments.remove(0); - (Some(EndpointPath { - app_id: id.to_owned(), - app_params: path_segments.into_iter().map(Into::into).collect(), - query, - host: host.to_owned(), - port, - using_dapps_domains: false, - }), special) - }, - _ => (None, special_endpoint(&path_segments)), - } -} - -fn default_port(url: &Uri, extra_port: Option) -> u16 { - let scheme = url.scheme().unwrap_or("http"); - url.port().or(extra_port).unwrap_or_else(|| match scheme { - "http" => 80, - "https" => 443, - _ => 80, - }) -} - -#[cfg(test)] -mod tests { - use super::{SpecialEndpoint, EndpointPath, extract_endpoint}; - - #[test] - fn should_extract_endpoint() { - let dapps_domain = ".web3.site"; - - // With path prefix - assert_eq!( - extract_endpoint(&"http://localhost:8080/status/index.html?q=1".parse().unwrap(), None, dapps_domain), - (Some(EndpointPath { - app_id: "status".to_owned(), - app_params: vec!["index.html".to_owned()], - query: Some("q=1".into()), - host: "localhost".to_owned(), - port: 8080, - using_dapps_domains: false, - }), SpecialEndpoint::None) - ); - - // With path prefix - assert_eq!( - extract_endpoint(&"http://localhost:8080/rpc/".parse().unwrap(), None, dapps_domain), - (Some(EndpointPath { - app_id: "rpc".to_owned(), - app_params: vec!["".to_owned()], - query: None, - host: "localhost".to_owned(), - port: 8080, - using_dapps_domains: false, - }), SpecialEndpoint::Rpc) - ); - - assert_eq!( - extract_endpoint(&"http://my.status.web3.site/parity-utils/inject.js".parse().unwrap(), None, dapps_domain), - (Some(EndpointPath { - app_id: "status".to_owned(), - app_params: vec!["my".into(), "inject.js".into()], - query: None, - host: "my.status.web3.site".to_owned(), - port: 80, - using_dapps_domains: true, - }), SpecialEndpoint::Utils) - ); - - assert_eq!( - extract_endpoint(&"http://my.status.web3.site/inject.js".parse().unwrap(), None, dapps_domain), - (Some(EndpointPath { - app_id: "status".to_owned(), - app_params: vec!["my".into(), "inject.js".into()], - query: None, - host: "my.status.web3.site".to_owned(), - port: 80, - using_dapps_domains: true, - }), SpecialEndpoint::None) - ); - - // By Subdomain - assert_eq!( - extract_endpoint(&"http://status.web3.site/test.html".parse().unwrap(), None, dapps_domain), - (Some(EndpointPath { - app_id: "status".to_owned(), - app_params: vec!["test.html".to_owned()], - query: None, - host: "status.web3.site".to_owned(), - port: 80, - using_dapps_domains: true, - }), SpecialEndpoint::None) - ); - - // RPC by subdomain - assert_eq!( - extract_endpoint(&"http://my.status.web3.site/rpc/".parse().unwrap(), None, dapps_domain), - (Some(EndpointPath { - app_id: "status".to_owned(), - app_params: vec!["my".into(), "".into()], - query: None, - host: "my.status.web3.site".to_owned(), - port: 80, - using_dapps_domains: true, - }), SpecialEndpoint::Rpc) - ); - - // API by subdomain - assert_eq!( - extract_endpoint(&"http://my.status.web3.site/api/".parse().unwrap(), None, dapps_domain), - (Some(EndpointPath { - app_id: "status".to_owned(), - app_params: vec!["my".into(), "".into()], - query: None, - host: "my.status.web3.site".to_owned(), - port: 80, - using_dapps_domains: true, - }), SpecialEndpoint::Api) - ); - } -} diff --git a/dapps/src/tests/api.rs b/dapps/src/tests/api.rs deleted file mode 100644 index 3ae3f7cbbf88da4febf11e689c13f2ecb845d6cc..0000000000000000000000000000000000000000 --- a/dapps/src/tests/api.rs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2015-2017 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 . - -use tests::helpers::{serve, serve_with_registrar, request, assert_security_headers}; - -#[test] -fn should_return_error() { - // given - let server = serve(); - - // when - let response = request(server, - "\ - GET /api/empty HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 404 Not Found"); - response.assert_header("Content-Type", "application/json"); - assert_eq!(response.body, format!("58\n{}\n0\n\n", r#"{"code":"404","title":"Not Found","detail":"Resource you requested has not been found."}"#)); - assert_security_headers(&response.headers); -} - -#[test] -fn should_handle_ping() { - // given - let server = serve(); - - // when - let response = request(server, - "\ - POST /api/ping HTTP/1.1\r\n\ - Host: home.parity\r\n\ - Content-Type: application/json\r\n\ - Connection: close\r\n\ - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - response.assert_header("Content-Type", "application/json"); - assert_eq!(response.body, "0\n\n".to_owned()); - assert_security_headers(&response.headers); -} - - -#[test] -fn should_try_to_resolve_dapp() { - // given - let (server, registrar) = serve_with_registrar(); - - // when - let response = request(server, - "\ - GET /api/content/1472a9e190620cdf6b31f383373e45efcfe869a820c91f9ccd7eb9fb45e4985d HTTP/1.1\r\n\ - Host: home.parity\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 404 Not Found"); - assert_eq!(registrar.calls.lock().len(), 2); - assert_security_headers(&response.headers); -} diff --git a/dapps/src/tests/fetch.rs b/dapps/src/tests/fetch.rs deleted file mode 100644 index 59eeaf8d662e6fcef7df2a3d3197845609dac380..0000000000000000000000000000000000000000 --- a/dapps/src/tests/fetch.rs +++ /dev/null @@ -1,545 +0,0 @@ -// Copyright 2015-2017 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 . - -use devtools::http_client; -use rustc_hex::FromHex; -use tests::helpers::{ - serve_with_registrar, serve_with_registrar_and_sync, serve_with_fetch, - serve_with_registrar_and_fetch, - request, assert_security_headers_for_embed, -}; - -#[test] -fn should_resolve_dapp() { - // given - let (server, registrar) = serve_with_registrar(); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: 1472a9e190620cdf6b31f383373e45efcfe869a820c91f9ccd7eb9fb45e4985d.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 404 Not Found"); - assert_eq!(registrar.calls.lock().len(), 4); - assert_security_headers_for_embed(&response.headers); -} - -#[test] -fn should_return_503_when_syncing_but_should_make_the_calls() { - // given - let (server, registrar) = serve_with_registrar_and_sync(); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: 1472a9e190620cdf6b31f383373e45efcfe869a820c91f9ccd7eb9fb45e4985d.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 503 Service Unavailable"); - assert_eq!(registrar.calls.lock().len(), 2); - assert_security_headers_for_embed(&response.headers); -} - -const GAVCOIN_DAPP: &'static str = "00000000000000000000000000000000000000000000000000000000000000609faf32e1e3845e237cc6efd27187cee13b3b99db000000000000000000000000000000000000000000000000d8bd350823e28ff75e74a34215faefdc8a52fd8e00000000000000000000000000000000000000000000000000000000000000116761766f66796f726b2f676176636f696e000000000000000000000000000000"; -const GAVCOIN_ICON: &'static str = "00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d8bd350823e28ff75e74a34215faefdc8a52fd8e000000000000000000000000000000000000000000000000000000000000007768747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f657468636f72652f646170702d6173736574732f623838653938336162616131613661363334356238643934343863313562313137646462353430652f746f6b656e732f676176636f696e2d36347836342e706e67000000000000000000"; - -#[test] -fn should_return_502_on_hash_mismatch() { - // given - let (server, fetch, registrar) = serve_with_registrar_and_fetch(); - let gavcoin = GAVCOIN_DAPP.from_hex().unwrap(); - registrar.set_result( - "94f093625c06887d94d9fee0d5f9cc4aaa46f33d24d1c7e4b5237e7c37d547dd".parse().unwrap(), - Ok(gavcoin.clone()) - ); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: 94f093625c06887d94d9fee0d5f9cc4aaa46f33d24d1c7e4b5237e7c37d547dd.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - assert_eq!(registrar.calls.lock().len(), 4); - - fetch.assert_requested("https://codeload.github.com/gavofyork/gavcoin/zip/9faf32e1e3845e237cc6efd27187cee13b3b99db"); - fetch.assert_no_more_requests(); - - response.assert_status("HTTP/1.1 502 Bad Gateway"); - assert!(response.body.contains("HashMismatch"), "Expected hash mismatch response, got: {:?}", response.body); - assert_security_headers_for_embed(&response.headers); -} - -#[test] -fn should_return_error_for_invalid_dapp_zip() { - // given - let (server, fetch, registrar) = serve_with_registrar_and_fetch(); - let gavcoin = GAVCOIN_DAPP.from_hex().unwrap(); - registrar.set_result( - "2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e".parse().unwrap(), - Ok(gavcoin.clone()) - ); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: 2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - assert_eq!(registrar.calls.lock().len(), 4); - - fetch.assert_requested("https://codeload.github.com/gavofyork/gavcoin/zip/9faf32e1e3845e237cc6efd27187cee13b3b99db"); - fetch.assert_no_more_requests(); - - response.assert_status("HTTP/1.1 502 Bad Gateway"); - assert!(response.body.contains("InvalidArchive"), "Expected invalid zip response, got: {:?}", response.body); - assert_security_headers_for_embed(&response.headers); -} - -#[test] -fn should_return_fetched_dapp_content() { - // given - let (server, fetch, registrar) = serve_with_registrar_and_fetch(); - let gavcoin = GAVCOIN_DAPP.from_hex().unwrap(); - registrar.set_result( - "9c94e154dab8acf859b30ee80fc828fb1d38359d938751b65db71d460588d82a".parse().unwrap(), - Ok(gavcoin.clone()) - ); - fetch.set_response(include_bytes!("../../res/gavcoin.zip")); - - // when - let response1 = http_client::request(server.addr(), - "\ - GET /index.html HTTP/1.1\r\n\ - Host: 9c94e154dab8acf859b30ee80fc828fb1d38359d938751b65db71d460588d82a.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - let response2 = http_client::request(server.addr(), - "\ - GET /manifest.json HTTP/1.1\r\n\ - Host: 9c94e154dab8acf859b30ee80fc828fb1d38359d938751b65db71d460588d82a.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - assert_eq!(registrar.calls.lock().len(), 4); - - fetch.assert_requested("https://codeload.github.com/gavofyork/gavcoin/zip/9faf32e1e3845e237cc6efd27187cee13b3b99db"); - fetch.assert_no_more_requests(); - - response1.assert_status("HTTP/1.1 200 OK"); - assert_security_headers_for_embed(&response1.headers); - assert!( - response1.body.contains(r#"18 -

Hello Gavcoin!

- -0 - -"#), - "Expected Gavcoin body: {}", - response1.body - ); - - response2.assert_status("HTTP/1.1 200 OK"); - assert_security_headers_for_embed(&response2.headers); - assert_eq!( - response2.body, - r#"EA -{ - "id": "9c94e154dab8acf859b30ee80fc828fb1d38359d938751b65db71d460588d82a", - "name": "Gavcoin", - "description": "Gavcoin", - "version": "1.0.0", - "author": "", - "iconUrl": "icon.png", - "localUrl": null, - "allowJsEval": false -} -0 - -"# - ); -} - -#[test] -fn should_return_fetched_content() { - // given - let (server, fetch, registrar) = serve_with_registrar_and_fetch(); - let gavcoin = GAVCOIN_ICON.from_hex().unwrap(); - registrar.set_result( - "2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e".parse().unwrap(), - Ok(gavcoin.clone()) - ); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: 2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - assert_eq!(registrar.calls.lock().len(), 4); - - fetch.assert_requested("https://raw.githubusercontent.com/ethcore/dapp-assets/b88e983abaa1a6a6345b8d9448c15b117ddb540e/tokens/gavcoin-64x64.png"); - fetch.assert_no_more_requests(); - - response.assert_status("HTTP/1.1 200 OK"); - response.assert_security_headers_present(None); -} - -#[test] -fn should_cache_content() { - // given - let (server, fetch, registrar) = serve_with_registrar_and_fetch(); - let gavcoin = GAVCOIN_ICON.from_hex().unwrap(); - registrar.set_result( - "2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e".parse().unwrap(), - Ok(gavcoin.clone()) - ); - let request_str = "\ - GET / HTTP/1.1\r\n\ - Host: 2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - "; - - let response = http_client::request(server.addr(), request_str); - fetch.assert_requested("https://raw.githubusercontent.com/ethcore/dapp-assets/b88e983abaa1a6a6345b8d9448c15b117ddb540e/tokens/gavcoin-64x64.png"); - fetch.assert_no_more_requests(); - response.assert_status("HTTP/1.1 200 OK"); - - // when - let response = http_client::request(server.addr(), request_str); - - // then - fetch.assert_no_more_requests(); - response.assert_status("HTTP/1.1 200 OK"); -} - -#[test] -fn should_not_request_content_twice() { - use std::thread; - - // given - let (server, fetch, registrar) = serve_with_registrar_and_fetch(); - let gavcoin = GAVCOIN_ICON.from_hex().unwrap(); - registrar.set_result( - "2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e".parse().unwrap(), - Ok(gavcoin.clone()) - ); - let request_str = "\ - GET / HTTP/1.1\r\n\ - Host: 2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - "; - let fire_request = || { - let addr = server.addr().to_owned(); - let req = request_str.to_owned(); - thread::spawn(move || { - http_client::request(&addr, &req) - }) - }; - let control = fetch.manual(); - - // when - - // Fire two requests at the same time - let r1 = fire_request(); - let r2 = fire_request(); - - // wait for single request in fetch, the second one should go into waiting state. - control.wait_for_requests(1); - control.respond(); - - let response1 = r1.join().unwrap(); - let response2 = r2.join().unwrap(); - - // then - fetch.assert_requested("https://raw.githubusercontent.com/ethcore/dapp-assets/b88e983abaa1a6a6345b8d9448c15b117ddb540e/tokens/gavcoin-64x64.png"); - fetch.assert_no_more_requests(); - response1.assert_status("HTTP/1.1 200 OK"); - response2.assert_status("HTTP/1.1 200 OK"); -} - -#[test] -fn should_encode_and_decode_base32() { - use base32; - - let encoded = base32::encode(base32::Alphabet::Crockford, "token+https://parity.io".as_bytes()); - assert_eq!("EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY", &encoded); - - let data = base32::decode(base32::Alphabet::Crockford, "EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY").unwrap(); - assert_eq!("token+https://parity.io", &String::from_utf8(data).unwrap()); -} - -#[test] -fn should_stream_web_content() { - // given - let (server, fetch) = serve_with_fetch("token", "https://parity.io"); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY.web.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - assert_security_headers_for_embed(&response.headers); - - fetch.assert_requested("https://parity.io/"); - fetch.assert_no_more_requests(); -} - -#[test] -fn should_support_base32_encoded_web_urls() { - // given - let (server, fetch) = serve_with_fetch("token", "https://parity.io"); - - // when - let response = request(server, - "\ - GET /styles.css?test=123 HTTP/1.1\r\n\ - Host: EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY.web.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - assert_security_headers_for_embed(&response.headers); - - fetch.assert_requested("https://parity.io/styles.css?test=123"); - fetch.assert_no_more_requests(); -} - -#[test] -fn should_correctly_handle_long_label_when_splitted() { - // given - let (server, fetch) = serve_with_fetch("xolrg9fePeQyKLnL", "https://contribution.melonport.com"); - - // when - let response = request(server, - "\ - GET /styles.css?test=123 HTTP/1.1\r\n\ - Host: f1qprwk775k6am35a5wmpk3e9gnpgx3me1sk.mbsfcdqpwx3jd5h7ax39dxq2wvb5dhqpww3fe9t2wrvfdm.web.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - assert_security_headers_for_embed(&response.headers); - - fetch.assert_requested("https://contribution.melonport.com/styles.css?test=123"); - fetch.assert_no_more_requests(); -} - - -#[test] -fn should_support_base32_encoded_web_urls_as_path() { - // given - let (server, fetch) = serve_with_fetch("token", "https://parity.io"); - - // when - let response = request(server, - "\ - GET /web/EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY/styles.css?test=123 HTTP/1.1\r\n\ - Host: localhost:8080\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - assert_security_headers_for_embed(&response.headers); - - fetch.assert_requested("https://parity.io/styles.css?test=123"); - fetch.assert_no_more_requests(); -} - -#[test] -fn should_return_error_on_non_whitelisted_domain() { - // given - let (server, fetch) = serve_with_fetch("token", "https://ethcore.io"); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY.web.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 400 Bad Request"); - assert_security_headers_for_embed(&response.headers); - - fetch.assert_no_more_requests(); -} - -#[test] -fn should_return_error_on_invalid_token() { - // given - let (server, fetch) = serve_with_fetch("test", "https://parity.io"); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY.web.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 400 Bad Request"); - assert_security_headers_for_embed(&response.headers); - - fetch.assert_no_more_requests(); -} - -#[test] -fn should_return_error_on_invalid_protocol() { - // given - let (server, fetch) = serve_with_fetch("token", "ftp://parity.io"); - - // when - let response = request(server, - "\ - GET /web/token/ftp/parity.io/ HTTP/1.1\r\n\ - Host: localhost:8080\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 400 Bad Request"); - assert_security_headers_for_embed(&response.headers); - - fetch.assert_no_more_requests(); -} - -#[test] -fn should_disallow_non_get_requests() { - // given - let (server, fetch) = serve_with_fetch("token", "https://parity.io"); - - // when - let response = request(server, - "\ - POST / HTTP/1.1\r\n\ - Host: EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY.web.web3.site\r\n\ - Content-Type: application/json\r\n\ - Connection: close\r\n\ - \r\n\ - 123\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 405 Method Not Allowed"); - assert_security_headers_for_embed(&response.headers); - - fetch.assert_no_more_requests(); -} - -#[test] -fn should_fix_absolute_requests_based_on_referer() { - // given - let (server, fetch) = serve_with_fetch("token", "https://parity.io"); - - // when - let response = request(server, - "\ - GET /styles.css HTTP/1.1\r\n\ - Host: localhost:8080\r\n\ - Connection: close\r\n\ - Referer: http://localhost:8080/web/EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY/\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 302 Found"); - response.assert_header("Location", "/web/EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY/styles.css"); - - fetch.assert_no_more_requests(); -} - -#[test] -fn should_fix_absolute_requests_based_on_referer_in_url() { - // given - let (server, fetch) = serve_with_fetch("token", "https://parity.io"); - - // when - let response = request(server, - "\ - GET /styles.css HTTP/1.1\r\n\ - Host: localhost:8080\r\n\ - Connection: close\r\n\ - Referer: http://localhost:8080/?__referer=web/EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY/\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 302 Found"); - response.assert_header("Location", "/web/EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY/styles.css"); - - fetch.assert_no_more_requests(); -} diff --git a/dapps/src/tests/helpers/fetch.rs b/dapps/src/tests/helpers/fetch.rs deleted file mode 100644 index 51c98db531d31a863ac66d6297bd2b1fe50ef621..0000000000000000000000000000000000000000 --- a/dapps/src/tests/helpers/fetch.rs +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright 2015-2017 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 . - -use std::{thread, time}; -use std::sync::{atomic, mpsc, Arc}; -use parking_lot::Mutex; -use hyper; - -use futures::{self, future, Future}; -use fetch::{self, Fetch, Url, Request, Abort}; - -pub struct FetchControl { - sender: mpsc::Sender<()>, - fetch: FakeFetch, -} - -impl FetchControl { - pub fn respond(self) { - self.sender.send(()) - .expect("Fetch cannot be finished without sending a response at least once."); - } - - pub fn wait_for_requests(&self, len: usize) { - const MAX_TIMEOUT: time::Duration = time::Duration::from_millis(5000); - const ATTEMPTS: u32 = 10; - let mut attempts_left = ATTEMPTS; - loop { - let current = self.fetch.requested.lock().len(); - - if current == len { - break; - } else if attempts_left == 0 { - panic!( - "Timeout reached when waiting for pending requests. Expected: {}, current: {}", - len, current - ); - } else { - attempts_left -= 1; - // Should we handle spurious timeouts better? - thread::park_timeout(MAX_TIMEOUT / ATTEMPTS); - } - } - } -} - -#[derive(Clone, Default)] -pub struct FakeFetch { - manual: Arc>>>, - response: Arc>>, - asserted: Arc, - requested: Arc>>, -} - -impl FakeFetch { - pub fn set_response(&self, data: &'static [u8]) { - *self.response.lock() = Some(data); - } - - pub fn manual(&self) -> FetchControl { - assert!(self.manual.lock().is_none(), "Only one manual control may be active."); - let (tx, rx) = mpsc::channel(); - *self.manual.lock() = Some(rx); - - FetchControl { - sender: tx, - fetch: self.clone(), - } - } - - pub fn assert_requested(&self, url: &str) { - let requests = self.requested.lock(); - let idx = self.asserted.fetch_add(1, atomic::Ordering::SeqCst); - - assert_eq!(requests.get(idx), Some(&url.to_owned()), "Expected fetch from specific URL."); - } - - pub fn assert_no_more_requests(&self) { - let requests = self.requested.lock(); - let len = self.asserted.load(atomic::Ordering::SeqCst); - assert_eq!(requests.len(), len, "Didn't expect any more requests, got: {:?}", &requests[len..]); - } -} - -impl Fetch for FakeFetch { - type Result = Box + Send>; - - fn fetch(&self, request: Request, abort: fetch::Abort) -> Self::Result { - let u = request.url().clone(); - self.requested.lock().push(u.as_str().into()); - let manual = self.manual.clone(); - let response = self.response.clone(); - - let (tx, rx) = futures::oneshot(); - thread::spawn(move || { - if let Some(rx) = manual.lock().take() { - // wait for manual resume - let _ = rx.recv(); - } - let data = response.lock().take().unwrap_or(b"Some content"); - tx.send(fetch::Response::new(u, hyper::Response::new().with_body(data), abort)).unwrap(); - }); - - Box::new(rx.map_err(|_| fetch::Error::Aborted)) - } - - fn get(&self, url: &str, abort: Abort) -> Self::Result { - let url: Url = match url.parse() { - Ok(u) => u, - Err(e) => return Box::new(future::err(e.into())) - }; - self.fetch(Request::get(url), abort) - } - - fn post(&self, url: &str, abort: Abort) -> Self::Result { - let url: Url = match url.parse() { - Ok(u) => u, - Err(e) => return Box::new(future::err(e.into())) - }; - self.fetch(Request::post(url), abort) - } -} diff --git a/dapps/src/tests/helpers/mod.rs b/dapps/src/tests/helpers/mod.rs deleted file mode 100644 index 41df0db61b9e1cff5d8acc3a8d062f5b3c9e57b7..0000000000000000000000000000000000000000 --- a/dapps/src/tests/helpers/mod.rs +++ /dev/null @@ -1,290 +0,0 @@ -// Copyright 2015-2017 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 . - -use std::{env, io, str}; -use std::net::SocketAddr; -use std::path::{Path, PathBuf}; -use std::sync::Arc; -use env_logger::LogBuilder; -use jsonrpc_core::IoHandler; -use jsonrpc_http_server::{self as http, Host, DomainsValidation}; -use parity_reactor::Remote; - -use devtools::http_client; -use registrar::{RegistrarClient, Asynchronous}; -use fetch::{Fetch, Client as FetchClient}; -use node_health::{NodeHealth, TimeChecker, CpuPool}; - -use {Middleware, SyncStatus, WebProxyTokens}; - -mod registrar; -mod fetch; - -use self::registrar::FakeRegistrar; -use self::fetch::FakeFetch; - -const SIGNER_PORT: u16 = 18180; - -#[derive(Debug)] -struct FakeSync(bool); -impl SyncStatus for FakeSync { - fn is_major_importing(&self) -> bool { self.0 } - fn peers(&self) -> (usize, usize) { (0, 5) } -} - -fn init_logger() { - // Initialize logger - if let Ok(log) = env::var("RUST_LOG") { - let mut builder = LogBuilder::new(); - builder.parse(&log); - let _ = builder.init(); // ignore errors since ./test.sh will call this multiple times. - } -} - -pub fn init_server(process: F, io: IoHandler) -> (Server, Arc) where - F: FnOnce(ServerBuilder) -> ServerBuilder, - B: Fetch, -{ - init_logger(); - let registrar = Arc::new(FakeRegistrar::new()); - let mut dapps_path = env::temp_dir(); - dapps_path.push("non-existent-dir-to-prevent-fs-files-from-loading"); - - let mut builder = ServerBuilder::new(FetchClient::new().unwrap(), &dapps_path, registrar.clone()); - builder.signer_address = Some(("127.0.0.1".into(), SIGNER_PORT)); - let server = process(builder).start_unsecured_http(&"127.0.0.1:0".parse().unwrap(), io).unwrap(); - ( - server, - registrar, - ) -} - -pub fn serve_with_rpc(io: IoHandler) -> Server { - init_server(|builder| builder, io).0 -} - -pub fn serve_hosts(hosts: Option>) -> Server { - let hosts = hosts.map(|hosts| hosts.into_iter().map(Into::into).collect()); - init_server(|mut builder| { - builder.allowed_hosts = hosts.into(); - builder - }, Default::default()).0 -} - -pub fn serve_with_registrar() -> (Server, Arc) { - init_server(|builder| builder, Default::default()) -} - -pub fn serve_with_registrar_and_sync() -> (Server, Arc) { - init_server(|mut builder| { - builder.sync_status = Arc::new(FakeSync(true)); - builder - }, Default::default()) -} - -pub fn serve_with_registrar_and_fetch() -> (Server, FakeFetch, Arc) { - let fetch = FakeFetch::default(); - let f = fetch.clone(); - let (server, reg) = init_server(move |builder| { - builder.fetch(f.clone()) - }, Default::default()); - - (server, fetch, reg) -} - -pub fn serve_with_fetch(web_token: &'static str, domain: &'static str) -> (Server, FakeFetch) { - let fetch = FakeFetch::default(); - let f = fetch.clone(); - let (server, _) = init_server(move |mut builder| { - builder.web_proxy_tokens = Arc::new(move |token| { - if &token == web_token { Some(domain.into()) } else { None } - }); - builder.fetch(f.clone()) - }, Default::default()); - - (server, fetch) -} - -pub fn serve() -> Server { - init_server(|builder| builder, Default::default()).0 -} - -pub fn serve_ui() -> Server { - init_server(|mut builder| { - builder.serve_ui = true; - builder - }, Default::default()).0 -} - -pub fn request(server: Server, request: &str) -> http_client::Response { - http_client::request(server.addr(), request) -} - -pub fn assert_security_headers(headers: &[String]) { - http_client::assert_security_headers_present(headers, None) -} -pub fn assert_security_headers_for_embed(headers: &[String]) { - http_client::assert_security_headers_present(headers, Some(SIGNER_PORT)) -} - - -/// Webapps HTTP+RPC server build. -pub struct ServerBuilder { - dapps_path: PathBuf, - registrar: Arc>, - sync_status: Arc, - web_proxy_tokens: Arc, - signer_address: Option<(String, u16)>, - allowed_hosts: DomainsValidation, - fetch: T, - serve_ui: bool, -} - -impl ServerBuilder { - /// Construct new dapps server - pub fn new>(fetch: FetchClient, dapps_path: P, registrar: Arc>) -> Self { - ServerBuilder { - dapps_path: dapps_path.as_ref().to_owned(), - registrar: registrar, - sync_status: Arc::new(FakeSync(false)), - web_proxy_tokens: Arc::new(|_| None), - signer_address: None, - allowed_hosts: DomainsValidation::Disabled, - fetch: fetch, - serve_ui: false, - } - } -} - -impl ServerBuilder { - /// Set a fetch client to use. - pub fn fetch(self, fetch: X) -> ServerBuilder { - ServerBuilder { - dapps_path: self.dapps_path, - registrar: self.registrar, - sync_status: self.sync_status, - web_proxy_tokens: self.web_proxy_tokens, - signer_address: self.signer_address, - allowed_hosts: self.allowed_hosts, - fetch: fetch, - serve_ui: self.serve_ui, - } - } - - /// Asynchronously start server with no authentication, - /// returns result with `Server` handle on success or an error. - pub fn start_unsecured_http(self, addr: &SocketAddr, io: IoHandler) -> io::Result { - Server::start_http( - addr, - io, - self.allowed_hosts, - self.signer_address, - self.dapps_path, - vec![], - self.registrar, - self.sync_status, - self.web_proxy_tokens, - Remote::new_sync(), - self.fetch, - self.serve_ui, - ) - } -} - -const DAPPS_DOMAIN: &'static str = "web3.site"; - -/// Webapps HTTP server. -pub struct Server { - server: Option, -} - -impl Server { - fn start_http( - addr: &SocketAddr, - io: IoHandler, - allowed_hosts: DomainsValidation, - signer_address: Option<(String, u16)>, - dapps_path: PathBuf, - extra_dapps: Vec, - registrar: Arc>, - sync_status: Arc, - web_proxy_tokens: Arc, - remote: Remote, - fetch: F, - serve_ui: bool, - ) -> io::Result { - let health = NodeHealth::new( - sync_status.clone(), - TimeChecker::new::(&[], CpuPool::new(1)), - remote.clone(), - ); - let pool = ::futures_cpupool::CpuPool::new(1); - let middleware = if serve_ui { - Middleware::ui( - pool, - health, - DAPPS_DOMAIN.into(), - registrar, - sync_status, - fetch, - false, - ) - } else { - Middleware::dapps( - pool, - health, - signer_address, - vec![], - vec![], - dapps_path, - extra_dapps, - DAPPS_DOMAIN.into(), - registrar, - sync_status, - web_proxy_tokens, - fetch, - ) - }; - - let mut allowed_hosts: Option> = allowed_hosts.into(); - allowed_hosts.as_mut().map(|hosts| { - hosts.push(format!("http://*.{}:*", DAPPS_DOMAIN).into()); - hosts.push(format!("http://*.{}", DAPPS_DOMAIN).into()); - }); - - http::ServerBuilder::new(io) - .request_middleware(middleware) - .allowed_hosts(allowed_hosts.into()) - .cors(http::DomainsValidation::Disabled) - .start_http(addr) - .map(|server| Server { - server: Some(server), - }) - } - - /// Returns address that this server is bound to. - pub fn addr(&self) -> &SocketAddr { - self.server.as_ref() - .expect("server is always Some at the start; it's consumed only when object is dropped; qed") - .address() - } -} - -impl Drop for Server { - fn drop(&mut self) { - self.server.take().unwrap().close() - } -} diff --git a/dapps/src/tests/helpers/registrar.rs b/dapps/src/tests/helpers/registrar.rs deleted file mode 100644 index e770146f5a2a43e770cf146cf19c54976a572060..0000000000000000000000000000000000000000 --- a/dapps/src/tests/helpers/registrar.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2015-2017 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 . - -use std::str; -use std::sync::Arc; -use std::collections::HashMap; - -use ethereum_types::{H256, Address}; -use bytes::{Bytes, ToPretty}; -use registrar::{RegistrarClient, Asynchronous}; -use parking_lot::Mutex; -use rustc_hex::FromHex; - -const REGISTRAR: &'static str = "8e4e9b13d4b45cb0befc93c3061b1408f67316b2"; -const URLHINT: &'static str = "deadbeefcafe0000000000000000000000000000"; -const URLHINT_RESOLVE: &'static str = "267b6922"; -const DEFAULT_HASH: &'static str = "1472a9e190620cdf6b31f383373e45efcfe869a820c91f9ccd7eb9fb45e4985d"; - -pub struct FakeRegistrar { - pub calls: Arc>>, - pub responses: Mutex>>, -} - -impl FakeRegistrar { - pub fn new() -> Self { - FakeRegistrar { - calls: Arc::new(Mutex::new(Vec::new())), - responses: Mutex::new({ - let mut map = HashMap::new(); - map.insert( - (REGISTRAR.into(), "6795dbcd058740ee9a5a3fb9f1cfa10752baec87e09cc45cd7027fd54708271aca300c75000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000000".into()), - Ok(format!("000000000000000000000000{}", URLHINT).from_hex().unwrap()), - ); - map.insert( - (URLHINT.into(), format!("{}{}", URLHINT_RESOLVE, DEFAULT_HASH)), - Ok(vec![]) - ); - map - }), - } - } - - pub fn set_result(&self, hash: H256, result: Result) { - self.responses.lock().insert( - (URLHINT.into(), format!("{}{:x}", URLHINT_RESOLVE, hash)), - result - ); - } -} - -impl RegistrarClient for FakeRegistrar { - type Call = Asynchronous; - - fn registrar_address(&self) -> Result { - Ok(REGISTRAR.parse().unwrap()) - } - - fn call_contract(&self, address: Address, data: Bytes) -> Self::Call { - let call = (address.to_hex(), data.to_hex()); - self.calls.lock().push(call.clone()); - let res = self.responses.lock().get(&call).cloned().expect(&format!("No response for call: {:?}", call)); - Box::new(::futures::future::done(res)) - } -} diff --git a/dapps/src/tests/home.rs b/dapps/src/tests/home.rs deleted file mode 100644 index fa5c5b4c465e3748e8bae5a21682b134935551d7..0000000000000000000000000000000000000000 --- a/dapps/src/tests/home.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2015-2017 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 . - -use tests::helpers::{serve_ui, request, assert_security_headers}; - -#[test] -fn should_serve_home_js() { - // given - let server = serve_ui(); - - // when - let response = request(server, - "\ - GET /inject.js HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - response.assert_header("Content-Type", "application/javascript"); - assert_eq!(response.body.contains("function(){"), true, "Expected function in: {}", response.body); - assert_security_headers(&response.headers); -} - -#[test] -fn should_serve_home() { - // given - let server = serve_ui(); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - response.assert_header("Content-Type", "text/html"); - assert_security_headers(&response.headers); -} diff --git a/dapps/src/tests/mod.rs b/dapps/src/tests/mod.rs deleted file mode 100644 index a47294392ea8e1b5b9f2df39c2681a7f8b9f7132..0000000000000000000000000000000000000000 --- a/dapps/src/tests/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Dapps server test suite - -mod helpers; - -mod api; -mod fetch; -mod home; -mod redirection; -mod rpc; -mod validation; - diff --git a/dapps/src/tests/redirection.rs b/dapps/src/tests/redirection.rs deleted file mode 100644 index b7f72009f72f987394d53960aad62a6079e02f09..0000000000000000000000000000000000000000 --- a/dapps/src/tests/redirection.rs +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2015-2017 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 . - -use tests::helpers::{serve, request, assert_security_headers, assert_security_headers_for_embed}; - -#[test] -fn should_redirect_to_home() { - // given - let server = serve(); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 302 Found"); - assert_eq!(response.headers.get(0).unwrap(), "Location: http://127.0.0.1:18180"); -} - -#[test] -fn should_redirect_to_home_with_domain() { - // given - let server = serve(); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: home.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 302 Found"); - assert_eq!(response.headers.get(0).unwrap(), "Location: http://127.0.0.1:18180"); -} - -#[test] -fn should_redirect_to_home_when_trailing_slash_is_missing() { - // given - let server = serve(); - - // when - let response = request(server, - "\ - GET /app HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 302 Found"); - assert_eq!(response.headers.get(0).unwrap(), "Location: http://127.0.0.1:18180"); -} - -#[test] -fn should_display_404_on_invalid_dapp() { - // given - let server = serve(); - - // when - let response = request(server, - "\ - GET /invaliddapp/ HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 404 Not Found"); - assert_security_headers_for_embed(&response.headers); -} - -#[test] -fn should_display_404_on_invalid_dapp_with_domain() { - // given - let server = serve(); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: invaliddapp.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 404 Not Found"); - assert_security_headers_for_embed(&response.headers); -} - -#[test] -fn should_serve_rpc() { - // given - let server = serve(); - - // when - let response = request(server, - "\ - POST / HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - Content-Type: application/json\r\n - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - assert_eq!(response.body, format!("4C\n{}\n\n0\n\n", r#"{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"},"id":null}"#)); -} - -#[test] -fn should_serve_rpc_at_slash_rpc() { - // given - let server = serve(); - - // when - let response = request(server, - "\ - POST /rpc HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - Content-Type: application/json\r\n - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - assert_eq!(response.body, format!("4C\n{}\n\n0\n\n", r#"{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"},"id":null}"#)); -} - - -#[test] -fn should_serve_proxy_pac() { - // given - let server = serve(); - - // when - let response = request(server, - "\ - GET /proxy/proxy.pac HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - assert_eq!(response.body, "DB\n\nfunction FindProxyForURL(url, host) {\n\tif (shExpMatch(host, \"home.web3.site\"))\n\t{\n\t\treturn \"PROXY 127.0.0.1:18180\";\n\t}\n\n\tif (shExpMatch(host, \"*.web3.site\"))\n\t{\n\t\treturn \"PROXY 127.0.0.1:8080\";\n\t}\n\n\treturn \"DIRECT\";\n}\n\n0\n\n".to_owned()); - assert_security_headers(&response.headers); -} - -#[test] -fn should_serve_utils() { - // given - let server = serve(); - - // when - let response = request(server, - "\ - GET /parity-utils/inject.js HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - response.assert_header("Content-Type", "application/javascript"); - assert_eq!(response.body.contains("function(){"), true, "Expected function in: {}", response.body); - assert_security_headers(&response.headers); -} diff --git a/dapps/src/tests/rpc.rs b/dapps/src/tests/rpc.rs deleted file mode 100644 index 0cfc2c5a812b79edcb0ab858181f488ee8e273eb..0000000000000000000000000000000000000000 --- a/dapps/src/tests/rpc.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2015-2017 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 . - -use jsonrpc_core::{IoHandler, Value}; - -use tests::helpers::{serve_with_rpc, request}; - -#[test] -fn should_serve_rpc() { - // given - let mut io = IoHandler::default(); - io.add_method("rpc_test", |_| { - Ok(Value::String("Hello World!".into())) - }); - let server = serve_with_rpc(io); - - // when - let req = r#"{"jsonrpc":"2.0","id":1,"method":"rpc_test","params":[]}"#; - let response = request(server, &format!( - "\ - POST /rpc/ HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - Content-Type: application/json\r\n\ - Content-Length: {}\r\n\ - \r\n\ - {}\r\n\ - ", - req.as_bytes().len(), - req, - )); - - // then - response.assert_status("HTTP/1.1 200 OK"); - assert_eq!(response.body, "31\n{\"jsonrpc\":\"2.0\",\"result\":\"Hello World!\",\"id\":1}\n\n0\n\n".to_owned()); -} diff --git a/dapps/src/tests/validation.rs b/dapps/src/tests/validation.rs deleted file mode 100644 index bd97c940a04c67f38cc89f125741462d5e688f66..0000000000000000000000000000000000000000 --- a/dapps/src/tests/validation.rs +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2015-2017 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 . - -use tests::helpers::{serve_hosts, request}; - -#[test] -fn should_reject_invalid_host() { - // given - let server = serve_hosts(Some(vec!["localhost:8080".into()])); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 403 Forbidden"); - assert!(response.body.contains("Provided Host header is not whitelisted."), response.body); -} - -#[test] -fn should_allow_valid_host() { - // given - let server = serve_hosts(Some(vec!["localhost:8080".into()])); - - // when - let response = request(server, - "\ - GET /ui/ HTTP/1.1\r\n\ - Host: localhost:8080\r\n\ - Connection: close\r\n\ - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); -} - -#[test] -fn should_serve_dapps_domains() { - // given - let server = serve_hosts(Some(vec!["localhost:8080".into()])); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: ui.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); -} - -#[test] -// NOTE [todr] This is required for error pages to be styled properly. -fn should_allow_parity_utils_even_on_invalid_domain() { - // given - let server = serve_hosts(Some(vec!["localhost:8080".into()])); - - // when - let response = request(server, - "\ - GET /parity-utils/styles.css HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); -} diff --git a/dapps/src/web.rs b/dapps/src/web.rs deleted file mode 100644 index 86c0ac28d6c8d01bae482f60e2df36bfa69a3942..0000000000000000000000000000000000000000 --- a/dapps/src/web.rs +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Serving web-based content (proxying) - -use std::sync::Arc; - -use base32; -use fetch::{self, Fetch}; -use hyper::{mime, StatusCode}; - -use apps; -use endpoint::{Endpoint, EndpointPath, Request, Response}; -use futures::future; -use futures_cpupool::CpuPool; -use handlers::{ - ContentFetcherHandler, ContentHandler, ContentValidator, ValidatorResponse, - StreamingHandler, -}; -use {Embeddable, WebProxyTokens}; - -pub struct Web { - embeddable_on: Embeddable, - web_proxy_tokens: Arc, - fetch: F, - pool: CpuPool, -} - -impl Web { - pub fn boxed( - embeddable_on: Embeddable, - web_proxy_tokens: Arc, - fetch: F, - pool: CpuPool, - ) -> Box { - Box::new(Web { - embeddable_on, - web_proxy_tokens, - fetch, - pool, - }) - } - - fn extract_target_url(&self, path: &EndpointPath) -> Result { - let token_and_url = path.app_params.get(0) - .map(|encoded| encoded.replace('.', "")) - .and_then(|encoded| base32::decode(base32::Alphabet::Crockford, &encoded.to_uppercase())) - .and_then(|data| String::from_utf8(data).ok()) - .ok_or_else(|| ContentHandler::error( - StatusCode::BadRequest, - "Invalid parameter", - "Couldn't parse given parameter:", - path.app_params.get(0).map(String::as_str), - self.embeddable_on.clone() - ))?; - - let mut token_it = token_and_url.split('+'); - let token = token_it.next(); - let target_url = token_it.next(); - - // Check if token supplied in URL is correct. - let domain = match token.and_then(|token| self.web_proxy_tokens.domain(token)) { - Some(domain) => domain, - _ => { - return Err(ContentHandler::error( - StatusCode::BadRequest, "Invalid Access Token", "Invalid or old web proxy access token supplied.", Some("Try refreshing the page."), self.embeddable_on.clone() - )); - } - }; - - // Validate protocol - let mut target_url = match target_url { - Some(url) if url.starts_with("http://") || url.starts_with("https://") => url.to_owned(), - _ => { - return Err(ContentHandler::error( - StatusCode::BadRequest, "Invalid Protocol", "Invalid protocol used.", None, self.embeddable_on.clone() - )); - } - }; - - if !target_url.starts_with(&*domain) { - return Err(ContentHandler::error( - StatusCode::BadRequest, "Invalid Domain", "Dapp attempted to access invalid domain.", Some(&target_url), self.embeddable_on.clone(), - )); - } - - if !target_url.ends_with("/") { - target_url = format!("{}/", target_url); - } - - // Skip the token - let query = path.query.as_ref().map_or_else(String::new, |query| format!("?{}", query)); - let path = path.app_params[1..].join("/"); - - Ok(format!("{}{}{}", target_url, path, query)) - } -} - -impl Endpoint for Web { - fn respond(&self, path: EndpointPath, req: Request) -> Response { - // First extract the URL (reject invalid URLs) - let target_url = match self.extract_target_url(&path) { - Ok(url) => url, - Err(response) => { - return Box::new(future::ok(response.into())); - } - }; - - let token = path.app_params.get(0) - .expect("`target_url` is valid; app_params is not empty;qed") - .to_owned(); - - Box::new(ContentFetcherHandler::new( - req.method(), - &target_url, - path, - WebInstaller { - embeddable_on: self.embeddable_on.clone(), - token, - }, - self.embeddable_on.clone(), - self.fetch.clone(), - self.pool.clone(), - )) - } -} - -struct WebInstaller { - embeddable_on: Embeddable, - token: String, -} - -impl ContentValidator for WebInstaller { - type Error = String; - - fn validate_and_install(self, response: fetch::Response) -> Result { - let status = response.status(); - let is_html = response.is_html(); - let mime = response.content_type().unwrap_or(mime::TEXT_HTML); - let mut handler = StreamingHandler::new( - fetch::BodyReader::new(response), - status, - mime, - self.embeddable_on, - ); - if is_html { - handler.set_initial_content(&format!( - r#""#, - apps::UTILS_PATH, - apps::URL_REFERER, - apps::WEB_PATH, - &self.token, - )); - } - Ok(ValidatorResponse::Streaming(handler)) - } -} - diff --git a/dapps/ui-deprecation/Cargo.toml b/dapps/ui-deprecation/Cargo.toml deleted file mode 100644 index f4479c2367eaa0e7f277066935577c002f3109d1..0000000000000000000000000000000000000000 --- a/dapps/ui-deprecation/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -description = "Parity UI deprecation notice." -name = "parity-ui-deprecation" -version = "1.10.0" -license = "GPL-3.0" -authors = ["Parity Technologies "] -build = "build.rs" - -[features] -default = ["with-syntex", "use-precompiled-js"] -use-precompiled-js = ["parity-dapps-glue/use-precompiled-js"] -with-syntex = ["parity-dapps-glue/with-syntex"] - -[build-dependencies] -parity-dapps-glue = "1.9" - -[dependencies] -parity-dapps-glue = "1.9" diff --git a/dapps/ui-deprecation/build/index.html b/dapps/ui-deprecation/build/index.html deleted file mode 100644 index 07059743c6265b4671d3d2e7fdba3bef5c3ea461..0000000000000000000000000000000000000000 --- a/dapps/ui-deprecation/build/index.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - Parity - - - -
-
-
-

The Parity UI has been split off into a standalone project.

-

Get the standalone Parity UI from here

-

- -

-
-
-
- - diff --git a/dapps/ui-deprecation/src/lib.rs.in b/dapps/ui-deprecation/src/lib.rs.in deleted file mode 100644 index 892ebbded218022bbe8f3cb576fabd58e2cc222d..0000000000000000000000000000000000000000 --- a/dapps/ui-deprecation/src/lib.rs.in +++ /dev/null @@ -1,55 +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 . - -extern crate parity_dapps_glue; - -use std::collections::HashMap; -use parity_dapps_glue::{WebApp, File, Info}; - -#[derive(WebAppFiles)] -#[webapp(path = "../build")] -pub struct App { - pub files: HashMap<&'static str, File>, -} - -impl Default for App { - fn default() -> App { - App { - files: Self::files(), - } - } -} - -impl WebApp for App { - fn file(&self, path: &str) -> Option<&File> { - self.files.get(path) - } - - fn info(&self) -> Info { - Info { - name: "Parity Wallet info page", - version: env!("CARGO_PKG_VERSION"), - author: "Parity ", - description: "Deprecation notice for Parity Wallet", - icon_url: "icon.png", - } - } -} - -#[test] -fn test_js() { - parity_dapps_glue::js::build(env!("CARGO_MANIFEST_DIR"), "build"); -} diff --git a/dapps/ui/Cargo.toml b/dapps/ui/Cargo.toml deleted file mode 100644 index acb7a91735fb89c39eb0b98bacb96b3249e9ec98..0000000000000000000000000000000000000000 --- a/dapps/ui/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -description = "Ethcore Parity UI" -homepage = "http://parity.io" -license = "GPL-3.0" -name = "parity-ui" -version = "1.12.0" -authors = ["Parity Technologies "] - -[build-dependencies] -rustc_version = "0.2" - -[dependencies] -parity-ui-dev = { git = "https://github.com/parity-js/shell.git", rev = "eecaadcb9e421bce31e91680d14a20bbd38f92a2", optional = true } -parity-ui-old-dev = { git = "https://github.com/parity-js/dapp-wallet.git", rev = "65deb02e7c007a0fd8aab0c089c93e3fd1de6f87", optional = true } -parity-ui-precompiled = { git = "https://github.com/js-dist-paritytech/parity-master-1-10-shell.git", rev="bd25b41cd642c6b822d820dded3aa601a29aa079", optional = true } -parity-ui-old-precompiled = { git = "https://github.com/js-dist-paritytech/parity-master-1-10-wallet.git", rev="4b6f112412716cd05123d32eeb7fda448288a6c6", optional = true } - -[features] -no-precompiled-js = ["parity-ui-dev", "parity-ui-old-dev"] -use-precompiled-js = ["parity-ui-precompiled", "parity-ui-old-precompiled"] diff --git a/dapps/ui/src/lib.rs b/dapps/ui/src/lib.rs deleted file mode 100644 index aa1c86736668a09d325f1f91462c171a959ce265..0000000000000000000000000000000000000000 --- a/dapps/ui/src/lib.rs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2015-2017 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 . - - -#[cfg(feature = "parity-ui-dev")] -mod inner { - extern crate parity_ui_dev; - - pub use self::parity_ui_dev::*; -} - -#[cfg(feature = "parity-ui-precompiled")] -mod inner { - extern crate parity_ui_precompiled; - - pub use self::parity_ui_precompiled::*; -} - -#[cfg(feature = "parity-ui-old-dev")] -pub mod old { - extern crate parity_ui_old_dev; - - pub use self::parity_ui_old_dev::*; -} - -#[cfg(feature = "parity-ui-old-precompiled")] -pub mod old { - extern crate parity_ui_old_precompiled; - - pub use self::parity_ui_old_precompiled::*; -} - -pub use self::inner::*; diff --git a/devtools/src/http_client.rs b/devtools/src/http_client.rs index ab234105929077c3d777e2b5ac37a733a2bfbe2c..e2f33d4257fbc071c466a171249f1ac4021ba391 100644 --- a/devtools/src/http_client.rs +++ b/devtools/src/http_client.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/devtools/src/lib.rs b/devtools/src/lib.rs index efaf4b9351acb9e04e65e4eabcb68f9310925789..6fdbc8d8902edd4d7c224ef1b494b51b10aff67c 100644 --- a/devtools/src/lib.rs +++ b/devtools/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index ad8879ecf736ede6d3cee1c4c8089ad2d0d6dc59..ad375e5a91a99ab1329793ef334ee46f0a793666 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -1,11 +1,11 @@ -FROM alpine:3.7 +FROM alpine:edge WORKDIR /build # install tools and dependencies -RUN apk add --no-cache gcc musl-dev openssl-dev pkgconfig g++ make curl \ - eudev-dev rust cargo git file binutils libusb-dev \ - linux-headers +RUN apk add --no-cache gcc musl-dev pkgconfig g++ make curl \ + eudev-dev rust cargo git file binutils \ + libusb-dev linux-headers perl cmake # show backtraces ENV RUST_BACKTRACE 1 diff --git a/docker/android/Dockerfile b/docker/android/Dockerfile index 7783781b4cad35a2493bb7352dad6ff8920fd842..1dbf15fac7dbe587fd912cb8b8833feb10ec5486 100644 --- a/docker/android/Dockerfile +++ b/docker/android/Dockerfile @@ -23,24 +23,6 @@ RUN /usr/local/android-ndk-r16b/build/tools/make-standalone-toolchain.sh \ --arch=arm --install-dir=/opt/ndk-standalone --stl=libc++ --platform=android-26 ENV PATH $PATH:/opt/ndk-standalone/bin -# Compiling OpenSSL for Android -RUN cd /root && \ - git clone git://git.openssl.org/openssl.git && \ - cd openssl && \ - git checkout OpenSSL_1_1_0-stable -ENV CROSS_SYSROOT /opt/ndk-standalone/sysroot -RUN cd /root/openssl && \ - ./Configure android-armeabi --cross-compile-prefix=arm-linux-androideabi- \ - -static no-stdio no-ui \ - -I/usr/local/android-ndk-r16b/sysroot/usr/include \ - -I/usr/local/android-ndk-r16b/sysroot/usr/include/arm-linux-androideabi \ - -L/usr/local/android-ndk-r16b/sysroot/usr/lib \ - --prefix=/opt/ndk-standalone/sysroot/usr -RUN cd /root/openssl && \ - make build_libs && \ - make install_dev -RUN rm -rf /root/openssl - # Compiling libudev for Android # This is the most hacky part of the process, as we need to apply a patch and pass specific # options that the compiler environment doesn't define. diff --git a/docker/centos/Dockerfile b/docker/centos/Dockerfile index 747a227c90b3ed0320db4d434516e62fe8a68d53..7c944001e2c01156016f9dea5bc0be7dd3008ede 100644 --- a/docker/centos/Dockerfile +++ b/docker/centos/Dockerfile @@ -3,7 +3,7 @@ WORKDIR /build # install tools and dependencies RUN yum -y update&& \ - yum install -y git make gcc-c++ gcc file binutils + yum install -y git make gcc-c++ gcc file binutils cmake # install rustup RUN curl -sSf https://static.rust-lang.org/rustup.sh -o rustup.sh &&\ diff --git a/docker/hub/Dockerfile b/docker/hub/Dockerfile index a0921ae4b574f1ba182bb51190686952e937dadd..eb007dc10a8b26ba642fd22cb38d7e5ecf3d0ce8 100644 --- a/docker/hub/Dockerfile +++ b/docker/hub/Dockerfile @@ -1,27 +1,64 @@ FROM ubuntu:xenial MAINTAINER Parity Technologies -#set ENVIROMENT -ARG TARGET -ENV TARGET ${TARGET} - +WORKDIR /build +#ENV for build TAG +ARG BUILD_TAG +ENV BUILD_TAG ${BUILD_TAG:-master} +RUN echo "Build tag:" $BUILD_TAG # install tools and dependencies -RUN apt update && apt install -y --no-install-recommends openssl libudev-dev file - +RUN apt-get update && \ + apt-get install -y --force-yes --no-install-recommends \ + # make + build-essential \ + # add-apt-repository + software-properties-common \ + make \ + cmake \ + curl \ + wget \ + git \ + g++ \ + gcc \ + libc6 \ + libc6-dev \ + binutils \ + file \ + libudev-dev \ + pkg-config \ + dpkg-dev &&\ +# install rustup + curl https://sh.rustup.rs -sSf | sh -s -- -y && \ +# rustup directory + PATH=/root/.cargo/bin:$PATH && \ # show backtraces -ENV RUST_BACKTRACE 1 - + RUST_BACKTRACE=1 && \ +# build parity +cd /build&&git clone https://github.com/paritytech/parity-ethereum && \ + cd parity-ethereum&& \ + git pull&& \ + git checkout $BUILD_TAG && \ + cargo build --verbose --release --features final && \ + strip /build/parity-ethereum/target/release/parity && \ + file /build/parity-ethereum/target/release/parity&&mkdir -p /parity&& cp /build/parity-ethereum/target/release/parity /parity&&\ #cleanup Docker image -RUN apt autoremove -y -RUN apt clean -y -RUN rm -rf /tmp/* /var/tmp/* /var/lib/apt/lists/* - -#add TARGET to docker image -COPY artifacts/$TARGET /usr/bin/$TARGET - -# Build a shell script because the ENTRYPOINT command doesn't like using ENV -RUN echo "#!/bin/bash \n ${TARGET} \$@" > ./entrypoint.sh -RUN chmod +x ./entrypoint.sh - + rm -rf /root/.cargo&&rm -rf /root/.multirust&&rm -rf /root/.rustup&&rm -rf /build&&\ + apt-get purge -y \ + # make + build-essential \ + # add-apt-repository + software-properties-common \ + make \ + cmake \ + curl \ + wget \ + git \ + g++ \ + gcc \ + binutils \ + file \ + pkg-config \ + dpkg-dev &&\ + rm -rf /var/lib/apt/lists/* # setup ENTRYPOINT EXPOSE 8080 8545 8180 -ENTRYPOINT ["./entrypoint.sh"] +ENTRYPOINT ["/parity/parity"] diff --git a/docker/ubuntu-aarch64/Dockerfile b/docker/ubuntu-aarch64/Dockerfile index eee1587f4f696ee068ba4dca09c7008c1d3ee01b..5eefe3dbdbfbd9d62f78d4e9fc72e7fa20ba3c6e 100644 --- a/docker/ubuntu-aarch64/Dockerfile +++ b/docker/ubuntu-aarch64/Dockerfile @@ -6,7 +6,7 @@ RUN apt-get -y update && \ apt-get install -y --force-yes --no-install-recommends \ curl git make g++ gcc-aarch64-linux-gnu g++-aarch64-linux-gnu \ libc6-arm64-cross libc6-dev-arm64-cross wget file ca-certificates \ - binutils-aarch64-linux-gnu \ + binutils-aarch64-linux-gnu cmake \ && \ apt-get clean diff --git a/docker/ubuntu-arm/Dockerfile b/docker/ubuntu-arm/Dockerfile index f971c98f17b63b196ec1a1844bb8480c447b7e80..d924a20f57e2925682a0b2517a35b319feaed3b5 100644 --- a/docker/ubuntu-arm/Dockerfile +++ b/docker/ubuntu-arm/Dockerfile @@ -6,7 +6,7 @@ RUN apt-get -y update && \ apt-get install -y --force-yes --no-install-recommends \ curl git make g++ gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf \ libc6-dev-armhf-cross wget file ca-certificates \ - binutils-arm-linux-gnueabihf \ + binutils-arm-linux-gnueabihf cmake \ && \ apt-get clean diff --git a/docker/ubuntu/Dockerfile b/docker/ubuntu/Dockerfile index e840cdc6e11a98e4cfe1783f13dce752d631ab1d..574ff64ebd257964024c896a951429e7e10f206e 100644 --- a/docker/ubuntu/Dockerfile +++ b/docker/ubuntu/Dockerfile @@ -6,11 +6,11 @@ RUN apt-get update && \ apt-get install -y \ g++ \ build-essential \ + cmake \ curl \ git \ file \ binutils \ - libssl-dev \ pkg-config \ libudev-dev diff --git a/docs/CHANGELOG-1.10.md b/docs/CHANGELOG-1.10.md index a8c7ad20a7562a14fe457711e5e0e3e8cbadc798..21a18cbb3164d7ac8de9b746d1b76f40a6f88794 100644 --- a/docs/CHANGELOG-1.10.md +++ b/docs/CHANGELOG-1.10.md @@ -1,3 +1,124 @@ +Note: Parity 1.10 reached End-of-Life on 2018-07-18 (EOL). + +## 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. + +The full list of included changes: + +- Backports ([#8919](https://github.com/paritytech/parity/pull/8919)) + - Fixed AuthorityRound deadlock on shutdown, closes [#8088](https://github.com/paritytech/parity/issues/8088) ([#8803](https://github.com/paritytech/parity/pull/8803)) + - CI: Fix docker tags ([#8822](https://github.com/paritytech/parity/pull/8822)) + - Scripts: enable docker builds for beta and stable + - Scripts: docker latest should be beta not master + - Scripts: docker latest is master + - Fix concurrent access to signer queue ([#8854](https://github.com/paritytech/parity/pull/8854)) + - Fix concurrent access to signer queue + - Put request back to the queue if confirmation failed + - Typo: fix docs and rename functions to be more specific + - Change trace info "Transaction" -> "Request" + - Add new ovh bootnodes and fix port for foundation bootnode 3.2 ([#8886](https://github.com/paritytech/parity/pull/8886)) + - Add new ovh bootnodes and fix port for foundation bootnode 3.2 + - Remove old bootnodes. + - Remove duplicate 1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082 + - Block 0 is valid in queries ([#8891](https://github.com/paritytech/parity/pull/8891)) + - Update jsonrpc libs, fixed ipc leak, closes [#8774](https://github.com/paritytech/parity/issues/8774) ([#8876](https://github.com/paritytech/parity/pull/8876)) + - Add ETC Cooperative-run load balanced parity node ([#8892](https://github.com/paritytech/parity/pull/8892)) + - Minor fix in chain supplier and light provider ([#8906](https://github.com/paritytech/parity/pull/8906)) + - Fix chain supplier increment + - Fix light provider block_headers +- Parity-version: stable release 1.10.7 ([#8855](https://github.com/paritytech/parity/pull/8855)) + - Cherry-pick network-specific release flag ([#8821](https://github.com/paritytech/parity/pull/8821)) + - Parity-version: bump stable to 1.10.7 + +## Parity [v1.10.6](https://github.com/paritytech/parity/releases/tag/v1.10.6) (2018-06-05) + +Parity 1.10.6 is a security-relevant release. Please upgrade your nodes as soon as possible. + +If you can not upgrade to 1.10+ yet, please use the following branches and build your own binaries from source: + +- git checkout [old-stable-1.9](https://github.com/paritytech/parity/tree/old-stable-1.9) # `v1.9.8` (EOL) +- git checkout [old-stable-1.8](https://github.com/paritytech/parity/tree/old-stable-1.8) # `v1.8.12` (EOL) +- git checkout [old-stable-1.7](https://github.com/paritytech/parity/tree/old-stable-1.7) # `v1.7.14` (EOL) + +The full list of included changes: + +- Parity-version: bump stable to 1.10.6 ([#8805](https://github.com/paritytech/parity/pull/8805)) + - Parity-version: bump stable to 1.10.6 + - Disallow unsigned transactions in case EIP-86 is disabled ([#8802](https://github.com/paritytech/parity/pull/8802)) +- Update shell32-sys to fix windows build ([#8793](https://github.com/paritytech/parity/pull/8793)) +- Backports ([#8782](https://github.com/paritytech/parity/pull/8782)) + - Fix light sync with initial validator-set contract ([#8528](https://github.com/paritytech/parity/pull/8528)) + - Fix #8468 + - Use U256::max_value() instead + - Fix again + - Also change initial transaction gas + - Don't open Browser post-install on Mac ([#8641](https://github.com/paritytech/parity/pull/8641)) + - Prefix uint fmt with `0x` with alternate flag + - Set the request index to that of the current request ([#8683](https://github.com/paritytech/parity/pull/8683)) + - Set the request index to that of the current request + - Node table sorting according to last contact data ([#8541](https://github.com/paritytech/parity/pull/8541)) + - Network-devp2p: sort nodes in node table using last contact data + - Network-devp2p: rename node contact types in node table json output + - Network-devp2p: fix node table tests + - Network-devp2p: note node failure when failed to establish connection + - Network-devp2p: handle UselessPeer error + - Network-devp2p: note failure when marking node as useless + - Network-devp2p: handle UselessPeer disconnect ([#8686](https://github.com/paritytech/parity/pull/8686)) +- Parity: bump stable version to 1.10.5 ([#8749](https://github.com/paritytech/parity/pull/8749)) + - Parity: bump stable version to 1.10.5 + - Fix failing doc tests running on non-code + ## Parity [v1.10.4](https://github.com/paritytech/parity/releases/tag/v1.10.4) (2018-05-15) Parity 1.10.4 is a bug-fix release to improve performance and stability. @@ -187,61 +308,61 @@ The full list of included changes: - Beta Backports ([#8136](https://github.com/paritytech/parity/pull/8136)) - Support parity protocol. ([#8035](https://github.com/paritytech/parity/pull/8035)) - updater: apply exponential backoff after download failure ([#8059](https://github.com/paritytech/parity/pull/8059)) - - updater: apply exponential backoff after download failure - - updater: reset backoff on new release + - updater: apply exponential backoff after download failure + - updater: reset backoff on new release - Max code size on Kovan ([#8067](https://github.com/paritytech/parity/pull/8067)) - - Enable code size limit on kovan - - Fix formatting. + - Enable code size limit on kovan + - Fix formatting. - Limit incoming connections. ([#8060](https://github.com/paritytech/parity/pull/8060)) - - Limit ingress connections - - Optimized handshakes logging + - Limit ingress connections + - Optimized handshakes logging - WASM libraries bump ([#7970](https://github.com/paritytech/parity/pull/7970)) - - update wasmi, parity-wasm, wasm-utils to latest version - - Update to new wasmi & error handling - - also utilize new stack limiter - - fix typo - - replace dependency url - - Cargo.lock update + - update wasmi, parity-wasm, wasm-utils to latest version + - Update to new wasmi & error handling + - also utilize new stack limiter + - fix typo + - replace dependency url + - Cargo.lock update - add some dos protection ([#8084](https://github.com/paritytech/parity/pull/8084)) - revert removing blooms ([#8066](https://github.com/paritytech/parity/pull/8066)) - Revert "fix traces, removed bloomchain crate, closes [#7228](https://github.com/paritytech/parity/issues/7228), closes [#7167](https://github.com/paritytech/parity/issues/7167)" - Revert "fixed broken logs ([#7934](https://github.com/paritytech/parity/pull/7934))" - - fixed broken logs - - bring back old lock order - - remove migration v13 - - revert CURRENT_VERSION to 12 in migration.rs + - fixed broken logs + - bring back old lock order + - remove migration v13 + - revert CURRENT_VERSION to 12 in migration.rs - more dos protection ([#8104](https://github.com/paritytech/parity/pull/8104)) - Const time comparison ([#8113](https://github.com/paritytech/parity/pull/8113)) - - Use `subtle::slices_equal` for constant time comparison. - - Also update the existing version of subtle in `ethcrypto` from 0.1 to 0.5 - - Test specifically for InvalidPassword error. + - Use `subtle::slices_equal` for constant time comparison. + - Also update the existing version of subtle in `ethcrypto` from 0.1 to 0.5 + - Test specifically for InvalidPassword error. - fix trace filter returning returning unrelated reward calls, closes #8070 ([#8098](https://github.com/paritytech/parity/pull/8098)) - network: init discovery using healthy nodes ([#8061](https://github.com/paritytech/parity/pull/8061)) - - network: init discovery using healthy nodes - - network: fix style grumble - - network: fix typo + - network: init discovery using healthy nodes + - network: fix style grumble + - network: fix typo - Postpone Kovan hard fork ([#8137](https://github.com/paritytech/parity/pull/8137)) - - ethcore: postpone Kovan hard fork - - util: update version fork metadata + - ethcore: postpone Kovan hard fork + - util: update version fork metadata - Disable UI by default. ([#8105](https://github.com/paritytech/parity/pull/8105)) - dapps: update parity-ui dependencies ([#8160](https://github.com/paritytech/parity/pull/8160)) - Probe changes one step deeper ([#8134](https://github.com/paritytech/parity/pull/8134)) ([#8135](https://github.com/paritytech/parity/pull/8135)) - Beta backports ([#8053](https://github.com/paritytech/parity/pull/8053)) - CI: Fix cargo cache ([#7968](https://github.com/paritytech/parity/pull/7968)) - - Fix cache - - Only clean locked cargo cache on windows + - Fix cache + - Only clean locked cargo cache on windows - fixed ethstore sign ([#8026](https://github.com/paritytech/parity/pull/8026)) - fixed parsing ethash seals and verify_block_undordered ([#8031](https://github.com/paritytech/parity/pull/8031)) - fix for verify_block_basic crashing on invalid transaction rlp ([#8032](https://github.com/paritytech/parity/pull/8032)) - fix cache & snapcraft CI build ([#8052](https://github.com/paritytech/parity/pull/8052)) - Add MCIP-6 Byzyantium transition to Musicoin spec ([#7841](https://github.com/paritytech/parity/pull/7841)) - - Add test chain spec for musicoin byzantium testnet - - Add MCIP-6 Byzyantium transition to Musicoin spec - - Update mcip6_byz.json - - ethcore: update musicoin byzantium block number - - ethcore: update musicoin bootnodes - - Update musicoin.json - - More bootnodes. + - Add test chain spec for musicoin byzantium testnet + - Add MCIP-6 Byzyantium transition to Musicoin spec + - Update mcip6_byz.json + - ethcore: update musicoin byzantium block number + - ethcore: update musicoin bootnodes + - Update musicoin.json + - More bootnodes. - Make 1.10 beta ([#8022](https://github.com/paritytech/parity/pull/8022)) - Make 1.10 beta - Fix gitlab builds diff --git a/docs/CHANGELOG-1.11.md b/docs/CHANGELOG-1.11.md new file mode 100644 index 0000000000000000000000000000000000000000..2d8630c80a5bfbc61ce32b9a87fa559e787082f9 --- /dev/null +++ b/docs/CHANGELOG-1.11.md @@ -0,0 +1,724 @@ +## Parity [v1.11.8](https://github.com/paritytech/parity-ethereum/releases/tag/v1.11.8) (2018-07-27) + +Parity 1.11.8-stable is a bug-fix release to improve performance and stability. + +Note, authorities in PoA networks based on the Aura engine, should upgrade their nodes immediately as this release includes a critical fix. + +The full list of included changes: + +- Backports to 1.11.8-stable ([#9144](https://github.com/paritytech/parity-ethereum/pull/9144)) + - Parity-version: bump stable to 1.11.8 + - Ci: update version strings for snaps ([#9160](https://github.com/paritytech/parity-ethereum/pull/9160)) + - Be more graceful on Aura difficulty validation ([#9164](https://github.com/paritytech/parity-ethereum/pull/9164)) + - Be more graceful on Aura difficulty validation + - Test: rejects_step_backwards + - Test: proposer_switching + - Test: rejects_future_block + - Test: reports_skipped + - Test: verify_empty_seal_steps + - Parity: fix UserDefaults json parser ([#9189](https://github.com/paritytech/parity-ethereum/pull/9189)) + - Parity: fix UserDefaults json parser + - Parity: use serde_derive for UserDefaults + - Parity: support deserialization of old UserDefault json format + - Parity: make UserDefaults serde backwards compatible + - Parity: tabify indentation in UserDefaults + - Fix bugfix hard fork logic ([#9138](https://github.com/paritytech/parity-ethereum/pull/9138)) + - Fix bugfix hard fork logic + - Remove dustProtectionTransition from bugfix category + - EIP-168 is not enabled by default + - Remove unnecessary 'static + - Disable per-sender limit for local transactions. ([#9148](https://github.com/paritytech/parity-ethereum/pull/9148)) + - Disable per-sender limit for local transactions. + - Add a missing new line. + - Rpc: fix is_major_importing sync state condition ([#9112](https://github.com/paritytech/parity-ethereum/pull/9112)) + - Rpc: fix is_major_importing sync state condition + - Rpc: fix informant printout when waiting for peers + - Fix verification in ethcore-sync collect_blocks ([#9135](https://github.com/paritytech/parity-ethereum/pull/9135)) + - Docker: update hub dockerfile ([#9173](https://github.com/paritytech/parity-ethereum/pull/9173)) + - Update Dockerfile for hub + - Update to Ubuntu Xenial 16.04 + - Fix cmake version + - Docker: fix tab indentation in hub dockerfile + - Ethcore: update to parity-wasm 0.31 + - Rpc: fix broken merge + +## Parity [v1.11.7](https://github.com/paritytech/parity-ethereum/releases/tag/v1.11.7) "Prosperity" (2018-07-17) + +Parity 1.11.7 "Prosperity" is a bug-fix release to improve performance and stability that marks the 1.11 release track as `stable`. Among other fixes, this release significantly addresses peering and synchronization issues. If you experienced such issues before, upgrading is highly recommended. If you rely on old versions of Parity, check out the `old-stable-1.10` branch, cherry-pick fixes, and compile your binaries independently. There will be no official support for any versions prior to 1.11.7, however (EOL). + +If you are upgrading directly from versions 1.10.9 or earlier, please note important changes to our transaction-queue implementation, namely: + +- The pool now limits transactions per-sender (see `--tx-queue-per-sender`), local transactions also have to obey that limit. Consider increasing the limit via CLI-flag when running benchmarks or sending a lot of transactions at once. +- In case the pool is full, transactions received over the network, but originating from accounts that you have private keys for might not get accepted to the pool any more with higher priority. Consider running with larger pool size or submitting the transactions directly on the node via `eth_sendRawTransaction`. + +The full list of included changes: + +- Backports to 1.11.7-stable ([#9093](https://github.com/paritytech/parity/pull/9093)) + - Parity-version: stabilize 1.11 + - Parity-version: bump stable to 1.11.7 + - Don't fetch snapshot chunks at random ([#9088](https://github.com/paritytech/parity/pull/9088)) + - Offload cull to IoWorker. ([#9099](https://github.com/paritytech/parity/pull/9099)) + - Limit the number of transactions in pending set ([#8777](https://github.com/paritytech/parity/pull/8777)) + - Unordered iterator. + - Use unordered and limited set if full not required. + - Split timeout work into smaller timers. + - Avoid collecting all pending transactions when mining + - Remove println. + - Use priority ordering in eth-filter. + - Fix ethcore-miner tests and tx propagation. + - Review grumbles addressed. + - Add test for unordered not populating the cache. + - Fix ethcore tests. + - Fix light tests. + - Fix ethcore-sync tests. + - Fix RPC tests. + - Make sure to produce full blocks. ([#9115](https://github.com/paritytech/parity/pull/9115)) + - Update hidapi, fixes [#7542](https://github.com/paritytech/parity-ethereum/issues/7542) ([#9108](https://github.com/paritytech/parity/pull/9108)) + - Docker: add cmake dependency ([#9111](https://github.com/paritytech/parity/pull/9111)) + - Fix miner tests. + - Revert "Make sure to produce full blocks." + - This reverts commit b12d592. + - Update light client hardcoded headers ([#9098](https://github.com/paritytech/parity/pull/9098)) + - Insert Kovan hardcoded headers until 7690241 + - Insert Kovan hardcoded headers until block 7690241 + - Insert Ropsten hardcoded headers until 3612673 + - Insert Mainnet hardcoded headers until block 5941249 + - Make sure to produce full blocks. ([#9115](https://github.com/paritytech/parity/pull/9115)) + - Insert ETC (classic) hardcoded headers until block 6170625 ([#9121](https://github.com/paritytech/parity/pull/9121)) + - Fix verification in ethcore-sync collect_blocks ([#9135](https://github.com/paritytech/parity/pull/9135)) + - `evm bench` fix broken dependencies ([#9134](https://github.com/paritytech/parity/pull/9134)) + - `evm bench` use valid dependencies + - Fix warnings + +## 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. + +The full list of included changes: + +- Backports ([#8916](https://github.com/paritytech/parity/pull/8916)) + - `Duration_ns: u64 -> duration: Duration` ([#8457](https://github.com/paritytech/parity/pull/8457)) + - Duration_ns: u64 -> duration: Duration + - Format on millis {:.2} -> {} + - Keep all enacted blocks notify in order ([#8524](https://github.com/paritytech/parity/pull/8524)) + - Keep all enacted blocks notify in order + - Collect is unnecessary + - Update ChainNotify to use ChainRouteType + - Fix all ethcore fn defs + - Wrap the type within ChainRoute + - Fix private-tx and sync api + - Fix secret_store API + - Fix updater API + - Fix rpc api + - Fix informant api + - Eagerly cache enacted/retracted and remove contain_enacted/retracted + - Fix indent + - Tests: should use full expr form for struct constructor + - Use into_enacted_retracted to further avoid copy + - Typo: not a function + - Rpc/tests: ChainRoute -> ChainRoute::new + - Handle removed logs in filter changes and add geth compatibility field ([#8796](https://github.com/paritytech/parity/pull/8796)) + - Add removed geth compatibility field in log + - Fix mocked tests + - Add field block hash in PollFilter + - Store last block hash info for log filters + - Implement canon route + - Use canon logs for fetching reorg logs + - Make sure removed flag is set + - Address grumbles + - Fixed AuthorityRound deadlock on shutdown, closes [#8088](https://github.com/paritytech/parity/issues/8088) ([#8803](https://github.com/paritytech/parity/pull/8803)) + - Ci: Fix docker tags ([#8822](https://github.com/paritytech/parity/pull/8822)) + - Scripts: enable docker builds for beta and stable + - Scripts: docker latest should be beta not master + - Scripts: docker latest is master + - Ethcore: fix ancient block error msg handling ([#8832](https://github.com/paritytech/parity/pull/8832)) + - Disable parallel verification and skip verifiying already imported txs. ([#8834](https://github.com/paritytech/parity/pull/8834)) + - Reject transactions that are already in pool without verifying them. + - Avoid verifying already imported transactions. + - Fix concurrent access to signer queue ([#8854](https://github.com/paritytech/parity/pull/8854)) + - Fix concurrent access to signer queue + - Put request back to the queue if confirmation failed + - Typo: fix docs and rename functions to be more specific + - Change trace info "Transaction" -> "Request" + - Don't allocate in expect_valid_rlp unless necessary ([#8867](https://github.com/paritytech/parity/pull/8867)) + - Don't allocate via format! in case there's no error + - Fix test? + - Fixed ipc leak, closes [#8774](https://github.com/paritytech/parity/issues/8774) ([#8876](https://github.com/paritytech/parity/pull/8876)) + - Add new ovh bootnodes and fix port for foundation bootnode 3.2 ([#8886](https://github.com/paritytech/parity/pull/8886)) + - Add new ovh bootnodes and fix port for foundation bootnode 3.2 + - Remove old bootnodes. + - Remove duplicate 1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082 + - Block 0 is valid in queries ([#8891](https://github.com/paritytech/parity/pull/8891)) + - Add ETC Cooperative-run load balanced parity node ([#8892](https://github.com/paritytech/parity/pull/8892)) + - Minor fix in chain supplier and light provider ([#8906](https://github.com/paritytech/parity/pull/8906)) + - Fix chain supplier increment + - Fix light provider block_headers + - Check whether we need resealing in miner and unwrap has_account in account_provider ([#8853](https://github.com/paritytech/parity/pull/8853)) + - Remove unused Result wrap in has_account + - Check whether we need to reseal for external transactions + - Fix reference to has_account interface + - Typo: missing ) + - Refactor duplicates to prepare_and_update_sealing + - Fix build + - Allow disabling local-by-default for transactions with new config entry ([#8882](https://github.com/paritytech/parity/pull/8882)) + - Add tx_queue_allow_unknown_local config option + - Refactor flag name + don't change import_own_tx behaviour + - Add fn to TestMinerService + - Avoid race condition from trusted sources +- Parity-version: beta release 1.11.4 ([#8856](https://github.com/paritytech/parity/pull/8856)) + - Cherry-pick network-specific release flag ([#8821](https://github.com/paritytech/parity/pull/8821)) + - Parity-version: bump beta to 1.11.4 + - Parity-version: remove merge leftovers + +## Parity [v1.11.3](https://github.com/paritytech/parity/releases/tag/v1.11.3) (2018-06-06) + +Parity 1.11.3 is a security-relevant release. Please upgrade your nodes as soon as possible to [v1.10.6](https://github.com/paritytech/parity/releases/tag/v1.10.6) or [v1.11.3](https://github.com/paritytech/parity/releases/tag/v1.11.3). + +The full list of included changes: + +- Parity-version: bump beta to 1.11.3 ([#8806](https://github.com/paritytech/parity/pull/8806)) + - Parity-version: bump beta to 1.11.3 + - Disallow unsigned transactions in case EIP-86 is disabled ([#8802](https://github.com/paritytech/parity/pull/8802)) + - Fix ancient blocks queue deadlock ([#8751](https://github.com/paritytech/parity/pull/8751)) +- Update shell32-sys to fix windows build ([#8792](https://github.com/paritytech/parity/pull/8792)) +- Backports ([#8785](https://github.com/paritytech/parity/pull/8785)) + - Fix light sync with initial validator-set contract ([#8528](https://github.com/paritytech/parity/pull/8528)) + - Fix [#8468](https://github.com/paritytech/parity-ethereum/issues/8468) + - Use U256::max_value() instead + - Also change initial transaction gas + - Resumable warp-sync / Seed downloaded snapshots ([#8544](https://github.com/paritytech/parity/pull/8544)) + - Start dividing sync chain : first supplier method + - WIP - updated chain sync supplier + - Finish refactoring the Chain Sync Supplier + - Create Chain Sync Requester + - Add Propagator for Chain Sync + - Add the Chain Sync Handler + - Move tests from mod -> handler + - Move tests to propagator + - Refactor SyncRequester arguments + - Refactoring peer fork header handler + - Fix wrong highest block number in snapshot sync + - Small refactor... + - Resume warp-sync downloaded chunks + - Refactoring the previous chunks import + - Address PR grumbles + - Fix not seeding current snapshot + - Update SnapshotService readiness check + - Early abort importing previous chunks + - Update Gitlab CI config + - SyncState back to Waiting when Manifest peers disconnect + - Revert GitLab CI changes + - Refactor resuming snapshots + - Revert "Refactor resuming snapshots" + - Update informant log + - Refactor resuming snapshots + - Update informant message : show chunks done + - Don't open Browser post-install on Mac ([#8641](https://github.com/paritytech/parity/pull/8641)) + - Fix not downloading old blocks ([#8642](https://github.com/paritytech/parity/pull/8642)) + - Fix PoW blockchains sealing notifications in chain_new_blocks ([#8656](https://github.com/paritytech/parity/pull/8656)) + - Shutdown the Snapshot Service early ([#8658](https://github.com/paritytech/parity/pull/8658)) + - Shutdown the Snapshot Service when shutting down the runner + - Rename `service` to `client_service` + - Fix tests + - Fix cli signer ([#8682](https://github.com/paritytech/parity/pull/8682)) + - Update ethereum-types so `{:#x}` applies 0x prefix + - Set the request index to that of the current request ([#8683](https://github.com/paritytech/parity/pull/8683)) + - Set the request index to that of the current request + - Network-devp2p: handle UselessPeer disconnect ([#8686](https://github.com/paritytech/parity/pull/8686)) + - Fix local transactions policy. ([#8691](https://github.com/paritytech/parity/pull/8691)) + - CI: Fixes for Android Pipeline ([#8745](https://github.com/paritytech/parity/pull/8745)) + - Ci: Remove check for shared libraries in gitlab script + - Ci: allow android arm build to fail + - Custom Error Messages on ENFILE and EMFILE IO Errors ([#8744](https://github.com/paritytech/parity/pull/8744)) + - Custom Error Messages on ENFILE and EMFILE IO Errors + - Use assert-matches for more readable tests + - Fix Wording and consistency + - Ethcore-sync: fix connection to peers behind chain fork block ([#8710](https://github.com/paritytech/parity/pull/8710)) +- Parity-version: bump beta to 1.11.2 ([#8750](https://github.com/paritytech/parity/pull/8750)) + - Parity-version: bump beta to 1.11.2 + - Parity-version: unset critical flag + +## Parity [v1.11.1](https://github.com/paritytech/parity/releases/tag/v1.11.1) (2018-05-15) + +This is the Parity 1.11.1-beta release! Hurray! + +Notable changes in reversed alphabetical order: + +- TOOLING: **Whisper CLI** [#8201](https://github.com/paritytech/parity/pull/8201) + - `whisper-cli` is a standalone tool to communicate with the Whisper protocol. + - It provides functionality to specify `whisper-pool-size`, `port` and `address` to use. + - All whisper RPC APIs are enabled and can be directly accessed. +- JSON-RPC API: **Return error in case eth_call returns VM errors** [#8448](https://github.com/paritytech/parity/pull/8448) + - This changes the behaviors of `eth_call` to respect VM errors if any. + - In case of `REVERT`, it will also return the reverted return data in hex format. +- ENGINES: **Block Reward Contract** [#8419](https://github.com/paritytech/parity/pull/8419) + - The _AuRa_ PoA engine has now support for having a contract to calculate the block rewards. + - The engine passes a list of benefactors and reward types to the contract which then returns a list of addresses and respective rewards. +- CORE: **Private Transactions** [#6422](https://github.com/paritytech/parity/pull/6422) + - Parity now provides a private transactions system. + - Please, check out our wiki to get an [overview and setup instructions](https://wiki.parity.io/Private-Transactions.html). +- CORE: **New Transaction Queue implementation** [#8074](https://github.com/paritytech/parity/pull/8074) + - Verification is now done in parallel. + - Previous queue had `O(1)` time to get pending set, but `O(n^2)` insertion time. And obviously insertion/removal happens much more often than retrieving the pending set (only for propagation and pending block building) Currently we have `O(n * log(senders))` pending set time (with cache) and `O(tx_per_sender)` (usually within `log(tx_per_sender)`) insertion time. + - `Scoring` and `Readiness` are separated from the pool, so it's easier to customize them or introduce different definitions (for instance for [EIP-859](https://github.com/ethereum/EIPs/issues/859) or private transactions, etc). + - Banning removed, soft-penalization introduced instead: if transaction exceeds the limit other transactions from that sender get lower priority. + - There is no explicit distinction between current and future transactions in the pool - `Readiness` determines that. Because of this we additionally remove `future` transactions that occupy the pool for long time. +- CONFIGURATION: **Warp-only sync with --warp-barrier [block-number] flag.** [#8228](https://github.com/paritytech/parity/pull/8228) + - Enables warp-only sync in case `--warp-barrier [block-number]` is provided. + - This avoids clients to warp to outdated snapshots that are too far away from the best block. + - This avoids clients to fall back to normal sync if there are no recent snapshots available currently. +- CONFIGURATION: **Disable UI by default.** [#8105](https://github.com/paritytech/parity/pull/8105) + - The user interface is now disabled by default. It still can be activated with the `--force-ui` flag. + - To get the stand-alone Parity UI, please check the dedicated [releases page](https://github.com/parity-js/shell/releases). +- CONFIGURATION: **Auto-updater improvements** [#8078](https://github.com/paritytech/parity/pull/8078) + - Added `--auto-update-delay` to randomly delay updates by `n` blocks. This takes into account the number of the block of the update release (old updates aren't delayed). + - Added `--auto-update-check-frequency` to define the periodicity of auto-update checks in number of blocks. + - This is an important improvement to ensure the network does not update all clients at the same time. +- CHAIN SPECS: **Enable WebAssembly and Byzantium for Ellaism** [#8520](https://github.com/paritytech/parity/pull/8520) + - This activates the Ellaism Byzantium hardfork ([2018-0004-byzantium](https://github.com/ellaism/specs/blob/master/specs/2018-0004-byzantium.md)) at block `2_000_000`. + - This enables the Wasm VM on Ellaism ([2018-0003-wasm-hardfork](https://github.com/ellaism/specs/blob/master/specs/2018-0003-wasm-hardfork.md)) at block `2_000_000`. + - Please, upgrade your clients if you run an Ellaism configuration. +- CHAIN SPECS: **Dev chain - increase gasLimit to 8_000_000** [#8362](https://github.com/paritytech/parity/pull/8362) + - This increases the default block gas limit on development chains to `8_000_000`. + - Please note, this makes previous dev chain configurations incompatible. +- CHAIN SPECS: **Add MCIP-6 Byzyantium transition to Musicoin spec** [#7841](https://github.com/paritytech/parity/pull/7841) + - This activates the Musicoin Byzantium hardfork ([MCIP-6](https://github.com/Musicoin/MCIPs/blob/master/MCIPS/mcip-6.md)) at block `2_222_222`. + - Please, upgrade your clients if you run a Musicoin configuration. + +The full list of included changes: + +- Backports ([#8624](https://github.com/paritytech/parity/pull/8624)) + - Trace precompiled contracts when the transfer value is not zero ([#8486](https://github.com/paritytech/parity/pull/8486)) + - Trace precompiled contracts when the transfer value is not zero + - Add tests for precompiled CALL tracing + - Use byzantium test machine for the new test + - Add notes in comments on why we don't trace all precompiles + - Use is_transferred instead of transferred + - Return error if RLP size of transaction exceeds the limit ([#8473](https://github.com/paritytech/parity/pull/8473)) + - Return error if RLP size of transaction exceeds the limit + - Review comments fixed + - RLP check moved to verifier, corresponding pool test added + - Don't block sync when importing old blocks ([#8530](https://github.com/paritytech/parity/pull/8530)) + - Alter IO queueing. + - Don't require IoMessages to be Clone + - Ancient blocks imported via IoChannel. + - Get rid of private transactions io message. + - Get rid of deadlock and fix disconnected handler. + - Revert to old disconnect condition. + - Fix tests. + - Fix deadlock. + - Refactoring `ethcore-sync` - Fixing warp-sync barrier ([#8543](https://github.com/paritytech/parity/pull/8543)) + - Start dividing sync chain : first supplier method + - WIP - updated chain sync supplier + - Finish refactoring the Chain Sync Supplier + - Create Chain Sync Requester + - Add Propagator for Chain Sync + - Add the Chain Sync Handler + - Move tests from mod -> handler + - Move tests to propagator + - Refactor SyncRequester arguments + - Refactoring peer fork header handler + - Fix wrong highest block number in snapshot sync + - Small refactor... + - Address PR grumbles + - Retry failed CI job + - Fix tests + - PR Grumbles + - Handle socket address parsing errors ([#8545](https://github.com/paritytech/parity/pull/8545)) + - Fix packet count when talking with PAR2 peers ([#8555](https://github.com/paritytech/parity/pull/8555)) + - Support diferent packet counts in different protocol versions. + - Fix light timeouts and eclipse protection. + - Fix devp2p tests. + - Fix whisper-cli compilation. + - Fix compilation. + - Fix ethcore-sync tests. + - Revert "Fix light timeouts and eclipse protection." + - Increase timeouts. + - Add whisper CLI to the pipelines ([#8578](https://github.com/paritytech/parity/pull/8578)) + - Add whisper CLI to the pipelines + - Address todo, ref [#8579](https://github.com/paritytech/parity/pull/8579) + - Rename `whisper-cli binary` to `whisper` ([#8579](https://github.com/paritytech/parity/pull/8579)) + - Rename whisper-cli binary to whisper + - Fix tests + - Remove manually added text to the errors ([#8595](https://github.com/paritytech/parity/pull/8595)) + - Fix account list double 0x display ([#8596](https://github.com/paritytech/parity/pull/8596)) + - Remove unused self import + - Fix account list double 0x display + - Fix BlockReward contract "arithmetic operation overflow" ([#8611](https://github.com/paritytech/parity/pull/8611)) + - Fix BlockReward contract "arithmetic operation overflow" + - Add docs on how execute_as_system works + - Fix typo + - Rlp decode returns Result ([#8527](https://github.com/paritytech/parity/pull/8527)) + - Remove expect ([#8536](https://github.com/paritytech/parity/pull/8536)) + - Remove expect and propagate rlp::DecoderErrors as TrieErrors + - Decoding headers can fail ([#8570](https://github.com/paritytech/parity/pull/8570)) + - Rlp::decode returns Result + - Fix journaldb to handle rlp::decode Result + - Fix ethcore to work with rlp::decode returning Result + - Light client handles rlp::decode returning Result + - Fix tests in rlp_derive + - Fix tests + - Cleanup + - Cleanup + - Allow panic rather than breaking out of iterator + - Let decoding failures when reading from disk blow up + - Syntax + - Fix the trivial grumbles + - Fix failing tests + - Make Account::from_rlp return Result + - Syntx, sigh + - Temp-fix for decoding failures + - Header::decode returns Result + - Do not continue reading from the DB when a value could not be read + - Fix tests + - Handle header decoding in light_sync + - Handling header decoding errors + - Let the DecodeError bubble up unchanged + - Remove redundant error conversion + - Fix compiler warning ([#8590](https://github.com/paritytech/parity/pull/8590)) + - Attempt to fix intermittent test failures ([#8584](https://github.com/paritytech/parity/pull/8584)) + - Block_header can fail so return Result ([#8581](https://github.com/paritytech/parity/pull/8581)) + - Block_header can fail so return Result + - Restore previous return type based on feedback + - Fix failing doc tests running on non-code + - Block::decode() returns Result ([#8586](https://github.com/paritytech/parity/pull/8586)) + - Gitlab test script fixes ([#8573](https://github.com/paritytech/parity/pull/8573)) + - Exclude /docs from modified files. + - Ensure all references in the working tree are available + - Remove duplicated line from test script +- Bump beta to 1.11.1 ([#8627](https://github.com/paritytech/parity/pull/8627)) + +## Parity [v1.11.0](https://github.com/paritytech/parity/releases/tag/v1.11.0) (2018-05-09) + +This is the Parity 1.11.0-beta release! ~~Hurray!~~ This release has been pulled due to peering issues, please use 1.11.1-beta. + +The full list of included changes: + +- Backports ([#8558](https://github.com/paritytech/parity/pull/8558)) + - Fetching logs by hash in blockchain database ([#8463](https://github.com/paritytech/parity/pull/8463)) + - Fetch logs by hash in blockchain database + - Fix tests + - Add unit test for branch block logs fetching + - Add docs that blocks must already be sorted + - Handle branch block cases properly + - typo: empty -> is_empty + - Remove return_empty_if_none by using a closure + - Use BTreeSet to avoid sorting again + - Move is_canon to BlockChain + - typo: pass value by reference + - Use loop and wrap inside blocks to simplify the code + - typo: missed a comment + - Pass on storage keys tracing to handle the case when it is not modified ([#8491](https://github.com/paritytech/parity/pull/8491)) + - Pass on storage keys even if it is not modified + - typo: account and storage query + - Fix tests + - Use state query directly because of suicided accounts + - Fix a RefCell borrow issue + - Add tests for unmodified storage trace + - Address grumbles + - typo: remove unwanted empty line + - ensure_cached compiles with the original signature + - Update wasmi and pwasm-utils ([#8493](https://github.com/paritytech/parity/pull/8493)) + - Update wasmi to 0.2 + - Update pwasm-utils to 0.1.5 + - Show imported messages for light client ([#8517](https://github.com/paritytech/parity/pull/8517)) + - Enable WebAssembly and Byzantium for Ellaism ([#8520](https://github.com/paritytech/parity/pull/8520)) + - Enable WebAssembly and Byzantium for Ellaism + - Fix indentation + - Remove empty lines + - Don't panic in import_block if invalid rlp ([#8522](https://github.com/paritytech/parity/pull/8522)) + - Don't panic in import_block if invalid rlp + - Remove redundant type annotation + - Replace RLP header view usage with safe decoding + - Node table sorting according to last contact data ([#8541](https://github.com/paritytech/parity/pull/8541)) + - network-devp2p: sort nodes in node table using last contact data + - network-devp2p: rename node contact types in node table json output + - network-devp2p: fix node table tests + - network-devp2p: note node failure when failed to establish connection + - network-devp2p: handle UselessPeer error + - network-devp2p: note failure when marking node as useless +- Betalize 1.11 :) ([#8475](https://github.com/paritytech/parity/pull/8475)) + - Betalize 1.11 :) + - Update Gitlab scripts + - Use master as gitlab latest + - Fix snap builds ([#8483](https://github.com/paritytech/parity/pull/8483)) + - Update hardcodedSync for Ethereum, Kovan, and Ropsten ([#8489](https://github.com/paritytech/parity/pull/8489)) +- Fix typos in vm description comment ([#8446](https://github.com/paritytech/parity/pull/8446)) +- Add changelog for 1.9.7 and 1.10.2 ([#8460](https://github.com/paritytech/parity/pull/8460)) +- Fix docker build ([#8462](https://github.com/paritytech/parity/pull/8462)) +- Parityshell::open `Return result` ([#8377](https://github.com/paritytech/parity/pull/8377)) +- Return error in case eth_call returns VM errors ([#8448](https://github.com/paritytech/parity/pull/8448)) +- Update wasmi ([#8452](https://github.com/paritytech/parity/pull/8452)) +- Allow 32 bit pipelines to fail ([#8454](https://github.com/paritytech/parity/pull/8454)) +- Update Cargo hidapi-rs dependency ([#8447](https://github.com/paritytech/parity/pull/8447)) +- Private transactions processing error handling ([#8431](https://github.com/paritytech/parity/pull/8431)) +- Improve VM executor stack size estimation rules ([#8439](https://github.com/paritytech/parity/pull/8439)) +- Block reward contract ([#8419](https://github.com/paritytech/parity/pull/8419)) +- Permission fix ([#8441](https://github.com/paritytech/parity/pull/8441)) +- Use forked app_dirs crate for reverted Windows dir behavior ([#8438](https://github.com/paritytech/parity/pull/8438)) +- Remove From::from. ([#8390](https://github.com/paritytech/parity/pull/8390)) +- Move ethcore::Error to error_chain ([#8386](https://github.com/paritytech/parity/pull/8386)) +- Changelogs for 1.9.6 and 1.10.1 ([#8411](https://github.com/paritytech/parity/pull/8411)) +- Fix receipts stripping. ([#8414](https://github.com/paritytech/parity/pull/8414)) +- Typo, docs parity_chainId: empty string -> None ([#8434](https://github.com/paritytech/parity/pull/8434)) +- Update zip to 0.3 ([#8381](https://github.com/paritytech/parity/pull/8381)) +- Fix TODO comments ([#8413](https://github.com/paritytech/parity/pull/8413)) +- Replace legacy Rlp with UntrustedRlp and use in ethcore rlp views ([#8316](https://github.com/paritytech/parity/pull/8316)) +- Tokio-core v0.1.16 -> v0.1.17 ([#8408](https://github.com/paritytech/parity/pull/8408)) +- More code refactoring to integrate Duration ([#8322](https://github.com/paritytech/parity/pull/8322)) +- Remove Tendermint extra_info due to seal inconsistencies ([#8367](https://github.com/paritytech/parity/pull/8367)) +- Use tokio::spawn in secret_store listener and fix Uri ([#8373](https://github.com/paritytech/parity/pull/8373)) +- Unify and limit rocksdb dependency places ([#8371](https://github.com/paritytech/parity/pull/8371)) +- Clarify that windows need perl and yasm ([#8402](https://github.com/paritytech/parity/pull/8402)) +- New Transaction Queue implementation ([#8074](https://github.com/paritytech/parity/pull/8074)) +- Some tweaks to main.rs for parity as a library ([#8370](https://github.com/paritytech/parity/pull/8370)) +- Handle queue import errors a bit more gracefully ([#8385](https://github.com/paritytech/parity/pull/8385)) +- Ci: fix change detection in master builds ([#8382](https://github.com/paritytech/parity/pull/8382)) +- Fix config test by adding no-hardcodec-sync ([#8380](https://github.com/paritytech/parity/pull/8380)) +- Fixed unsafe shell call on windows ([#8372](https://github.com/paritytech/parity/pull/8372)) +- Parity uses winapi 0.3.4 ([#8366](https://github.com/paritytech/parity/pull/8366)) +- No hardcoded client name ([#8368](https://github.com/paritytech/parity/pull/8368)) +- Add `util/mem` to zero out memory on drop. ([#8356](https://github.com/paritytech/parity/pull/8356)) +- Use atty instead of isatty ([#8365](https://github.com/paritytech/parity/pull/8365)) +- Increase gasLimit to 8'000'000 ([#8362](https://github.com/paritytech/parity/pull/8362)) +- Util `fake-fetch` ([#8363](https://github.com/paritytech/parity/pull/8363)) +- Bump snappy and ring, use single rayon version, closes [#8296](https://github.com/paritytech/parity/issues/8296) ([#8364](https://github.com/paritytech/parity/pull/8364)) +- Use async hyper server in secret_store and upgrade igd ([#8359](https://github.com/paritytech/parity/pull/8359)) +- Enable UI by default, but only display deprecation notice ([#8262](https://github.com/paritytech/parity/pull/8262)) +- Ethcrypto renamed to ethcore-crypto and moved to ethcore dir ([#8340](https://github.com/paritytech/parity/pull/8340)) +- Use hyper 0.11 in ethcore-miner and improvements in parity-reactor ([#8335](https://github.com/paritytech/parity/pull/8335)) +- Ethcore-sync ([#8347](https://github.com/paritytech/parity/pull/8347)) +- Rpc, eth_filter: return error if the filter id does not exist ([#8341](https://github.com/paritytech/parity/pull/8341)) +- Ethcore-stratum crate moved to ethcore directory ([#8338](https://github.com/paritytech/parity/pull/8338)) +- Secretstore: get rid of engine.signer dependency ([#8173](https://github.com/paritytech/parity/pull/8173)) +- Whisper cli ([#8201](https://github.com/paritytech/parity/pull/8201)) +- Replace_home for password_files, reserved_peers and log_file ([#8324](https://github.com/paritytech/parity/pull/8324)) +- Add Ethereum Social support ([#8325](https://github.com/paritytech/parity/pull/8325)) +- Private transactions integration pr ([#6422](https://github.com/paritytech/parity/pull/6422)) +- Decouple rocksdb dependency from ethcore ([#8320](https://github.com/paritytech/parity/pull/8320)) +- Remove the clone operation of code_cache ([#8334](https://github.com/paritytech/parity/pull/8334)) +- Fix the JSONRPC API not running with the light client ([#8326](https://github.com/paritytech/parity/pull/8326)) +- Read registry_address from block with REQUEST_CONFIRMATIONS_REQUIRED ([#8309](https://github.com/paritytech/parity/pull/8309)) +- Tweaks and add a Dockerfile for Android ([#8036](https://github.com/paritytech/parity/pull/8036)) +- Use associated type M::Error instead of Error ([#8308](https://github.com/paritytech/parity/pull/8308)) +- Remove InvalidParentHash in favor of assert! ([#8300](https://github.com/paritytech/parity/pull/8300)) +- Bump proc macro deps ([#8310](https://github.com/paritytech/parity/pull/8310)) +- Decouple timestamp open-block-assignment/verification to Engine ([#8305](https://github.com/paritytech/parity/pull/8305)) +- Validate if gas limit is not zero ([#8307](https://github.com/paritytech/parity/pull/8307)) +- Implement Easthub chain spec ([#8295](https://github.com/paritytech/parity/pull/8295)) +- Update some dependencies ([#8285](https://github.com/paritytech/parity/pull/8285)) +- Ethcore now uses Rayon 1.0 as a dependency ([#8296](https://github.com/paritytech/parity/pull/8296)) ([#8304](https://github.com/paritytech/parity/pull/8304)) +- Upgrader `remove raw unwrap` and bump semver ([#8251](https://github.com/paritytech/parity/pull/8251)) +- Cleaner binary shutdown system ([#8284](https://github.com/paritytech/parity/pull/8284)) +- Ethcore now uses rayon to 0.9 as a dependency ([#8296](https://github.com/paritytech/parity/pull/8296)) ([#8302](https://github.com/paritytech/parity/pull/8302)) +- Include suicided accounts in state diff ([#8297](https://github.com/paritytech/parity/pull/8297)) +- Remove evmjit ([#8229](https://github.com/paritytech/parity/pull/8229)) +- Build: fix updater rand dependency in Cargo.lock ([#8298](https://github.com/paritytech/parity/pull/8298)) +- Honor --max-peers if --min-peers is not specified ([#8087](https://github.com/paritytech/parity/pull/8087)) +- Auto-updater improvements ([#8078](https://github.com/paritytech/parity/pull/8078)) +- Dapps-fetcher: calculate keccak in-flight while reading the response ([#8294](https://github.com/paritytech/parity/pull/8294)) +- Cleanup Ellaism bootnodes ([#8276](https://github.com/paritytech/parity/pull/8276)) +- Allow unsafe js eval on Parity Wallet. ([#8204](https://github.com/paritytech/parity/pull/8204)) +- Remove RefCell from Header ([#8227](https://github.com/paritytech/parity/pull/8227)) +- Typo fix: todo with no content ([#8292](https://github.com/paritytech/parity/pull/8292)) +- Revert "ci: disable link-dead-code in coverage build ([#8118](https://github.com/paritytech/parity/pull/8118))" ([#8287](https://github.com/paritytech/parity/pull/8287)) +- Bump ethabi & ethereum-types. ([#8258](https://github.com/paritytech/parity/pull/8258)) +- Allow customization of max WS connections. ([#8257](https://github.com/paritytech/parity/pull/8257)) +- Supress TemporaryInvalid verification failures. ([#8256](https://github.com/paritytech/parity/pull/8256)) +- Return null number for pending block in eth_getBlockByNumber ([#8281](https://github.com/paritytech/parity/pull/8281)) +- Use constant durations ([#8278](https://github.com/paritytech/parity/pull/8278)) +- Typo fix: Mode doc - RLP should be client ([#8283](https://github.com/paritytech/parity/pull/8283)) +- Eth_uninstallfilter should return false for non-existent filter ([#8280](https://github.com/paritytech/parity/pull/8280)) +- Update `app_dirs` to 1.2.1 ([#8268](https://github.com/paritytech/parity/pull/8268)) +- Add missing license header for runtime.rs ([#8252](https://github.com/paritytech/parity/pull/8252)) +- Warp-only sync with warp-barrier [blocknumber] flag. ([#8228](https://github.com/paritytech/parity/pull/8228)) +- Replace all Rlp usages with UntrustedRlp except for ethcore views ([#8233](https://github.com/paritytech/parity/pull/8233)) +- Add test for ethstore-cli, fixes [#8027](https://github.com/paritytech/parity/issues/8027) ([#8187](https://github.com/paritytech/parity/pull/8187)) +- Update musicoin spec in line with gmc v2.6.2 ([#8242](https://github.com/paritytech/parity/pull/8242)) +- Fixed ethcore tx_filter ([#8200](https://github.com/paritytech/parity/pull/8200)) +- Update CLI help for jsonrpc-apis, ws-apis and ipc-apis ([#8234](https://github.com/paritytech/parity/pull/8234)) +- Remove network stats ([#8225](https://github.com/paritytech/parity/pull/8225)) +- Node-filter does not use ChainNotify ([#8231](https://github.com/paritytech/parity/pull/8231)) +- Implement hardcoded sync in the light client ([#8075](https://github.com/paritytech/parity/pull/8075)) +- Update some of the dependencies for WASM ([#8223](https://github.com/paritytech/parity/pull/8223)) +- Bump wasmi version ([#8209](https://github.com/paritytech/parity/pull/8209)) +- Updated jsonrpc to point to the 1.11 branch ([#8180](https://github.com/paritytech/parity/pull/8180)) +- Change name Wallet -> UI ([#8164](https://github.com/paritytech/parity/pull/8164)) +- Introduce Parity UI ([#8202](https://github.com/paritytech/parity/pull/8202)) +- Update Changelogs ([#8175](https://github.com/paritytech/parity/pull/8175)) +- Returns number of topcis to take fr.. ([#8199](https://github.com/paritytech/parity/pull/8199)) +- Make docopt usage non-const ([#8189](https://github.com/paritytech/parity/pull/8189)) +- Avoid allocations when computing triehash. ([#8176](https://github.com/paritytech/parity/pull/8176)) +- Handle rlp decoding Result in patricia trie ([#8166](https://github.com/paritytech/parity/pull/8166)) +- Bump wasm libs ([#8171](https://github.com/paritytech/parity/pull/8171)) +- Re-enable signer, even with no UI. ([#8167](https://github.com/paritytech/parity/pull/8167)) +- Update daemonize ([#8165](https://github.com/paritytech/parity/pull/8165)) +- Some tiny modifications. ([#8163](https://github.com/paritytech/parity/pull/8163)) +- Secretstore: store key author address in db ([#7887](https://github.com/paritytech/parity/pull/7887)) +- Rename DatabaseValueView::new to from_rlp ([#8159](https://github.com/paritytech/parity/pull/8159)) +- Dapps: update parity-ui dependencies ([#8160](https://github.com/paritytech/parity/pull/8160)) +- Disable UI by default. ([#8105](https://github.com/paritytech/parity/pull/8105)) +- Fix wasmi x32 builds ([#8155](https://github.com/paritytech/parity/pull/8155)) +- Postpone Kovan hard fork ([#8137](https://github.com/paritytech/parity/pull/8137)) +- Secretstore: ability to identify requester via Public/Address ([#7886](https://github.com/paritytech/parity/pull/7886)) +- Optional dependency on secp256k1 for ethcrypto ([#8109](https://github.com/paritytech/parity/pull/8109)) +- Network: init discovery using healthy nodes ([#8061](https://github.com/paritytech/parity/pull/8061)) +- Check one step deeper if we're on release track branches ([#8134](https://github.com/paritytech/parity/pull/8134)) +- Explicitly mention pruning_history uses RAM ([#8130](https://github.com/paritytech/parity/pull/8130)) +- Remove `ethcrypto::{en,de}crypt_single_message`. ([#8126](https://github.com/paritytech/parity/pull/8126)) +- Fix typo ([#8124](https://github.com/paritytech/parity/pull/8124)) +- Secret_store: use `ecies::encrypt`/`ecies::decrypt`. ([#8125](https://github.com/paritytech/parity/pull/8125)) +- Fix comment for fn gas() in wasm/runtime ([#8122](https://github.com/paritytech/parity/pull/8122)) +- Structured rlp encoding in journaldb ([#8047](https://github.com/paritytech/parity/pull/8047)) +- Ci: disable link-dead-code in coverage build ([#8118](https://github.com/paritytech/parity/pull/8118)) +- Fix trace filter returning returning unrelated reward calls, closes [#8070](https://github.com/paritytech/parity/issues/8070) ([#8098](https://github.com/paritytech/parity/pull/8098)) +- Const time comparison ([#8113](https://github.com/paritytech/parity/pull/8113)) +- Replace reqwest with hyper ([#8099](https://github.com/paritytech/parity/pull/8099)) +- More dos protection ([#8104](https://github.com/paritytech/parity/pull/8104)) +- Remove the time dependency where possible ([#8100](https://github.com/paritytech/parity/pull/8100)) +- Fix comment for gas extern in Wasm runtime ([#8101](https://github.com/paritytech/parity/pull/8101)) +- Replace std::env::temp_dir with tempdir in tests ([#8103](https://github.com/paritytech/parity/pull/8103)) +- Fix Cargo.lock not parsable ([#8102](https://github.com/paritytech/parity/pull/8102)) +- Additional data in EVMTestClient ([#7964](https://github.com/paritytech/parity/pull/7964)) +- Update serde, serde-derive, ethabi-derive, syn, quote and rlp_derive ([#8085](https://github.com/paritytech/parity/pull/8085)) +- Ethcore-service ([#8089](https://github.com/paritytech/parity/pull/8089)) +- [contract-client] refactor ([#7978](https://github.com/paritytech/parity/pull/7978)) +- Revert removing blooms ([#8066](https://github.com/paritytech/parity/pull/8066)) +- Ethcore test::helpers cleanup ([#8086](https://github.com/paritytech/parity/pull/8086)) +- Add some dos protection ([#8084](https://github.com/paritytech/parity/pull/8084)) +- Wasm libraries bump ([#7970](https://github.com/paritytech/parity/pull/7970)) +- Echo back the message hash of a ping in the pong request ([#8042](https://github.com/paritytech/parity/pull/8042)) +- Add Kovan WASM activation blocknumber ([#8057](https://github.com/paritytech/parity/pull/8057)) +- [ethkey] Unify debug/display for Address/Public/Secret ([#8076](https://github.com/paritytech/parity/pull/8076)) +- Limit incoming connections. ([#8060](https://github.com/paritytech/parity/pull/8060)) +- Max code size on Kovan ([#8067](https://github.com/paritytech/parity/pull/8067)) +- Updater: apply exponential backoff after download failure ([#8059](https://github.com/paritytech/parity/pull/8059)) +- Make blockchain functions more idiomatic, avoid needless writes to cache_man ([#8054](https://github.com/paritytech/parity/pull/8054)) +- Make patricia-trie more idiomatic and remove redundant code ([#8056](https://github.com/paritytech/parity/pull/8056)) +- Abstract devp2p ([#8048](https://github.com/paritytech/parity/pull/8048)) +- Update refs to shell ([#8051](https://github.com/paritytech/parity/pull/8051)) +- Fix cache & snapcraft CI build ([#8052](https://github.com/paritytech/parity/pull/8052)) +- Prelude to the block module cleanup ([#8025](https://github.com/paritytech/parity/pull/8025)) +- Add MCIP-6 Byzyantium transition to Musicoin spec ([#7841](https://github.com/paritytech/parity/pull/7841)) +- Bump master to 1.11.0 ([#8021](https://github.com/paritytech/parity/pull/8021)) +- `client` refactoring ([#7038](https://github.com/paritytech/parity/pull/7038)) +- [hardware wallet] sleeping -> pollling ([#8018](https://github.com/paritytech/parity/pull/8018)) +- Fixed broken link in README ([#8012](https://github.com/paritytech/parity/pull/8012)) +- Support parity protocol. ([#8035](https://github.com/paritytech/parity/pull/8035)) +- Add changelog for 1.8.11 stable and 1.9.4 beta ([#8017](https://github.com/paritytech/parity/pull/8017)) +- Fix for verify_block_basic crashing on invalid transaction rlp ([#8032](https://github.com/paritytech/parity/pull/8032)) +- Extract the hard dependency on rocksdb from the light client ([#8034](https://github.com/paritytech/parity/pull/8034)) +- Fixed parsing ethash seals and verify_block_undordered ([#8031](https://github.com/paritytech/parity/pull/8031)) +- Fixed ethstore sign ([#8026](https://github.com/paritytech/parity/pull/8026)) +- Ci: Fix cargo cache ([#7968](https://github.com/paritytech/parity/pull/7968)) +- Update ref to new shell ([#8024](https://github.com/paritytech/parity/pull/8024)) diff --git a/ethash/Cargo.toml b/ethash/Cargo.toml index 4bb1b50470ed9de363c7126833b225b8d03306e1..df0f17e0f371d4568036d17d818462b89db49062 100644 --- a/ethash/Cargo.toml +++ b/ethash/Cargo.toml @@ -7,9 +7,9 @@ authors = ["Parity Technologies "] [dependencies] log = "0.3" -keccak-hash = { path = "../util/hash" } +keccak-hash = { git = "https://github.com/paritytech/parity-common" } 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 eef426bcf1b95ad7fe5904f4689ab3d90c42a9e3..023e4bb468fa383ce0021beaf0bba8fa30551ddd 100644 --- a/ethash/src/cache.rs +++ b/ethash/src/cache.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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/compute.rs b/ethash/src/compute.rs index de2b57637fae577f7c98366ad5acada1b52cacef..69211f244875ebc045269af25f26e7bf65e7dad2 100644 --- a/ethash/src/compute.rs +++ b/ethash/src/compute.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -137,11 +137,11 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64) ($n:expr, $value:expr) => {{ // We use explicit lifetimes to ensure that val's borrow is invalidated until the // transmuted val dies. - unsafe fn make_const_array<'a, T, U>(val: &'a mut [T]) -> &'a mut [U; $n] { + unsafe fn make_const_array(val: &mut [T]) -> &mut [U; $n] { use ::std::mem; debug_assert_eq!(val.len() * mem::size_of::(), $n * mem::size_of::()); - mem::transmute(val.as_mut_ptr()) + &mut *(val.as_mut_ptr() as *mut [U; $n]) } make_const_array($value) @@ -177,7 +177,7 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64) ptr::copy_nonoverlapping(header_hash.as_ptr(), out.as_mut_ptr(), header_hash.len()); ptr::copy_nonoverlapping( - mem::transmute(&nonce), + &nonce as *const u64 as *const u8, out[header_hash.len()..].as_mut_ptr(), mem::size_of::(), ); @@ -266,18 +266,20 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64) let mix_hash = buf.compress_bytes; - let value: H256 = unsafe { + let value: H256 = { // We can interpret the buffer as an array of `u8`s, since it's `repr(C)`. - let read_ptr: *const u8 = mem::transmute(&buf); + let read_ptr: *const u8 = &buf as *const MixBuf as *const u8; // We overwrite the second half since `keccak_256` has an internal buffer and so allows // overlapping arrays as input. - let write_ptr: *mut u8 = mem::transmute(&mut buf.compress_bytes); - keccak_256::unchecked( - write_ptr, - buf.compress_bytes.len(), - read_ptr, - buf.half_mix.bytes.len() + buf.compress_bytes.len(), - ); + let write_ptr: *mut u8 = &mut buf.compress_bytes as *mut [u8; 32] as *mut u8; + unsafe { + keccak_256::unchecked( + write_ptr, + buf.compress_bytes.len(), + read_ptr, + buf.half_mix.bytes.len() + buf.compress_bytes.len(), + ); + } buf.compress_bytes }; diff --git a/ethash/src/keccak.rs b/ethash/src/keccak.rs index 36fb17354704f4af74ffddcf8ff584fb683dc64d..ab6be94dcaac31519102381a636696f679645eca 100644 --- a/ethash/src/keccak.rs +++ b/ethash/src/keccak.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethash/src/lib.rs b/ethash/src/lib.rs index 9d0c669d9c8c7454774d132699b4196d3a31b915..69b5a1d11551d5ac1815c0f02a45ab6ce67bc169 100644 --- a/ethash/src/lib.rs +++ b/ethash/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethash/src/seed_compute.rs b/ethash/src/seed_compute.rs index 04774b3e39e507609c54db43ee1bccd0ca972e8a..7a3f89b9b5d414a2f341cecd12fa164f1265a51a 100644 --- a/ethash/src/seed_compute.rs +++ b/ethash/src/seed_compute.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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/ethash/src/shared.rs b/ethash/src/shared.rs index 39e1c8eb88479513b64de007d8b8ed4b2e76b7bf..90969c522254a48fd2dcbee3a5942fee7f30229b 100644 --- a/ethash/src/shared.rs +++ b/ethash/src/shared.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 71c84a293f9070799dd12b7f108d428e895bf7a5..82dd2230dd6d2c6f5afc80da5b8b8a7ef1bf51b4 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -8,24 +8,24 @@ authors = ["Parity Technologies "] [dependencies] ansi_term = "0.10" -bloomchain = { path = "../util/bloomchain" } +blooms-db = { path = "../util/blooms-db" } bn = { git = "https://github.com/paritytech/bn", default-features = false } byteorder = "1.0" common-types = { path = "types" } 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" } -ethcore-crypto = { path = "crypto" } -error-chain = { version = "0.11", default-features = false } +parity-bytes = { git = "https://github.com/paritytech/parity-common" } +hashdb = { git = "https://github.com/paritytech/parity-common" } +memorydb = { git = "https://github.com/paritytech/parity-common" } +patricia-trie = { git = "https://github.com/paritytech/parity-common" } +patricia-trie-ethereum = { path = "../util/patricia-trie-ethereum" } +parity-crypto = { git = "https://github.com/paritytech/parity-common" } +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" } @@ -36,7 +36,6 @@ ethjson = { path = "../json" } ethkey = { path = "../ethkey" } ethstore = { path = "../ethstore" } evm = { path = "evm" } -hardware-wallet = { path = "../hw" } heapsize = "0.4" itertools = "0.5" lazy_static = "1.0" @@ -45,15 +44,14 @@ 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" } +rlp = { git = "https://github.com/paritytech/parity-common" } 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" } +kvdb = { git = "https://github.com/paritytech/parity-common" } +kvdb-memorydb = { git = "https://github.com/paritytech/parity-common" } snappy = { git = "https://github.com/paritytech/rust-snappy" } stop-guard = { path = "../util/stop-guard" } macros = { path = "../util/macros" } @@ -63,19 +61,38 @@ trace-time = { path = "../util/trace-time" } using_queue = { path = "../util/using_queue" } vm = { path = "vm" } wasm = { path = "wasm" } -keccak-hash = { path = "../util/hash" } -triehash = { path = "../util/triehash" } +keccak-hash = { git = "https://github.com/paritytech/parity-common" } +triehash-ethereum = { version = "0.2", path = "../util/triehash-ethereum" } unexpected = { path = "../util/unexpected" } journaldb = { path = "../util/journaldb" } +keccak-hasher = { path = "../util/keccak-hasher" } +kvdb-rocksdb = { git = "https://github.com/paritytech/parity-common" } +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" } + +[target.'cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))'.dependencies] +fake-hardware-wallet = { path = "../util/fake-hardware-wallet" } [dev-dependencies] tempdir = "0.3" -trie-standardmap = { path = "../util/trie-standardmap" } -kvdb-rocksdb = { path = "../util/kvdb-rocksdb" } +trie-standardmap = { git = "https://github.com/paritytech/parity-common" } [features] +parity = ["work-notify", "price-info", "stratum"] +# Large optional features that are enabled by default for Parity, +# but might be omitted for other dependent crates. +work-notify = ["ethcore-miner/work-notify"] +price-info = ["ethcore-miner/price-info"] +stratum = ["ethcore-stratum"] + +# Disables seal verification for mined blocks. +# This allows you to submit any seal via RPC to test and benchmark +# how fast pending block get's created while running on the mainnet. +miner-debug = [] # Display EVM debug traces. -evm-debug = ["slow-blocks"] +evm-debug = ["evm/evm-debug"] # Display EVM debug traces when running tests. evm-debug-tests = ["evm-debug", "evm/evm-debug-tests"] # Measure time of transaction execution. @@ -84,8 +101,10 @@ evm-debug-tests = ["evm-debug", "evm/evm-debug-tests"] # EVM debug traces are printed. slow-blocks = [] # Run JSON consensus tests. -json-tests = ["ethcore-transaction/json-tests"] +json-tests = ["ethcore-transaction/json-tests", "test-helpers", "tempdir"] # Run memory/cpu heavy tests. test-heavy = [] # Compile benches benches = [] +# Compile test helpers +test-helpers = ["tempdir"] diff --git a/ethcore/benches/builtin.rs b/ethcore/benches/builtin.rs new file mode 100644 index 0000000000000000000000000000000000000000..11df5028df9f1798c0dc75c40cd5464d016e5084 --- /dev/null +++ b/ethcore/benches/builtin.rs @@ -0,0 +1,658 @@ +// 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 test; + +#[macro_use] +extern crate lazy_static; + +extern crate ethcore; +extern crate ethereum_types; +extern crate parity_bytes as bytes; +extern crate rustc_hex; + +use std::collections::BTreeMap; + +use bytes::BytesRef; +use ethcore::builtin::Builtin; +use ethcore::machine::EthereumMachine; +use ethereum_types::{Address, U256}; +use ethcore::ethereum::new_byzantium_test_machine; +use rustc_hex::FromHex; +use self::test::Bencher; + +lazy_static! { + static ref BYZANTIUM_MACHINE: EthereumMachine = new_byzantium_test_machine(); +} + +struct BuiltinBenchmark<'a> { + builtin: &'a Builtin, + input: Vec, + expected: Vec, +} + +impl<'a> BuiltinBenchmark<'a> { + fn new(builtin_address: &'static str, input: &str, expected: &str) -> BuiltinBenchmark<'a> { + let builtins = BYZANTIUM_MACHINE.builtins(); + + let builtin = builtins.get(&builtin_address.into()).unwrap().clone(); + let input = FromHex::from_hex(input).unwrap(); + let expected = FromHex::from_hex(expected).unwrap(); + + BuiltinBenchmark { + builtin, input, expected + } + } + + fn gas_cost(&self) -> U256 { + self.builtin.cost(&self.input) + } + + fn run(&self, b: &mut Bencher) { + let mut output = vec![0; self.expected.len()]; + + b.iter(|| { + self.builtin.execute(&self.input, &mut BytesRef::Fixed(&mut output)).unwrap(); + }); + + assert_eq!(self.expected[..], output[..]); + } +} + +fn bench( + builtin_address: &'static str, + input: &str, + expected: &str, + b: &mut Bencher, +) { + let bench = BuiltinBenchmark::new(builtin_address, input, expected); + + println!("gas cost: {}", bench.gas_cost()); + bench.run(b); +} + +#[bench] +fn ecrecover(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000001", // ecrecover + "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02", + "000000000000000000000000ceaccac640adf55b2028469bd36ba501f28b699d", + b, + ); +} + +#[bench] +fn sha256(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000002", // sha256 + "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02", + "811c7003375852fabd0d362e40e68607a12bdabae61a7d068fe5fdd1dbbf2a5d", + b, + ); +} + +#[bench] +fn ripemd(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000003", // ripemd + "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02", + "0000000000000000000000009215b8d9882ff46f0dfde6684d78e831467f65e6", + b, + ); +} + +#[bench] +fn identity(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000004", // identity + "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02", + "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02", + b, + ); +} + +#[bench] +fn modexp_eip_example1(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000005", // modexp + "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002003fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "0000000000000000000000000000000000000000000000000000000000000001", + b, + ); +} + +#[bench] +fn modexp_eip_example2(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000005", // modexp + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "0000000000000000000000000000000000000000000000000000000000000000", + b, + ); +} + +#[bench] +fn modexp_nagydani_1_square(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000005", // modexp + "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb502fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b", + "60008f1614cc01dcfb6bfb09c625cf90b47d4468db81b5f8b7a39d42f332eab9b2da8f2d95311648a8f243f4bb13cfb3d8f7f2a3c014122ebb3ed41b02783adc", + b, + ); +} + +#[bench] +fn modexp_nagydani_1_qube(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000005", // modexp + "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb503fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b", + "4834a46ba565db27903b1c720c9d593e84e4cbd6ad2e64b31885d944f68cd801f92225a8961c952ddf2797fa4701b330c85c4b363798100b921a1a22a46a7fec", + b, + ); +} + +#[bench] +fn modexp_nagydani_1_pow0x10001(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000005", // modexp + "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000040e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5010001fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b", + "c36d804180c35d4426b57b50c5bfcca5c01856d104564cd513b461d3c8b8409128a5573e416d0ebe38f5f736766d9dc27143e4da981dfa4d67f7dc474cbee6d2", + b, + ); +} + +#[bench] +fn modexp_nagydani_2_square(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000005", // modexp + "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf5102e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", + "981dd99c3b113fae3e3eaa9435c0dc96779a23c12a53d1084b4f67b0b053a27560f627b873e3f16ad78f28c94f14b6392def26e4d8896c5e3c984e50fa0b3aa44f1da78b913187c6128baa9340b1e9c9a0fd02cb78885e72576da4a8f7e5a113e173a7a2889fde9d407bd9f06eb05bc8fc7b4229377a32941a02bf4edcc06d70", + b, + ); +} + + +#[bench] +fn modexp_nagydani_2_qube(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000005", // modexp + "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf5103e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", + "d89ceb68c32da4f6364978d62aaa40d7b09b59ec61eb3c0159c87ec3a91037f7dc6967594e530a69d049b64adfa39c8fa208ea970cfe4b7bcd359d345744405afe1cbf761647e32b3184c7fbe87cee8c6c7ff3b378faba6c68b83b6889cb40f1603ee68c56b4c03d48c595c826c041112dc941878f8c5be828154afd4a16311f", + b, + ); +} + +#[bench] +fn modexp_nagydani_2_pow0x10001(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000005", // modexp + "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51010001e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", + "ad85e8ef13fd1dd46eae44af8b91ad1ccae5b7a1c92944f92a19f21b0b658139e0cabe9c1f679507c2de354bf2c91ebd965d1e633978a830d517d2f6f8dd5fd58065d58559de7e2334a878f8ec6992d9b9e77430d4764e863d77c0f87beede8f2f7f2ab2e7222f85cc9d98b8467f4bb72e87ef2882423ebdb6daf02dddac6db2", + b, + ); +} + +#[bench] +fn modexp_nagydani_3_square(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000005", // modexp + "000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb02d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", + "affc7507ea6d84751ec6b3f0d7b99dbcc263f33330e450d1b3ff0bc3d0874320bf4edd57debd587306988157958cb3cfd369cc0c9c198706f635c9e0f15d047df5cb44d03e2727f26b083c4ad8485080e1293f171c1ed52aef5993a5815c35108e848c951cf1e334490b4a539a139e57b68f44fee583306f5b85ffa57206b3ee5660458858534e5386b9584af3c7f67806e84c189d695e5eb96e1272d06ec2df5dc5fabc6e94b793718c60c36be0a4d031fc84cd658aa72294b2e16fc240aef70cb9e591248e38bd49c5a554d1afa01f38dab72733092f7555334bbef6c8c430119840492380aa95fa025dcf699f0a39669d812b0c6946b6091e6e235337b6f8", + b, + ); +} + +#[bench] +fn modexp_nagydani_3_qube(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000005", // modexp + "000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb03d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", + "1b280ecd6a6bf906b806d527c2a831e23b238f89da48449003a88ac3ac7150d6a5e9e6b3be4054c7da11dd1e470ec29a606f5115801b5bf53bc1900271d7c3ff3cd5ed790d1c219a9800437a689f2388ba1a11d68f6a8e5b74e9a3b1fac6ee85fc6afbac599f93c391f5dc82a759e3c6c0ab45ce3f5d25d9b0c1bf94cf701ea6466fc9a478dacc5754e593172b5111eeba88557048bceae401337cd4c1182ad9f700852bc8c99933a193f0b94cf1aedbefc48be3bc93ef5cb276d7c2d5462ac8bb0c8fe8923a1db2afe1c6b90d59c534994a6a633f0ead1d638fdc293486bb634ff2c8ec9e7297c04241a61c37e3ae95b11d53343d4ba2b4cc33d2cfa7eb705e", + b, + ); +} + +#[bench] +fn modexp_nagydani_3_pow0x10001(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000005", // modexp + "000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb010001d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", + "37843d7c67920b5f177372fa56e2a09117df585f81df8b300fba245b1175f488c99476019857198ed459ed8d9799c377330e49f4180c4bf8e8f66240c64f65ede93d601f957b95b83efdee1e1bfde74169ff77002eaf078c71815a9220c80b2e3b3ff22c2f358111d816ebf83c2999026b6de50bfc711ff68705d2f40b753424aefc9f70f08d908b5a20276ad613b4ab4309a3ea72f0c17ea9df6b3367d44fb3acab11c333909e02e81ea2ed404a712d3ea96bba87461720e2d98723e7acd0520ac1a5212dbedcd8dc0c1abf61d4719e319ff4758a774790b8d463cdfe131d1b2dcfee52d002694e98e720cb6ae7ccea353bc503269ba35f0f63bf8d7b672a76", + b, + ); +} + +#[bench] +fn modexp_nagydani_4_square(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000005", // modexp + "000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b8102df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", + "8a5aea5f50dcc03dc7a7a272b5aeebc040554dbc1ffe36753c4fc75f7ed5f6c2cc0de3a922bf96c78bf0643a73025ad21f45a4a5cadd717612c511ab2bff1190fe5f1ae05ba9f8fe3624de1de2a817da6072ddcdb933b50216811dbe6a9ca79d3a3c6b3a476b079fd0d05f04fb154e2dd3e5cb83b148a006f2bcbf0042efb2ae7b916ea81b27aac25c3bf9a8b6d35440062ad8eae34a83f3ffa2cc7b40346b62174a4422584f72f95316f6b2bee9ff232ba9739301c97c99a9ded26c45d72676eb856ad6ecc81d36a6de36d7f9dafafee11baa43a4b0d5e4ecffa7b9b7dcefd58c397dd373e6db4acd2b2c02717712e6289bed7c813b670c4a0c6735aa7f3b0f1ce556eae9fcc94b501b2c8781ba50a8c6220e8246371c3c7359fe4ef9da786ca7d98256754ca4e496be0a9174bedbecb384bdf470779186d6a833f068d2838a88d90ef3ad48ff963b67c39cc5a3ee123baf7bf3125f64e77af7f30e105d72c4b9b5b237ed251e4c122c6d8c1405e736299c3afd6db16a28c6a9cfa68241e53de4cd388271fe534a6a9b0dbea6171d170db1b89858468885d08fecbd54c8e471c3e25d48e97ba450b96d0d87e00ac732aaa0d3ce4309c1064bd8a4c0808a97e0143e43a24cfa847635125cd41c13e0574487963e9d725c01375db99c31da67b4cf65eff555f0c0ac416c727ff8d438ad7c42030551d68c2e7adda0abb1ca7c10", + b, + ); +} + +#[bench] +fn modexp_nagydani_4_qube(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000005", // modexp + "000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b8103df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", + "5a2664252aba2d6e19d9600da582cdd1f09d7a890ac48e6b8da15ae7c6ff1856fc67a841ac2314d283ffa3ca81a0ecf7c27d89ef91a5a893297928f5da0245c99645676b481b7e20a566ee6a4f2481942bee191deec5544600bb2441fd0fb19e2ee7d801ad8911c6b7750affec367a4b29a22942c0f5f4744a4e77a8b654da2a82571037099e9c6d930794efe5cdca73c7b6c0844e386bdca8ea01b3d7807146bb81365e2cdc6475f8c23e0ff84463126189dc9789f72bbce2e3d2d114d728a272f1345122de23df54c922ec7a16e5c2a8f84da8871482bd258c20a7c09bbcd64c7a96a51029bbfe848736a6ba7bf9d931a9b7de0bcaf3635034d4958b20ae9ab3a95a147b0421dd5f7ebff46c971010ebfc4adbbe0ad94d5498c853e7142c450d8c71de4b2f84edbf8acd2e16d00c8115b150b1c30e553dbb82635e781379fe2a56360420ff7e9f70cc64c00aba7e26ed13c7c19622865ae07248daced36416080f35f8cc157a857ed70ea4f347f17d1bee80fa038abd6e39b1ba06b97264388b21364f7c56e192d4b62d9b161405f32ab1e2594e86243e56fcf2cb30d21adef15b9940f91af681da24328c883d892670c6aa47940867a81830a82b82716895db810df1b834640abefb7db2092dd92912cb9a735175bc447be40a503cf22dfe565b4ed7a3293ca0dfd63a507430b323ee248ec82e843b673c97ad730728cebc", + b, + ); +} + +#[bench] +fn modexp_nagydani_4_pow0x10001(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000005", // modexp + "000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81010001df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", + "bed8b970c4a34849fc6926b08e40e20b21c15ed68d18f228904878d4370b56322d0da5789da0318768a374758e6375bfe4641fca5285ec7171828922160f48f5ca7efbfee4d5148612c38ad683ae4e3c3a053d2b7c098cf2b34f2cb19146eadd53c86b2d7ccf3d83b2c370bfb840913ee3879b1057a6b4e07e110b6bcd5e958bc71a14798c91d518cc70abee264b0d25a4110962a764b364ac0b0dd1ee8abc8426d775ec0f22b7e47b32576afaf1b5a48f64573ed1c5c29f50ab412188d9685307323d990802b81dacc06c6e05a1e901830ba9fcc67688dc29c5e27bde0a6e845ca925f5454b6fb3747edfaa2a5820838fb759eadf57f7cb5cec57fc213ddd8a4298fa079c3c0f472b07fb15aa6a7f0a3780bd296ff6a62e58ef443870b02260bd4fd2bbc98255674b8e1f1f9f8d33c7170b0ebbea4523b695911abbf26e41885344823bd0587115fdd83b721a4e8457a31c9a84b3d3520a07e0e35df7f48e5a9d534d0ec7feef1ff74de6a11e7f93eab95175b6ce22c68d78a642ad642837897ec11349205d8593ac19300207572c38d29ca5dfa03bc14cdbc32153c80e5cc3e739403d34c75915e49beb43094cc6dcafb3665b305ddec9286934ae66ec6b777ca528728c851318eb0f207b39f1caaf96db6eeead6b55ed08f451939314577d42bcc9f97c0b52d0234f88fd07e4c1d7780fdebc025cfffcb572cb27a8c33963", + b, + ); +} + +#[bench] +fn modexp_nagydani_5_square(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000005", // modexp + "000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf02e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", + "d61fe4e3f32ac260915b5b03b78a86d11bfc41d973fce5b0cc59035cf8289a8a2e3878ea15fa46565b0d806e2f85b53873ea20ed653869b688adf83f3ef444535bf91598ff7e80f334fb782539b92f39f55310cc4b35349ab7b278346eda9bc37c0d8acd3557fae38197f412f8d9e57ce6a76b7205c23564cab06e5615be7c6f05c3d05ec690cba91da5e89d55b152ff8dd2157dc5458190025cf94b1ad98f7cbe64e9482faba95e6b33844afc640892872b44a9932096508f4a782a4805323808f23e54b6ff9b841dbfa87db3505ae4f687972c18ea0f0d0af89d36c1c2a5b14560c153c3fee406f5cf15cfd1c0bb45d767426d465f2f14c158495069d0c5955a00150707862ecaae30624ebacdd8ac33e4e6aab3ff90b6ba445a84689386b9e945d01823a65874444316e83767290fcff630d2477f49d5d8ffdd200e08ee1274270f86ed14c687895f6caf5ce528bd970c20d2408a9ba66216324c6a011ac4999098362dbd98a038129a2d40c8da6ab88318aa3046cb660327cc44236d9e5d2163bd0959062195c51ed93d0088b6f92051fc99050ece2538749165976233697ab4b610385366e5ce0b02ad6b61c168ecfbedcdf74278a38de340fd7a5fead8e588e294795f9b011e2e60377a89e25c90e145397cdeabc60fd32444a6b7642a611a83c464d8b8976666351b4865c37b02e6dc21dbcdf5f930341707b618cc0f03c3122646b3385c9df9f2ec730eec9d49e7dfc9153b6e6289da8c4f0ebea9ccc1b751948e3bb7171c9e4d57423b0eeeb79095c030cb52677b3f7e0b45c30f645391f3f9c957afa549c4e0b2465b03c67993cd200b1af01035962edbc4c9e89b31c82ac121987d6529dafdeef67a132dc04b6dc68e77f22862040b75e2ceb9ff16da0fca534e6db7bd12fa7b7f51b6c08c1e23dfcdb7acbd2da0b51c87ffbced065a612e9b1c8bba9b7e2d8d7a2f04fcc4aaf355b60d764879a76b5e16762d5f2f55d585d0c8e82df6940960cddfb72c91dfa71f6b4e1c6ca25dfc39a878e998a663c04fe29d5e83b9586d047b4d7ff70a9f0d44f127e7d741685ca75f11629128d916a0ffef4be586a30c4b70389cc746e84ebf177c01ee8a4511cfbb9d1ecf7f7b33c7dd8177896e10bbc82f838dcd6db7ac67de62bf46b6a640fb580c5d1d2708f3862e3d2b645d0d18e49ef088053e3a220adc0e033c2afcfe61c90e32151152eb3caaf746c5e377d541cafc6cbb0cc0fa48b5caf1728f2e1957f5addfc234f1a9d89e40d49356c9172d0561a695fce6dab1d412321bbf407f63766ffd7b6b3d79bcfa07991c5a9709849c1008689e3b47c50d613980bec239fb64185249d055b30375ccb4354d71fe4d05648fbf6c80634dfc3575f2f24abb714c1e4c95e8896763bf4316e954c7ad19e5780ab7a040ca6fb9271f90a8b22ae738daf6cb", + b, + ); +} + +#[bench] +fn modexp_nagydani_5_qube(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000005", // modexp + "000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf03e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", + "5f9c70ec884926a89461056ad20ac4c30155e817f807e4d3f5bb743d789c83386762435c3627773fa77da5144451f2a8aad8adba88e0b669f5377c5e9bad70e45c86fe952b613f015a9953b8a5de5eaee4566acf98d41e327d93a35bd5cef4607d025e58951167957df4ff9b1627649d3943805472e5e293d3efb687cfd1e503faafeb2840a3e3b3f85d016051a58e1c9498aab72e63b748d834b31eb05d85dcde65e27834e266b85c75cc4ec0135135e0601cb93eeeb6e0010c8ceb65c4c319623c5e573a2c8c9fbbf7df68a930beb412d3f4dfd146175484f45d7afaa0d2e60684af9b34730f7c8438465ad3e1d0c3237336722f2aa51095bd5759f4b8ab4dda111b684aa3dac62a761722e7ae43495b7709933512c81c4e3c9133a51f7ce9f2b51fcec064f65779666960b4e45df3900f54311f5613e8012dd1b8efd359eda31a778264c72aa8bb419d862734d769076bce2810011989a45374e5c5d8729fec21427f0bf397eacbb4220f603cf463a4b0c94efd858ffd9768cd60d6ce68d755e0fbad007ce5c2223d70c7018345a102e4ab3c60a13a9e7794303156d4c2063e919f2153c13961fb324c80b240742f47773a7a8e25b3e3fb19b00ce839346c6eb3c732fbc6b888df0b1fe0a3d07b053a2e9402c267b2d62f794d8a2840526e3ade15ce2264496ccd7519571dfde47f7a4bb16292241c20b2be59f3f8fb4f6383f232d838c5a22d8c95b6834d9d2ca493f5a505ebe8899503b0e8f9b19e6e2dd81c1628b80016d02097e0134de51054c4e7674824d4d758760fc52377d2cad145e259aa2ffaf54139e1a66b1e0c1c191e32ac59474c6b526f5b3ba07d3e5ec286eddf531fcd5292869be58c9f22ef91026159f7cf9d05ef66b4299f4da48cc1635bf2243051d342d378a22c83390553e873713c0454ce5f3234397111ac3fe3207b86f0ed9fc025c81903e1748103692074f83824fda6341be4f95ff00b0a9a208c267e12fa01825054cc0513629bf3dbb56dc5b90d4316f87654a8be18227978ea0a8a522760cad620d0d14fd38920fb7321314062914275a5f99f677145a6979b156bd82ecd36f23f8e1273cc2759ecc0b2c69d94dad5211d1bed939dd87ed9e07b91d49713a6e16ade0a98aea789f04994e318e4ff2c8a188cd8d43aeb52c6daa3bc29b4af50ea82a247c5cd67b573b34cbadcc0a376d3bbd530d50367b42705d870f2e27a8197ef46070528bfe408360faa2ebb8bf76e9f388572842bcb119f4d84ee34ae31f5cc594f23705a49197b181fb78ed1ec99499c690f843a4d0cf2e226d118e9372271054fbabdcc5c92ae9fefaef0589cd0e722eaf30c1703ec4289c7fd81beaa8a455ccee5298e31e2080c10c366a6fcf56f7d13582ad0bcad037c612b710fc595b70fbefaaca23623b60c6c39b11beb8e5843b6b3dac60f", + b, + ); +} + + +#[bench] +fn modexp_nagydani_5_pow0x10001(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000005", // modexp + "000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf010001e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", + "5a0eb2bdf0ac1cae8e586689fa16cd4b07dfdedaec8a110ea1fdb059dd5253231b6132987598dfc6e11f86780428982d50cf68f67ae452622c3b336b537ef3298ca645e8f89ee39a26758206a5a3f6409afc709582f95274b57b71fae5c6b74619ae6f089a5393c5b79235d9caf699d23d88fb873f78379690ad8405e34c19f5257d596580c7a6a7206a3712825afe630c76b31cdb4a23e7f0632e10f14f4e282c81a66451a26f8df2a352b5b9f607a7198449d1b926e27036810368e691a74b91c61afa73d9d3b99453e7c8b50fd4f09c039a2f2feb5c419206694c31b92df1d9586140cb3417b38d0c503c7b508cc2ed12e813a1c795e9829eb39ee78eeaf360a169b491a1d4e419574e712402de9d48d54c1ae5e03739b7156615e8267e1fb0a897f067afd11fb33f6e24182d7aaaaa18fe5bc1982f20d6b871e5a398f0f6f718181d31ec225cfa9a0a70124ed9a70031bdf0c1c7829f708b6e17d50419ef361cf77d99c85f44607186c8d683106b8bd38a49b5d0fb503b397a83388c5678dcfcc737499d84512690701ed621a6f0172aecf037184ddf0f2453e4053024018e5ab2e30d6d5363b56e8b41509317c99042f517247474ab3abc848e00a07f69c254f46f2a05cf6ed84e5cc906a518fdcfdf2c61ce731f24c5264f1a25fc04934dc28aec112134dd523f70115074ca34e3807aa4cb925147f3a0ce152d323bd8c675ace446d0fd1ae30c4b57f0eb2c23884bc18f0964c0114796c5b6d080c3d89175665fbf63a6381a6a9da39ad070b645c8bb1779506da14439a9f5b5d481954764ea114fac688930bc68534d403cff4210673b6a6ff7ae416b7cd41404c3d3f282fcd193b86d0f54d0006c2a503b40d5c3930da980565b8f9630e9493a79d1c03e74e5f93ac8e4dc1a901ec5e3b3e57049124c7b72ea345aa359e782285d9e6a5c144a378111dd02c40855ff9c2be9b48425cb0b2fd62dc8678fd151121cf26a65e917d65d8e0dacfae108eb5508b601fb8ffa370be1f9a8b749a2d12eeab81f41079de87e2d777994fa4d28188c579ad327f9957fb7bdecec5c680844dd43cb57cf87aeb763c003e65011f73f8c63442df39a92b946a6bd968a1c1e4d5fa7d88476a68bd8e20e5b70a99259c7d3f85fb1b65cd2e93972e6264e74ebf289b8b6979b9b68a85cd5b360c1987f87235c3c845d62489e33acf85d53fa3561fe3a3aee18924588d9c6eba4edb7a4d106b31173e42929f6f0c48c80ce6a72d54eca7c0fe870068b7a7c89c63cdda593f5b32d3cb4ea8a32c39f00ab449155757172d66763ed9527019d6de6c9f2416aa6203f4d11c9ebee1e1d3845099e55504446448027212616167eb36035726daa7698b075286f5379cd3e93cb3e0cf4f9cb8d017facbb5550ed32d5ec5400ae57e47e2bf78d1eaeff9480cc765ceff39db500", + b, + ); +} + +#[bench] +fn alt_bn128_add_chfast1(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000006", // alt_bn128_add + "18b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9063c909c4720840cb5134cb9f59fa749755796819658d32efc0d288198f3726607c2b7f58a84bd6145f00c9c2bc0bb1a187f20ff2c92963a88019e7c6a014eed06614e20c147e940f2d70da3f74c9a17df361706a4485c742bd6788478fa17d7", + "2243525c5efd4b9c3d3c45ac0ca3fe4dd85e830a4ce6b65fa1eeaee202839703301d1d33be6da8e509df21cc35964723180eed7532537db9ae5e7d48f195c915", + b, + ); +} + +#[bench] +fn alt_bn128_add_chfast2(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000006", // alt_bn128_add + "2243525c5efd4b9c3d3c45ac0ca3fe4dd85e830a4ce6b65fa1eeaee202839703301d1d33be6da8e509df21cc35964723180eed7532537db9ae5e7d48f195c91518b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9063c909c4720840cb5134cb9f59fa749755796819658d32efc0d288198f37266", + "2bd3e6d0f3b142924f5ca7b49ce5b9d54c4703d7ae5648e61d02268b1a0a9fb721611ce0a6af85915e2f1d70300909ce2e49dfad4a4619c8390cae66cefdb204", + b, + ); +} + +#[bench] +fn alt_bn128_add_cdetrio1(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000006", // alt_bn128_add + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + b, + ); +} + +#[bench] +fn alt_bn128_add_cdetrio2(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000006", // alt_bn128_add + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + b, + ); +} + +#[bench] +fn alt_bn128_add_cdetrio3(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000006", // alt_bn128_add + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + b, + ); +} + +#[bench] +fn alt_bn128_add_cdetrio4(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000006", // alt_bn128_add + "", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + b, + ); +} + +#[bench] +fn alt_bn128_add_cdetrio5(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000006", // alt_bn128_add + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + b, + ); +} + +#[bench] +fn alt_bn128_add_cdetrio6(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000006", // alt_bn128_add + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + b, + ); +} + +#[bench] +fn alt_bn128_add_cdetrio7(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000006", // alt_bn128_add + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + b, + ); +} + +#[bench] +fn alt_bn128_add_cdetrio8(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000006", // alt_bn128_add + "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + b, + ); +} + +#[bench] +fn alt_bn128_add_cdetrio9(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000006", // alt_bn128_add + "0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + b, + ); +} + +#[bench] +fn alt_bn128_add_cdetrio10(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000006", // alt_bn128_add + "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + b, + ); +} + +#[bench] +fn alt_bn128_add_cdetrio11(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000006", // alt_bn128_add + "0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4", + b, + ); +} + +#[bench] +fn alt_bn128_add_cdetrio12(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000006", // alt_bn128_add + "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4", + b, + ); +} + +#[bench] +fn alt_bn128_add_cdetrio13(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000006", // alt_bn128_add + "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98", + "15bf2bb17880144b5d1cd2b1f46eff9d617bffd1ca57c37fb5a49bd84e53cf66049c797f9ce0d17083deb32b5e36f2ea2a212ee036598dd7624c168993d1355f", + b, + ); +} + +#[bench] +fn alt_bn128_add_cdetrio14(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000006", // alt_bn128_add + "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa92e83f8d734803fc370eba25ed1f6b8768bd6d83887b87165fc2434fe11a830cb00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + b, + ); +} + +#[bench] +fn alt_bn128_mul_chfast1(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000007", // alt_bn128_mul + "2bd3e6d0f3b142924f5ca7b49ce5b9d54c4703d7ae5648e61d02268b1a0a9fb721611ce0a6af85915e2f1d70300909ce2e49dfad4a4619c8390cae66cefdb20400000000000000000000000000000000000000000000000011138ce750fa15c2", + "070a8d6a982153cae4be29d434e8faef8a47b274a053f5a4ee2a6c9c13c31e5c031b8ce914eba3a9ffb989f9cdd5b0f01943074bf4f0f315690ec3cec6981afc", + b, + ); +} + +#[bench] +fn alt_bn128_mul_chfast2(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000007", // alt_bn128_mul + "070a8d6a982153cae4be29d434e8faef8a47b274a053f5a4ee2a6c9c13c31e5c031b8ce914eba3a9ffb989f9cdd5b0f01943074bf4f0f315690ec3cec6981afc30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46", + "025a6f4181d2b4ea8b724290ffb40156eb0adb514c688556eb79cdea0752c2bb2eff3f31dea215f1eb86023a133a996eb6300b44da664d64251d05381bb8a02e", + b, + ); +} + +#[bench] +fn alt_bn128_mul_chfast3(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000007", // alt_bn128_mul + "025a6f4181d2b4ea8b724290ffb40156eb0adb514c688556eb79cdea0752c2bb2eff3f31dea215f1eb86023a133a996eb6300b44da664d64251d05381bb8a02e183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea3", + "14789d0d4a730b354403b5fac948113739e276c23e0258d8596ee72f9cd9d3230af18a63153e0ec25ff9f2951dd3fa90ed0197bfef6e2a1a62b5095b9d2b4a27", + b, + ); +} + +#[bench] +fn alt_bn128_mul_cdetrio1(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000007", // alt_bn128_mul + "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "2cde5879ba6f13c0b5aa4ef627f159a3347df9722efce88a9afbb20b763b4c411aa7e43076f6aee272755a7f9b84832e71559ba0d2e0b17d5f9f01755e5b0d11", + b, + ); +} + +#[bench] +fn alt_bn128_mul_cdetrio6(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000007", // alt_bn128_mul + "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "29e587aadd7c06722aabba753017c093f70ba7eb1f1c0104ec0564e7e3e21f6022b1143f6a41008e7755c71c3d00b6b915d386de21783ef590486d8afa8453b1", + b, + ); +} + +#[bench] +fn alt_bn128_mul_cdetrio11(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000007", // alt_bn128_mul + "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "00a1a234d08efaa2616607e31eca1980128b00b415c845ff25bba3afcb81dc00242077290ed33906aeb8e42fd98c41bcb9057ba03421af3f2d08cfc441186024", + b, + ); +} + +#[bench] +fn alt_bn128_pairing_jeff1(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000008", // alt_bn128_pairing + "1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "0000000000000000000000000000000000000000000000000000000000000001", + b, + ); +} + +#[bench] +fn alt_bn128_pairing_jeff2(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000008", // alt_bn128_pairing + "2eca0c7238bf16e83e7a1e6c5d49540685ff51380f309842a98561558019fc0203d3260361bb8451de5ff5ecd17f010ff22f5c31cdf184e9020b06fa5997db841213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f06967a1237ebfeca9aaae0d6d0bab8e28c198c5a339ef8a2407e31cdac516db922160fa257a5fd5b280642ff47b65eca77e626cb685c84fa6d3b6882a283ddd1198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "0000000000000000000000000000000000000000000000000000000000000001", + b, + ); +} + +#[bench] +fn alt_bn128_pairing_jeff3(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000008", // alt_bn128_pairing + "0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd216da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba2e89718ad33c8bed92e210e81d1853435399a271913a6520736a4729cf0d51eb01a9e2ffa2e92599b68e44de5bcf354fa2642bd4f26b259daa6f7ce3ed57aeb314a9a87b789a58af499b314e13c3d65bede56c07ea2d418d6874857b70763713178fb49a2d6cd347dc58973ff49613a20757d0fcc22079f9abd10c3baee245901b9e027bd5cfc2cb5db82d4dc9677ac795ec500ecd47deee3b5da006d6d049b811d7511c78158de484232fc68daf8a45cf217d1c2fae693ff5871e8752d73b21198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "0000000000000000000000000000000000000000000000000000000000000001", + b, + ); +} + +#[bench] +fn alt_bn128_pairing_jeff4(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000008", // alt_bn128_pairing + "2f2ea0b3da1e8ef11914acf8b2e1b32d99df51f5f4f206fc6b947eae860eddb6068134ddb33dc888ef446b648d72338684d678d2eb2371c61a50734d78da4b7225f83c8b6ab9de74e7da488ef02645c5a16a6652c3c71a15dc37fe3a5dcb7cb122acdedd6308e3bb230d226d16a105295f523a8a02bfc5e8bd2da135ac4c245d065bbad92e7c4e31bf3757f1fe7362a63fbfee50e7dc68da116e67d600d9bf6806d302580dc0661002994e7cd3a7f224e7ddc27802777486bf80f40e4ca3cfdb186bac5188a98c45e6016873d107f5cd131f3a3e339d0375e58bd6219347b008122ae2b09e539e152ec5364e7e2204b03d11d3caa038bfc7cd499f8176aacbee1f39e4e4afc4bc74790a4a028aff2c3d2538731fb755edefd8cb48d6ea589b5e283f150794b6736f670d6a1033f9b46c6f5204f50813eb85c8dc4b59db1c5d39140d97ee4d2b36d99bc49974d18ecca3e7ad51011956051b464d9e27d46cc25e0764bb98575bd466d32db7b15f582b2d5c452b36aa394b789366e5e3ca5aabd415794ab061441e51d01e94640b7e3084a07e02c78cf3103c542bc5b298669f211b88da1679b0b64a63b7e0e7bfe52aae524f73a55be7fe70c7e9bfc94b4cf0da1213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f", + "0000000000000000000000000000000000000000000000000000000000000001", + b, + ); +} + +#[bench] +fn alt_bn128_pairing_jeff5(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000008", // alt_bn128_pairing + "20a754d2071d4d53903e3b31a7e98ad6882d58aec240ef981fdf0a9d22c5926a29c853fcea789887315916bbeb89ca37edb355b4f980c9a12a94f30deeed30211213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f1abb4a25eb9379ae96c84fff9f0540abcfc0a0d11aeda02d4f37e4baf74cb0c11073b3ff2cdbb38755f8691ea59e9606696b3ff278acfc098fa8226470d03869217cee0a9ad79a4493b5253e2e4e3a39fc2df38419f230d341f60cb064a0ac290a3d76f140db8418ba512272381446eb73958670f00cf46f1d9e64cba057b53c26f64a8ec70387a13e41430ed3ee4a7db2059cc5fc13c067194bcc0cb49a98552fd72bd9edb657346127da132e5b82ab908f5816c826acb499e22f2412d1a2d70f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd2198a1f162a73261f112401aa2db79c7dab1533c9935c77290a6ce3b191f2318d198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "0000000000000000000000000000000000000000000000000000000000000001", + b, + ); +} + +#[bench] +fn alt_bn128_pairing_jeff6(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000008", // alt_bn128_pairing + "1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c103188585e2364128fe25c70558f1560f4f9350baf3959e603cc91486e110936198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "0000000000000000000000000000000000000000000000000000000000000000", + b, + ); +} + +#[bench] +fn alt_bn128_pairing_empty_data(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000008", // alt_bn128_pairing + "", + "0000000000000000000000000000000000000000000000000000000000000001", + b, + ); +} + +#[bench] +fn alt_bn128_pairing_one_point(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000008", // alt_bn128_pairing + "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "0000000000000000000000000000000000000000000000000000000000000000", + b, + ); +} + +#[bench] +fn alt_bn128_pairing_two_point_match_2(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000008", // alt_bn128_pairing + "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d", + "0000000000000000000000000000000000000000000000000000000000000001", + b, + ); +} + +#[bench] +fn alt_bn128_pairing_two_point_match_3(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000008", // alt_bn128_pairing + "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "0000000000000000000000000000000000000000000000000000000000000001", + b, + ); +} + +#[bench] +fn alt_bn128_pairing_two_point_match_4(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000008", // alt_bn128_pairing + "105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f2f997f3dbd66a7afe07fe7862ce239edba9e05c5afff7f8a1259c9733b2dfbb929d1691530ca701b4a106054688728c9972c8512e9789e9567aae23e302ccd75", + "0000000000000000000000000000000000000000000000000000000000000001", + b, + ); +} + +#[bench] +fn alt_bn128_pairing_ten_point_match_1(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000008", // alt_bn128_pairing + "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d", + "0000000000000000000000000000000000000000000000000000000000000001", + b, + ); +} + +#[bench] +fn alt_bn128_pairing_ten_point_match_2(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000008", // alt_bn128_pairing + "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "0000000000000000000000000000000000000000000000000000000000000001", + b, + ); +} + +#[bench] +fn alt_bn128_pairing_ten_point_match_3(b: &mut Bencher) { + bench( + "0000000000000000000000000000000000000008", // alt_bn128_pairing + "105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f2f997f3dbd66a7afe07fe7862ce239edba9e05c5afff7f8a1259c9733b2dfbb929d1691530ca701b4a106054688728c9972c8512e9789e9567aae23e302ccd75", + "0000000000000000000000000000000000000000000000000000000000000001", + b, + ); +} diff --git a/ethcore/benches/evm.rs b/ethcore/benches/evm.rs deleted file mode 100644 index 9fe2657d6141dd2e4b634edcadcbd54fdf250e64..0000000000000000000000000000000000000000 --- a/ethcore/benches/evm.rs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2015-2017 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 test; -extern crate ethcore_util as util; -extern crate rand; -extern crate bn; -extern crate ethcore_crypto; -extern crate ethkey; -extern crate rustc_hex; -extern crate ethcore_bigint; - -use self::test::{Bencher}; -use rand::{StdRng}; - - -#[bench] -fn bn_128_pairing(b: &mut Bencher) { - use bn::{pairing, G1, G2, Fr, Group}; - - let rng = &mut ::rand::thread_rng(); - - let sk0 = Fr::random(rng); - let sk1 = Fr::random(rng); - - let pk0 = G1::one() * sk0; - let pk1 = G2::one() * sk1; - - b.iter(|| { - let _ = pairing(pk0, pk1); - }); -} - -#[bench] -fn bn_128_mul(b: &mut Bencher) { - use bn::{AffineG1, G1, Fr, Group}; - - let mut rng = StdRng::new().unwrap(); - let p: G1 = G1::random(&mut rng); - let fr = Fr::random(&mut rng); - - b.iter(|| { - let _ = AffineG1::from_jacobian(p * fr); - }); -} - -#[bench] -fn sha256(b: &mut Bencher) { - use ethcore_crypto::digest::sha256; - - let mut input: [u8; 256] = [0; 256]; - let mut out = [0; 32]; - - b.iter(|| { - sha256(&input); - }); -} - -#[bench] -fn ecrecover(b: &mut Bencher) { - use rustc_hex::FromHex; - use ethkey::{Signature, recover as ec_recover}; - use ethcore_bigint::hash::H256; - let input = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap(); - let hash = H256::from_slice(&input[0..32]); - let v = H256::from_slice(&input[32..64]); - let r = H256::from_slice(&input[64..96]); - let s = H256::from_slice(&input[96..128]); - - let bit = match v[31] { - 27 | 28 if &v.0[..31] == &[0; 31] => v[31] - 27, - _ => { return; }, - }; - - let s = Signature::from_rsv(&r, &s, bit); - b.iter(|| { - let _ = ec_recover(&s, &hash); - }); -} - diff --git a/ethcore/crypto/Cargo.toml b/ethcore/crypto/Cargo.toml deleted file mode 100644 index b57b8497c0ed168ad97130e4a40645f811013a1d..0000000000000000000000000000000000000000 --- a/ethcore/crypto/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "ethcore-crypto" -version = "0.1.0" -authors = ["Parity Technologies "] - -[dependencies] -ethereum-types = "0.3" -quick-error = "1.2" -ring = "0.12" -rust-crypto = "0.2.36" -tiny-keccak = "1.4" - diff --git a/ethcore/crypto/README.md b/ethcore/crypto/README.md deleted file mode 100644 index 130d27f3ccb65cc6fd4c2bd569acc9575f34dcd9..0000000000000000000000000000000000000000 --- a/ethcore/crypto/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Ethcrypto - -General cryptographic utilities for Ethereum. - -By default, this library is compiled with the `secp256k1` feature, which provides ECDH and ECIES capability on that curve. It can be compiled without to avoid a dependency on the `libsecp256k1` library. diff --git a/ethcore/crypto/src/aes.rs b/ethcore/crypto/src/aes.rs deleted file mode 100644 index 79a8dcc86d682e9376794d8bf0681a2fcc049326..0000000000000000000000000000000000000000 --- a/ethcore/crypto/src/aes.rs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2015-2017 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 . - -use error::SymmError; -use rcrypto::blockmodes::{CtrMode, CbcDecryptor, PkcsPadding}; -use rcrypto::aessafe::{AesSafe128Encryptor, AesSafe128Decryptor}; -use rcrypto::symmetriccipher::{Encryptor, Decryptor}; -use rcrypto::buffer::{RefReadBuffer, RefWriteBuffer, WriteBuffer}; - -/// Encrypt a message (CTR mode). -/// -/// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each. -/// An error is returned if the input lengths are invalid. -pub fn encrypt_128_ctr(k: &[u8], iv: &[u8], plain: &[u8], dest: &mut [u8]) -> Result<(), SymmError> { - let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec()); - encryptor.encrypt(&mut RefReadBuffer::new(plain), &mut RefWriteBuffer::new(dest), true)?; - Ok(()) -} - -/// Decrypt a message (CTR mode). -/// -/// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each. -/// An error is returned if the input lengths are invalid. -pub fn decrypt_128_ctr(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) -> Result<(), SymmError> { - let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec()); - encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut RefWriteBuffer::new(dest), true)?; - Ok(()) -} - -/// Decrypt a message (CBC mode). -/// -/// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each. -/// An error is returned if the input lengths are invalid. -pub fn decrypt_128_cbc(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) -> Result { - let mut encryptor = CbcDecryptor::new(AesSafe128Decryptor::new(k), PkcsPadding, iv.to_vec()); - let len = dest.len(); - let mut buffer = RefWriteBuffer::new(dest); - encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut buffer, true)?; - Ok(len - buffer.remaining()) -} - diff --git a/ethcore/crypto/src/aes_gcm.rs b/ethcore/crypto/src/aes_gcm.rs deleted file mode 100644 index 178b5d1e12c5b4bf847154e19f5282c3722a27c7..0000000000000000000000000000000000000000 --- a/ethcore/crypto/src/aes_gcm.rs +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright 2015-2017 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 . - -use error::SymmError; -use ring; - -enum Mode { Aes128Gcm, Aes256Gcm } - -/// AES GCM encryptor. -pub struct Encryptor<'a> { - mode: Mode, - key: ring::aead::SealingKey, - ad: &'a [u8], - offset: usize, -} - -impl<'a> Encryptor<'a> { - pub fn aes_128_gcm(key: &[u8; 16]) -> Result, SymmError> { - let sk = ring::aead::SealingKey::new(&ring::aead::AES_128_GCM, key)?; - Ok(Encryptor { - mode: Mode::Aes128Gcm, - key: sk, - ad: &[], - offset: 0, - }) - } - - pub fn aes_256_gcm(key: &[u8; 32]) -> Result, SymmError> { - let sk = ring::aead::SealingKey::new(&ring::aead::AES_256_GCM, key)?; - Ok(Encryptor { - mode: Mode::Aes256Gcm, - key: sk, - ad: &[], - offset: 0, - }) - } - - /// Optional associated data which is not encrypted but authenticated. - pub fn associate(&mut self, data: &'a [u8]) -> &mut Self { - self.ad = data; - self - } - - /// Optional offset value. Only the slice `[offset..]` will be encrypted. - pub fn offset(&mut self, off: usize) -> &mut Self { - self.offset = off; - self - } - - /// Please note that the pair (key, nonce) must never be reused. Using random nonces - /// limits the number of messages encrypted with the same key to 2^32 (cf. [[1]]) - /// - /// [1]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf - pub fn encrypt(&self, nonce: &[u8; 12], mut data: Vec) -> Result, SymmError> { - if self.offset > data.len() { - return Err(SymmError::offset_error(self.offset)) - } - let tag_len = match self.mode { - Mode::Aes128Gcm => ring::aead::AES_128_GCM.tag_len(), - Mode::Aes256Gcm => ring::aead::AES_256_GCM.tag_len(), - }; - data.extend(::std::iter::repeat(0).take(tag_len)); - let len = ring::aead::seal_in_place(&self.key, nonce, self.ad, &mut data[self.offset ..], tag_len)?; - data.truncate(self.offset + len); - Ok(data) - } -} - -/// AES GCM decryptor. -pub struct Decryptor<'a> { - key: ring::aead::OpeningKey, - ad: &'a [u8], - offset: usize, -} - -impl<'a> Decryptor<'a> { - pub fn aes_128_gcm(key: &[u8; 16]) -> Result, SymmError> { - let ok = ring::aead::OpeningKey::new(&ring::aead::AES_128_GCM, key)?; - Ok(Decryptor { - key: ok, - ad: &[], - offset: 0, - }) - } - - pub fn aes_256_gcm(key: &[u8; 32]) -> Result, SymmError> { - let ok = ring::aead::OpeningKey::new(&ring::aead::AES_256_GCM, key)?; - Ok(Decryptor { - key: ok, - ad: &[], - offset: 0, - }) - } - - /// Optional associated data which is not encrypted but authenticated. - pub fn associate(&mut self, data: &'a [u8]) -> &mut Self { - self.ad = data; - self - } - - /// Optional offset value. Only the slice `[offset..]` will be decrypted. - pub fn offset(&mut self, off: usize) -> &mut Self { - self.offset = off; - self - } - - pub fn decrypt(&self, nonce: &[u8; 12], mut data: Vec) -> Result, SymmError> { - if self.offset > data.len() { - return Err(SymmError::offset_error(self.offset)) - } - let len = ring::aead::open_in_place(&self.key, nonce, self.ad, 0, &mut data[self.offset ..])?.len(); - data.truncate(self.offset + len); - Ok(data) - } -} - -#[cfg(test)] -mod tests { - use super::{Encryptor, Decryptor}; - - #[test] - fn aes_gcm_128() { - let secret = b"1234567890123456"; - let nonce = b"123456789012"; - let message = b"So many books, so little time"; - - let ciphertext = Encryptor::aes_128_gcm(secret) - .unwrap() - .encrypt(nonce, message.to_vec()) - .unwrap(); - - assert!(ciphertext != message); - - let plaintext = Decryptor::aes_128_gcm(secret) - .unwrap() - .decrypt(nonce, ciphertext) - .unwrap(); - - assert_eq!(plaintext, message) - } - - #[test] - fn aes_gcm_256() { - let secret = b"12345678901234567890123456789012"; - let nonce = b"123456789012"; - let message = b"So many books, so little time"; - - let ciphertext = Encryptor::aes_256_gcm(secret) - .unwrap() - .encrypt(nonce, message.to_vec()) - .unwrap(); - - assert!(ciphertext != message); - - let plaintext = Decryptor::aes_256_gcm(secret) - .unwrap() - .decrypt(nonce, ciphertext) - .unwrap(); - - assert_eq!(plaintext, message) - } - - #[test] - fn aes_gcm_256_offset() { - let secret = b"12345678901234567890123456789012"; - let nonce = b"123456789012"; - let message = b"prefix data; So many books, so little time"; - - let ciphertext = Encryptor::aes_256_gcm(secret) - .unwrap() - .offset(13) // length of "prefix data; " - .encrypt(nonce, message.to_vec()) - .unwrap(); - - assert!(ciphertext != &message[..]); - - let plaintext = Decryptor::aes_256_gcm(secret) - .unwrap() - .offset(13) // length of "prefix data; " - .decrypt(nonce, ciphertext) - .unwrap(); - - assert_eq!(plaintext, &message[..]) - } -} - diff --git a/ethcore/crypto/src/digest.rs b/ethcore/crypto/src/digest.rs deleted file mode 100644 index 095a8ca26206dbea1ec2d84540c12bb15c44a315..0000000000000000000000000000000000000000 --- a/ethcore/crypto/src/digest.rs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 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 . - -use rcrypto::ripemd160; -use ring::digest::{self, Context, SHA256, SHA512}; -use std::marker::PhantomData; -use std::ops::Deref; - -/// The message digest. -pub struct Digest(InnerDigest, PhantomData); - -enum InnerDigest { - Ring(digest::Digest), - Ripemd160([u8; 20]), -} - -impl Deref for Digest { - type Target = [u8]; - fn deref(&self) -> &Self::Target { - match self.0 { - InnerDigest::Ring(ref d) => d.as_ref(), - InnerDigest::Ripemd160(ref d) => &d[..] - } - } -} - -/// Single-step sha256 digest computation. -pub fn sha256(data: &[u8]) -> Digest { - Digest(InnerDigest::Ring(digest::digest(&SHA256, data)), PhantomData) -} - -/// Single-step sha512 digest computation. -pub fn sha512(data: &[u8]) -> Digest { - Digest(InnerDigest::Ring(digest::digest(&SHA512, data)), PhantomData) -} - -/// Single-step ripemd160 digest computation. -pub fn ripemd160(data: &[u8]) -> Digest { - let mut hasher = Hasher::ripemd160(); - hasher.update(data); - hasher.finish() -} - -pub enum Sha256 {} -pub enum Sha512 {} -pub enum Ripemd160 {} - -/// Stateful digest computation. -pub struct Hasher(Inner, PhantomData); - -enum Inner { - Ring(Context), - Ripemd160(ripemd160::Ripemd160) -} - -impl Hasher { - pub fn sha256() -> Hasher { - Hasher(Inner::Ring(Context::new(&SHA256)), PhantomData) - } -} - -impl Hasher { - pub fn sha512() -> Hasher { - Hasher(Inner::Ring(Context::new(&SHA512)), PhantomData) - } -} - -impl Hasher { - pub fn ripemd160() -> Hasher { - Hasher(Inner::Ripemd160(ripemd160::Ripemd160::new()), PhantomData) - } -} - -impl Hasher { - pub fn update(&mut self, data: &[u8]) { - match self.0 { - Inner::Ring(ref mut ctx) => ctx.update(data), - Inner::Ripemd160(ref mut ctx) => { - use rcrypto::digest::Digest; - ctx.input(data) - } - } - } - - pub fn finish(self) -> Digest { - match self.0 { - Inner::Ring(ctx) => Digest(InnerDigest::Ring(ctx.finish()), PhantomData), - Inner::Ripemd160(mut ctx) => { - use rcrypto::digest::Digest; - let mut d = [0; 20]; - ctx.result(&mut d); - Digest(InnerDigest::Ripemd160(d), PhantomData) - } - } - } -} diff --git a/ethcore/crypto/src/error.rs b/ethcore/crypto/src/error.rs deleted file mode 100644 index 4de3b80036df4ed3b5a41d2939806c67b23aba95..0000000000000000000000000000000000000000 --- a/ethcore/crypto/src/error.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2015-2017 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 . - -use rcrypto; -use ring; - -quick_error! { - #[derive(Debug)] - pub enum Error { - Scrypt(e: ScryptError) { - cause(e) - from() - } - Symm(e: SymmError) { - cause(e) - from() - } - } -} - -quick_error! { - #[derive(Debug)] - pub enum ScryptError { - // log(N) < r / 16 - InvalidN { - display("Invalid N argument of the scrypt encryption") - } - // p <= (2^31-1 * 32)/(128 * r) - InvalidP { - display("Invalid p argument of the scrypt encryption") - } - } -} - -quick_error! { - #[derive(Debug)] - pub enum SymmError wraps PrivSymmErr { - RustCrypto(e: rcrypto::symmetriccipher::SymmetricCipherError) { - display("symmetric crypto error") - from() - } - Ring(e: ring::error::Unspecified) { - display("symmetric crypto error") - cause(e) - from() - } - Offset(x: usize) { - display("offset {} greater than slice length", x) - } - } -} - -impl SymmError { - pub(crate) fn offset_error(x: usize) -> SymmError { - SymmError(PrivSymmErr::Offset(x)) - } -} - -impl From for SymmError { - fn from(e: ring::error::Unspecified) -> SymmError { - SymmError(PrivSymmErr::Ring(e)) - } -} - -impl From for SymmError { - fn from(e: rcrypto::symmetriccipher::SymmetricCipherError) -> SymmError { - SymmError(PrivSymmErr::RustCrypto(e)) - } -} - diff --git a/ethcore/crypto/src/hmac.rs b/ethcore/crypto/src/hmac.rs deleted file mode 100644 index 7327250442dbf9f7177c948b28e2bdd6c6594aba..0000000000000000000000000000000000000000 --- a/ethcore/crypto/src/hmac.rs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 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 . - -use digest; -use ring::digest::{SHA256, SHA512}; -use ring::hmac::{self, SigningContext}; -use std::marker::PhantomData; -use std::ops::Deref; - -/// HMAC signature. -pub struct Signature(hmac::Signature, PhantomData); - -impl Deref for Signature { - type Target = [u8]; - fn deref(&self) -> &Self::Target { - self.0.as_ref() - } -} - -/// HMAC signing key. -pub struct SigKey(hmac::SigningKey, PhantomData); - -impl SigKey { - pub fn sha256(key: &[u8]) -> SigKey { - SigKey(hmac::SigningKey::new(&SHA256, key), PhantomData) - } -} - -impl SigKey { - pub fn sha512(key: &[u8]) -> SigKey { - SigKey(hmac::SigningKey::new(&SHA512, key), PhantomData) - } -} - -/// Compute HMAC signature of `data`. -pub fn sign(k: &SigKey, data: &[u8]) -> Signature { - Signature(hmac::sign(&k.0, data), PhantomData) -} - -/// Stateful HMAC computation. -pub struct Signer(SigningContext, PhantomData); - -impl Signer { - pub fn with(key: &SigKey) -> Signer { - Signer(hmac::SigningContext::with_key(&key.0), PhantomData) - } - - pub fn update(&mut self, data: &[u8]) { - self.0.update(data) - } - - pub fn sign(self) -> Signature { - Signature(self.0.sign(), PhantomData) - } -} - -/// HMAC signature verification key. -pub struct VerifyKey(hmac::VerificationKey, PhantomData); - -impl VerifyKey { - pub fn sha256(key: &[u8]) -> VerifyKey { - VerifyKey(hmac::VerificationKey::new(&SHA256, key), PhantomData) - } -} - -impl VerifyKey { - pub fn sha512(key: &[u8]) -> VerifyKey { - VerifyKey(hmac::VerificationKey::new(&SHA512, key), PhantomData) - } -} - -/// Verify HMAC signature of `data`. -pub fn verify(k: &VerifyKey, data: &[u8], sig: &[u8]) -> bool { - hmac::verify(&k.0, data, sig).is_ok() -} - diff --git a/ethcore/crypto/src/lib.rs b/ethcore/crypto/src/lib.rs deleted file mode 100644 index 0ee42e359910f308a30ecab36e2ff2a9de540895..0000000000000000000000000000000000000000 --- a/ethcore/crypto/src/lib.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Crypto utils used ethstore and network. - -extern crate crypto as rcrypto; -extern crate ethereum_types; -#[macro_use] -extern crate quick_error; -extern crate ring; -extern crate tiny_keccak; - -pub mod aes; -pub mod aes_gcm; -pub mod error; -pub mod scrypt; -pub mod digest; -pub mod hmac; -pub mod pbkdf2; - -pub use error::Error; - -use tiny_keccak::Keccak; - -pub const KEY_LENGTH: usize = 32; -pub const KEY_ITERATIONS: usize = 10240; -pub const KEY_LENGTH_AES: usize = KEY_LENGTH / 2; - -/// Default authenticated data to use (in RPC). -pub const DEFAULT_MAC: [u8; 2] = [0, 0]; - -pub trait Keccak256 { - fn keccak256(&self) -> T where T: Sized; -} - -impl Keccak256<[u8; 32]> for T where T: AsRef<[u8]> { - fn keccak256(&self) -> [u8; 32] { - let mut keccak = Keccak::new_keccak256(); - let mut result = [0u8; 32]; - keccak.update(self.as_ref()); - keccak.finalize(&mut result); - result - } -} - -pub fn derive_key_iterations(password: &str, salt: &[u8; 32], c: u32) -> (Vec, Vec) { - let mut derived_key = [0u8; KEY_LENGTH]; - pbkdf2::sha256(c, pbkdf2::Salt(salt), pbkdf2::Secret(password.as_bytes()), &mut derived_key); - let derived_right_bits = &derived_key[0..KEY_LENGTH_AES]; - let derived_left_bits = &derived_key[KEY_LENGTH_AES..KEY_LENGTH]; - (derived_right_bits.to_vec(), derived_left_bits.to_vec()) -} - -pub fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Vec { - let mut mac = vec![0u8; KEY_LENGTH_AES + cipher_text.len()]; - mac[0..KEY_LENGTH_AES].copy_from_slice(derived_left_bits); - mac[KEY_LENGTH_AES..cipher_text.len() + KEY_LENGTH_AES].copy_from_slice(cipher_text); - mac -} - -pub fn is_equal(a: &[u8], b: &[u8]) -> bool { - ring::constant_time::verify_slices_are_equal(a, b).is_ok() -} - diff --git a/ethcore/crypto/src/pbkdf2.rs b/ethcore/crypto/src/pbkdf2.rs deleted file mode 100644 index b4c993c51331da8bf553016c31f7ce3ad929816f..0000000000000000000000000000000000000000 --- a/ethcore/crypto/src/pbkdf2.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 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 . - -use ring; - -pub struct Salt<'a>(pub &'a [u8]); -pub struct Secret<'a>(pub &'a [u8]); - -pub fn sha256(iter: u32, salt: Salt, sec: Secret, out: &mut [u8; 32]) { - ring::pbkdf2::derive(&ring::digest::SHA256, iter, salt.0, sec.0, &mut out[..]) -} - -pub fn sha512(iter: u32, salt: Salt, sec: Secret, out: &mut [u8; 64]) { - ring::pbkdf2::derive(&ring::digest::SHA512, iter, salt.0, sec.0, &mut out[..]) -} - diff --git a/ethcore/crypto/src/scrypt.rs b/ethcore/crypto/src/scrypt.rs deleted file mode 100644 index 684ab2c572c691d71cdfbea799bd45c4e18de511..0000000000000000000000000000000000000000 --- a/ethcore/crypto/src/scrypt.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2015-2017 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 . - -use error::ScryptError; -use rcrypto::scrypt::{scrypt, ScryptParams}; -use super::{KEY_LENGTH_AES, KEY_LENGTH}; - -pub fn derive_key(pass: &str, salt: &[u8; 32], n: u32, p: u32, r: u32) -> Result<(Vec, Vec), ScryptError> { - // sanity checks - let log_n = (32 - n.leading_zeros() - 1) as u8; - if log_n as u32 >= r * 16 { - return Err(ScryptError::InvalidN); - } - - if p as u64 > ((u32::max_value() as u64 - 1) * 32)/(128 * (r as u64)) { - return Err(ScryptError::InvalidP); - } - - let mut derived_key = vec![0u8; KEY_LENGTH]; - let scrypt_params = ScryptParams::new(log_n, r, p); - scrypt(pass.as_bytes(), salt, &scrypt_params, &mut derived_key); - let derived_right_bits = &derived_key[0..KEY_LENGTH_AES]; - let derived_left_bits = &derived_key[KEY_LENGTH_AES..KEY_LENGTH]; - Ok((derived_right_bits.to_vec(), derived_left_bits.to_vec())) -} - diff --git a/ethcore/evm/Cargo.toml b/ethcore/evm/Cargo.toml index fa7a99f9ded8f96897f0bb88d455a36751948834..18c9a3907a6c48db4a2ba31143f7e099a08031d7 100644 --- a/ethcore/evm/Cargo.toml +++ b/ethcore/evm/Cargo.toml @@ -10,8 +10,8 @@ heapsize = "0.4" lazy_static = "1.0" log = "0.3" vm = { path = "../vm" } -keccak-hash = { path = "../../util/hash" } -parking_lot = "0.5" +keccak-hash = { git = "https://github.com/paritytech/parity-common" } +parking_lot = "0.6" memory-cache = { path = "../../util/memory_cache" } [dev-dependencies] diff --git a/ethcore/evm/src/benches/mod.rs b/ethcore/evm/src/benches/mod.rs index c87fda7bbfb538a980919733c5c9b0c7c9bee847..244c26985a846e14a20a7f4f40eba3827ff7827b 100644 --- a/ethcore/evm/src/benches/mod.rs +++ b/ethcore/evm/src/benches/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/evm/src/evm.rs b/ethcore/evm/src/evm.rs index 16dffe77c5381d9bf368b78916535c284532ea29..4c85b3702810552d61cf5fff9567bea470161cba 100644 --- a/ethcore/evm/src/evm.rs +++ b/ethcore/evm/src/evm.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/evm/src/factory.rs b/ethcore/evm/src/factory.rs index af38afede3f58afbe488dd3e762d5ab8aa703671..65a683cd4a8f1bda446f3f659dcc50f8de1aa7a0 100644 --- a/ethcore/evm/src/factory.rs +++ b/ethcore/evm/src/factory.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/evm/src/instructions.rs b/ethcore/evm/src/instructions.rs index 6ecfc7f67307d500f5df2de73462a9d875068d55..67d390d4dff9ce6e8d5fc724cf96dbb4c7551c73 100644 --- a/ethcore/evm/src/instructions.rs +++ b/ethcore/evm/src/instructions.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -16,83 +16,380 @@ //! VM Instructions list and utility functions -pub type Instruction = u8; +pub use self::Instruction::*; -/// Returns true if given instruction is `PUSHN` instruction. -pub fn is_push(i: Instruction) -> bool { - i >= PUSH1 && i <= PUSH32 -} +macro_rules! enum_with_from_u8 { + ( + $( #[$enum_attr:meta] )* + pub enum $name:ident { + $( $( #[$variant_attr:meta] )* $variant:ident = $discriminator:expr ),+, + } + ) => { + $( #[$enum_attr] )* + pub enum $name { + $( $( #[$variant_attr] )* $variant = $discriminator ),+, + } -#[test] -fn test_is_push() { - assert!(is_push(PUSH1)); - assert!(is_push(PUSH32)); - assert!(!is_push(DUP1)); + impl $name { + #[doc = "Convert from u8 to the given enum"] + pub fn from_u8(value: u8) -> Option { + match value { + $( $discriminator => Some($variant) ),+, + _ => None, + } + } + } + }; } -/// Returns number of bytes to read for `PUSHN` instruction -/// PUSH1 -> 1 -pub fn get_push_bytes(i: Instruction) -> usize { - assert!(is_push(i), "Only for PUSH instructions."); - (i - PUSH1 + 1) as usize +enum_with_from_u8! { + #[doc = "Virtual machine bytecode instruction."] + #[repr(u8)] + #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug)] + pub enum Instruction { + #[doc = "halts execution"] + STOP = 0x00, + #[doc = "addition operation"] + ADD = 0x01, + #[doc = "mulitplication operation"] + MUL = 0x02, + #[doc = "subtraction operation"] + SUB = 0x03, + #[doc = "integer division operation"] + DIV = 0x04, + #[doc = "signed integer division operation"] + SDIV = 0x05, + #[doc = "modulo remainder operation"] + MOD = 0x06, + #[doc = "signed modulo remainder operation"] + SMOD = 0x07, + #[doc = "unsigned modular addition"] + ADDMOD = 0x08, + #[doc = "unsigned modular multiplication"] + MULMOD = 0x09, + #[doc = "exponential operation"] + EXP = 0x0a, + #[doc = "extend length of signed integer"] + SIGNEXTEND = 0x0b, + + #[doc = "less-than comparision"] + LT = 0x10, + #[doc = "greater-than comparision"] + GT = 0x11, + #[doc = "signed less-than comparision"] + SLT = 0x12, + #[doc = "signed greater-than comparision"] + SGT = 0x13, + #[doc = "equality comparision"] + EQ = 0x14, + #[doc = "simple not operator"] + ISZERO = 0x15, + #[doc = "bitwise AND operation"] + AND = 0x16, + #[doc = "bitwise OR operation"] + OR = 0x17, + #[doc = "bitwise XOR operation"] + XOR = 0x18, + #[doc = "bitwise NOT opertation"] + NOT = 0x19, + #[doc = "retrieve single byte from word"] + BYTE = 0x1a, + #[doc = "shift left operation"] + SHL = 0x1b, + #[doc = "logical shift right operation"] + SHR = 0x1c, + #[doc = "arithmetic shift right operation"] + SAR = 0x1d, + + #[doc = "compute SHA3-256 hash"] + SHA3 = 0x20, + + #[doc = "get address of currently executing account"] + ADDRESS = 0x30, + #[doc = "get balance of the given account"] + BALANCE = 0x31, + #[doc = "get execution origination address"] + ORIGIN = 0x32, + #[doc = "get caller address"] + CALLER = 0x33, + #[doc = "get deposited value by the instruction/transaction responsible for this execution"] + CALLVALUE = 0x34, + #[doc = "get input data of current environment"] + CALLDATALOAD = 0x35, + #[doc = "get size of input data in current environment"] + CALLDATASIZE = 0x36, + #[doc = "copy input data in current environment to memory"] + CALLDATACOPY = 0x37, + #[doc = "get size of code running in current environment"] + CODESIZE = 0x38, + #[doc = "copy code running in current environment to memory"] + CODECOPY = 0x39, + #[doc = "get price of gas in current environment"] + GASPRICE = 0x3a, + #[doc = "get external code size (from another contract)"] + EXTCODESIZE = 0x3b, + #[doc = "copy external code (from another contract)"] + EXTCODECOPY = 0x3c, + #[doc = "get the size of the return data buffer for the last call"] + RETURNDATASIZE = 0x3d, + #[doc = "copy return data buffer to memory"] + RETURNDATACOPY = 0x3e, + #[doc = "return the keccak256 hash of contract code"] + EXTCODEHASH = 0x3f, + + #[doc = "get hash of most recent complete block"] + BLOCKHASH = 0x40, + #[doc = "get the block's coinbase address"] + COINBASE = 0x41, + #[doc = "get the block's timestamp"] + TIMESTAMP = 0x42, + #[doc = "get the block's number"] + NUMBER = 0x43, + #[doc = "get the block's difficulty"] + DIFFICULTY = 0x44, + #[doc = "get the block's gas limit"] + GASLIMIT = 0x45, + + #[doc = "remove item from stack"] + POP = 0x50, + #[doc = "load word from memory"] + MLOAD = 0x51, + #[doc = "save word to memory"] + MSTORE = 0x52, + #[doc = "save byte to memory"] + MSTORE8 = 0x53, + #[doc = "load word from storage"] + SLOAD = 0x54, + #[doc = "save word to storage"] + SSTORE = 0x55, + #[doc = "alter the program counter"] + JUMP = 0x56, + #[doc = "conditionally alter the program counter"] + JUMPI = 0x57, + #[doc = "get the program counter"] + PC = 0x58, + #[doc = "get the size of active memory"] + MSIZE = 0x59, + #[doc = "get the amount of available gas"] + GAS = 0x5a, + #[doc = "set a potential jump destination"] + JUMPDEST = 0x5b, + + #[doc = "place 1 byte item on stack"] + PUSH1 = 0x60, + #[doc = "place 2 byte item on stack"] + PUSH2 = 0x61, + #[doc = "place 3 byte item on stack"] + PUSH3 = 0x62, + #[doc = "place 4 byte item on stack"] + PUSH4 = 0x63, + #[doc = "place 5 byte item on stack"] + PUSH5 = 0x64, + #[doc = "place 6 byte item on stack"] + PUSH6 = 0x65, + #[doc = "place 7 byte item on stack"] + PUSH7 = 0x66, + #[doc = "place 8 byte item on stack"] + PUSH8 = 0x67, + #[doc = "place 9 byte item on stack"] + PUSH9 = 0x68, + #[doc = "place 10 byte item on stack"] + PUSH10 = 0x69, + #[doc = "place 11 byte item on stack"] + PUSH11 = 0x6a, + #[doc = "place 12 byte item on stack"] + PUSH12 = 0x6b, + #[doc = "place 13 byte item on stack"] + PUSH13 = 0x6c, + #[doc = "place 14 byte item on stack"] + PUSH14 = 0x6d, + #[doc = "place 15 byte item on stack"] + PUSH15 = 0x6e, + #[doc = "place 16 byte item on stack"] + PUSH16 = 0x6f, + #[doc = "place 17 byte item on stack"] + PUSH17 = 0x70, + #[doc = "place 18 byte item on stack"] + PUSH18 = 0x71, + #[doc = "place 19 byte item on stack"] + PUSH19 = 0x72, + #[doc = "place 20 byte item on stack"] + PUSH20 = 0x73, + #[doc = "place 21 byte item on stack"] + PUSH21 = 0x74, + #[doc = "place 22 byte item on stack"] + PUSH22 = 0x75, + #[doc = "place 23 byte item on stack"] + PUSH23 = 0x76, + #[doc = "place 24 byte item on stack"] + PUSH24 = 0x77, + #[doc = "place 25 byte item on stack"] + PUSH25 = 0x78, + #[doc = "place 26 byte item on stack"] + PUSH26 = 0x79, + #[doc = "place 27 byte item on stack"] + PUSH27 = 0x7a, + #[doc = "place 28 byte item on stack"] + PUSH28 = 0x7b, + #[doc = "place 29 byte item on stack"] + PUSH29 = 0x7c, + #[doc = "place 30 byte item on stack"] + PUSH30 = 0x7d, + #[doc = "place 31 byte item on stack"] + PUSH31 = 0x7e, + #[doc = "place 32 byte item on stack"] + PUSH32 = 0x7f, + + #[doc = "copies the highest item in the stack to the top of the stack"] + DUP1 = 0x80, + #[doc = "copies the second highest item in the stack to the top of the stack"] + DUP2 = 0x81, + #[doc = "copies the third highest item in the stack to the top of the stack"] + DUP3 = 0x82, + #[doc = "copies the 4th highest item in the stack to the top of the stack"] + DUP4 = 0x83, + #[doc = "copies the 5th highest item in the stack to the top of the stack"] + DUP5 = 0x84, + #[doc = "copies the 6th highest item in the stack to the top of the stack"] + DUP6 = 0x85, + #[doc = "copies the 7th highest item in the stack to the top of the stack"] + DUP7 = 0x86, + #[doc = "copies the 8th highest item in the stack to the top of the stack"] + DUP8 = 0x87, + #[doc = "copies the 9th highest item in the stack to the top of the stack"] + DUP9 = 0x88, + #[doc = "copies the 10th highest item in the stack to the top of the stack"] + DUP10 = 0x89, + #[doc = "copies the 11th highest item in the stack to the top of the stack"] + DUP11 = 0x8a, + #[doc = "copies the 12th highest item in the stack to the top of the stack"] + DUP12 = 0x8b, + #[doc = "copies the 13th highest item in the stack to the top of the stack"] + DUP13 = 0x8c, + #[doc = "copies the 14th highest item in the stack to the top of the stack"] + DUP14 = 0x8d, + #[doc = "copies the 15th highest item in the stack to the top of the stack"] + DUP15 = 0x8e, + #[doc = "copies the 16th highest item in the stack to the top of the stack"] + DUP16 = 0x8f, + + #[doc = "swaps the highest and second highest value on the stack"] + SWAP1 = 0x90, + #[doc = "swaps the highest and third highest value on the stack"] + SWAP2 = 0x91, + #[doc = "swaps the highest and 4th highest value on the stack"] + SWAP3 = 0x92, + #[doc = "swaps the highest and 5th highest value on the stack"] + SWAP4 = 0x93, + #[doc = "swaps the highest and 6th highest value on the stack"] + SWAP5 = 0x94, + #[doc = "swaps the highest and 7th highest value on the stack"] + SWAP6 = 0x95, + #[doc = "swaps the highest and 8th highest value on the stack"] + SWAP7 = 0x96, + #[doc = "swaps the highest and 9th highest value on the stack"] + SWAP8 = 0x97, + #[doc = "swaps the highest and 10th highest value on the stack"] + SWAP9 = 0x98, + #[doc = "swaps the highest and 11th highest value on the stack"] + SWAP10 = 0x99, + #[doc = "swaps the highest and 12th highest value on the stack"] + SWAP11 = 0x9a, + #[doc = "swaps the highest and 13th highest value on the stack"] + SWAP12 = 0x9b, + #[doc = "swaps the highest and 14th highest value on the stack"] + SWAP13 = 0x9c, + #[doc = "swaps the highest and 15th highest value on the stack"] + SWAP14 = 0x9d, + #[doc = "swaps the highest and 16th highest value on the stack"] + SWAP15 = 0x9e, + #[doc = "swaps the highest and 17th highest value on the stack"] + SWAP16 = 0x9f, + + #[doc = "Makes a log entry, no topics."] + LOG0 = 0xa0, + #[doc = "Makes a log entry, 1 topic."] + LOG1 = 0xa1, + #[doc = "Makes a log entry, 2 topics."] + LOG2 = 0xa2, + #[doc = "Makes a log entry, 3 topics."] + LOG3 = 0xa3, + #[doc = "Makes a log entry, 4 topics."] + LOG4 = 0xa4, + + #[doc = "create a new account with associated code"] + CREATE = 0xf0, + #[doc = "message-call into an account"] + CALL = 0xf1, + #[doc = "message-call with another account's code only"] + CALLCODE = 0xf2, + #[doc = "halt execution returning output data"] + RETURN = 0xf3, + #[doc = "like CALLCODE but keeps caller's value and sender"] + DELEGATECALL = 0xf4, + #[doc = "create a new account and set creation address to sha3(sender + sha3(init code)) % 2**160"] + CREATE2 = 0xfb, + #[doc = "stop execution and revert state changes. Return output data."] + REVERT = 0xfd, + #[doc = "like CALL but it does not take value, nor modify the state"] + STATICCALL = 0xfa, + #[doc = "halt execution and register account for later deletion"] + SUICIDE = 0xff, + } } -/// Returns number of bytes to read for `PUSHN` instruction or 0. -pub fn push_bytes(i: Instruction) -> usize { - if is_push(i) { - get_push_bytes(i) - } else { - 0 +impl Instruction { + /// Returns true if given instruction is `PUSHN` instruction. + pub fn is_push(&self) -> bool { + *self >= PUSH1 && *self <= PUSH32 } -} -#[test] -fn test_get_push_bytes() { - assert_eq!(get_push_bytes(PUSH1), 1); - assert_eq!(get_push_bytes(PUSH3), 3); - assert_eq!(get_push_bytes(PUSH32), 32); -} + /// Returns number of bytes to read for `PUSHN` instruction + /// PUSH1 -> 1 + pub fn push_bytes(&self) -> Option { + if self.is_push() { + Some(((*self as u8) - (PUSH1 as u8) + 1) as usize) + } else { + None + } + } -/// Returns stack position of item to duplicate -/// DUP1 -> 0 -pub fn get_dup_position(i: Instruction) -> usize { - assert!(i >= DUP1 && i <= DUP16); - (i - DUP1) as usize -} -#[test] -fn test_get_dup_position() { - assert_eq!(get_dup_position(DUP1), 0); - assert_eq!(get_dup_position(DUP5), 4); - assert_eq!(get_dup_position(DUP10), 9); -} + /// Returns stack position of item to duplicate + /// DUP1 -> 0 + pub fn dup_position(&self) -> Option { + if *self >= DUP1 && *self <= DUP16 { + Some(((*self as u8) - (DUP1 as u8)) as usize) + } else { + None + } + } -/// Returns stack position of item to SWAP top with -/// SWAP1 -> 1 -pub fn get_swap_position(i: Instruction) -> usize { - assert!(i >= SWAP1 && i <= SWAP16); - (i - SWAP1 + 1) as usize -} -#[test] -fn test_get_swap_position() { - assert_eq!(get_swap_position(SWAP1), 1); - assert_eq!(get_swap_position(SWAP5), 5); - assert_eq!(get_swap_position(SWAP10), 10); -} + /// Returns stack position of item to SWAP top with + /// SWAP1 -> 1 + pub fn swap_position(&self) -> Option { + if *self >= SWAP1 && *self <= SWAP16 { + Some(((*self as u8) - (SWAP1 as u8) + 1) as usize) + } else { + None + } + } -/// Returns number of topics to take from stack -/// LOG0 -> 0 -pub fn get_log_topics (i: Instruction) -> usize { - assert!(i >= LOG0 && i <= LOG4); - (i - LOG0) as usize -} + /// Returns number of topics to take from stack + /// LOG0 -> 0 + pub fn log_topics(&self) -> Option { + if *self >= LOG0 && *self <= LOG4 { + Some(((*self as u8) - (LOG0 as u8)) as usize) + } else { + None + } + } -#[test] -fn test_get_log_topics() { - assert_eq!(get_log_topics(LOG0), 0); - assert_eq!(get_log_topics(LOG2), 2); - assert_eq!(get_log_topics(LOG4), 4); + /// Returns the instruction info. + pub fn info(&self) -> &'static InstructionInfo { + INSTRUCTIONS[*self as usize].as_ref().expect("A instruction is defined in Instruction enum, but it is not found in InstructionInfo struct; this indicates a logic failure in the code.") + } } #[derive(PartialEq, Clone, Copy)] @@ -113,33 +410,26 @@ pub enum GasPriceTier { Ext, /// Multiparam or otherwise special Special, - /// Invalid - Invalid -} - -impl Default for GasPriceTier { - fn default() -> Self { - GasPriceTier::Invalid - } } -/// Returns the index in schedule for specific `GasPriceTier` -pub fn get_tier_idx (tier: GasPriceTier) -> usize { - match tier { - GasPriceTier::Zero => 0, - GasPriceTier::Base => 1, - GasPriceTier::VeryLow => 2, - GasPriceTier::Low => 3, - GasPriceTier::Mid => 4, - GasPriceTier::High => 5, - GasPriceTier::Ext => 6, - GasPriceTier::Special => 7, - GasPriceTier::Invalid => 8 +impl GasPriceTier { + /// Returns the index in schedule for specific `GasPriceTier` + pub fn idx(&self) -> usize { + match self { + &GasPriceTier::Zero => 0, + &GasPriceTier::Base => 1, + &GasPriceTier::VeryLow => 2, + &GasPriceTier::Low => 3, + &GasPriceTier::Mid => 4, + &GasPriceTier::High => 5, + &GasPriceTier::Ext => 6, + &GasPriceTier::Special => 7, + } } } /// EVM instruction information. -#[derive(Copy, Clone, Default)] +#[derive(Copy, Clone)] pub struct InstructionInfo { /// Mnemonic name. pub name: &'static str, @@ -165,436 +455,190 @@ impl InstructionInfo { lazy_static! { /// Static instruction table. - pub static ref INSTRUCTIONS: [InstructionInfo; 0x100] = { - let mut arr = [InstructionInfo::default(); 0x100]; - arr[STOP as usize] = InstructionInfo::new("STOP", 0, 0, GasPriceTier::Zero); - arr[ADD as usize] = InstructionInfo::new("ADD", 2, 1, GasPriceTier::VeryLow); - arr[SUB as usize] = InstructionInfo::new("SUB", 2, 1, GasPriceTier::VeryLow); - arr[MUL as usize] = InstructionInfo::new("MUL", 2, 1, GasPriceTier::Low); - arr[DIV as usize] = InstructionInfo::new("DIV", 2, 1, GasPriceTier::Low); - arr[SDIV as usize] = InstructionInfo::new("SDIV", 2, 1, GasPriceTier::Low); - arr[MOD as usize] = InstructionInfo::new("MOD", 2, 1, GasPriceTier::Low); - arr[SMOD as usize] = InstructionInfo::new("SMOD", 2, 1, GasPriceTier::Low); - arr[EXP as usize] = InstructionInfo::new("EXP", 2, 1, GasPriceTier::Special); - arr[NOT as usize] = InstructionInfo::new("NOT", 1, 1, GasPriceTier::VeryLow); - arr[LT as usize] = InstructionInfo::new("LT", 2, 1, GasPriceTier::VeryLow); - arr[GT as usize] = InstructionInfo::new("GT", 2, 1, GasPriceTier::VeryLow); - arr[SLT as usize] = InstructionInfo::new("SLT", 2, 1, GasPriceTier::VeryLow); - arr[SGT as usize] = InstructionInfo::new("SGT", 2, 1, GasPriceTier::VeryLow); - arr[EQ as usize] = InstructionInfo::new("EQ", 2, 1, GasPriceTier::VeryLow); - arr[ISZERO as usize] = InstructionInfo::new("ISZERO", 1, 1, GasPriceTier::VeryLow); - arr[AND as usize] = InstructionInfo::new("AND", 2, 1, GasPriceTier::VeryLow); - arr[OR as usize] = InstructionInfo::new("OR", 2, 1, GasPriceTier::VeryLow); - arr[XOR as usize] = InstructionInfo::new("XOR", 2, 1, GasPriceTier::VeryLow); - arr[BYTE as usize] = InstructionInfo::new("BYTE", 2, 1, GasPriceTier::VeryLow); - arr[SHL as usize] = InstructionInfo::new("SHL", 2, 1, GasPriceTier::VeryLow); - arr[SHR as usize] = InstructionInfo::new("SHR", 2, 1, GasPriceTier::VeryLow); - arr[SAR as usize] = InstructionInfo::new("SAR", 2, 1, GasPriceTier::VeryLow); - arr[ADDMOD as usize] = InstructionInfo::new("ADDMOD", 3, 1, GasPriceTier::Mid); - arr[MULMOD as usize] = InstructionInfo::new("MULMOD", 3, 1, GasPriceTier::Mid); - arr[SIGNEXTEND as usize] = InstructionInfo::new("SIGNEXTEND", 2, 1, GasPriceTier::Low); - arr[RETURNDATASIZE as usize] = InstructionInfo::new("RETURNDATASIZE", 0, 1, GasPriceTier::Base); - arr[RETURNDATACOPY as usize] = InstructionInfo::new("RETURNDATACOPY", 3, 0, GasPriceTier::VeryLow); - arr[SHA3 as usize] = InstructionInfo::new("SHA3", 2, 1, GasPriceTier::Special); - arr[ADDRESS as usize] = InstructionInfo::new("ADDRESS", 0, 1, GasPriceTier::Base); - arr[BALANCE as usize] = InstructionInfo::new("BALANCE", 1, 1, GasPriceTier::Special); - arr[ORIGIN as usize] = InstructionInfo::new("ORIGIN", 0, 1, GasPriceTier::Base); - arr[CALLER as usize] = InstructionInfo::new("CALLER", 0, 1, GasPriceTier::Base); - arr[CALLVALUE as usize] = InstructionInfo::new("CALLVALUE", 0, 1, GasPriceTier::Base); - arr[CALLDATALOAD as usize] = InstructionInfo::new("CALLDATALOAD", 1, 1, GasPriceTier::VeryLow); - arr[CALLDATASIZE as usize] = InstructionInfo::new("CALLDATASIZE", 0, 1, GasPriceTier::Base); - arr[CALLDATACOPY as usize] = InstructionInfo::new("CALLDATACOPY", 3, 0, GasPriceTier::VeryLow); - arr[CODESIZE as usize] = InstructionInfo::new("CODESIZE", 0, 1, GasPriceTier::Base); - arr[CODECOPY as usize] = InstructionInfo::new("CODECOPY", 3, 0, GasPriceTier::VeryLow); - arr[GASPRICE as usize] = InstructionInfo::new("GASPRICE", 0, 1, GasPriceTier::Base); - arr[EXTCODESIZE as usize] = InstructionInfo::new("EXTCODESIZE", 1, 1, GasPriceTier::Special); - arr[EXTCODECOPY as usize] = InstructionInfo::new("EXTCODECOPY", 4, 0, GasPriceTier::Special); - arr[BLOCKHASH as usize] = InstructionInfo::new("BLOCKHASH", 1, 1, GasPriceTier::Ext); - arr[COINBASE as usize] = InstructionInfo::new("COINBASE", 0, 1, GasPriceTier::Base); - arr[TIMESTAMP as usize] = InstructionInfo::new("TIMESTAMP", 0, 1, GasPriceTier::Base); - arr[NUMBER as usize] = InstructionInfo::new("NUMBER", 0, 1, GasPriceTier::Base); - arr[DIFFICULTY as usize] = InstructionInfo::new("DIFFICULTY", 0, 1, GasPriceTier::Base); - arr[GASLIMIT as usize] = InstructionInfo::new("GASLIMIT", 0, 1, GasPriceTier::Base); - arr[POP as usize] = InstructionInfo::new("POP", 1, 0, GasPriceTier::Base); - arr[MLOAD as usize] = InstructionInfo::new("MLOAD", 1, 1, GasPriceTier::VeryLow); - arr[MSTORE as usize] = InstructionInfo::new("MSTORE", 2, 0, GasPriceTier::VeryLow); - arr[MSTORE8 as usize] = InstructionInfo::new("MSTORE8", 2, 0, GasPriceTier::VeryLow); - arr[SLOAD as usize] = InstructionInfo::new("SLOAD", 1, 1, GasPriceTier::Special); - arr[SSTORE as usize] = InstructionInfo::new("SSTORE", 2, 0, GasPriceTier::Special); - arr[JUMP as usize] = InstructionInfo::new("JUMP", 1, 0, GasPriceTier::Mid); - arr[JUMPI as usize] = InstructionInfo::new("JUMPI", 2, 0, GasPriceTier::High); - arr[PC as usize] = InstructionInfo::new("PC", 0, 1, GasPriceTier::Base); - arr[MSIZE as usize] = InstructionInfo::new("MSIZE", 0, 1, GasPriceTier::Base); - arr[GAS as usize] = InstructionInfo::new("GAS", 0, 1, GasPriceTier::Base); - arr[JUMPDEST as usize] = InstructionInfo::new("JUMPDEST", 0, 0, GasPriceTier::Special); - arr[PUSH1 as usize] = InstructionInfo::new("PUSH1", 0, 1, GasPriceTier::VeryLow); - arr[PUSH2 as usize] = InstructionInfo::new("PUSH2", 0, 1, GasPriceTier::VeryLow); - arr[PUSH3 as usize] = InstructionInfo::new("PUSH3", 0, 1, GasPriceTier::VeryLow); - arr[PUSH4 as usize] = InstructionInfo::new("PUSH4", 0, 1, GasPriceTier::VeryLow); - arr[PUSH5 as usize] = InstructionInfo::new("PUSH5", 0, 1, GasPriceTier::VeryLow); - arr[PUSH6 as usize] = InstructionInfo::new("PUSH6", 0, 1, GasPriceTier::VeryLow); - arr[PUSH7 as usize] = InstructionInfo::new("PUSH7", 0, 1, GasPriceTier::VeryLow); - arr[PUSH8 as usize] = InstructionInfo::new("PUSH8", 0, 1, GasPriceTier::VeryLow); - arr[PUSH9 as usize] = InstructionInfo::new("PUSH9", 0, 1, GasPriceTier::VeryLow); - arr[PUSH10 as usize] = InstructionInfo::new("PUSH10", 0, 1, GasPriceTier::VeryLow); - arr[PUSH11 as usize] = InstructionInfo::new("PUSH11", 0, 1, GasPriceTier::VeryLow); - arr[PUSH12 as usize] = InstructionInfo::new("PUSH12", 0, 1, GasPriceTier::VeryLow); - arr[PUSH13 as usize] = InstructionInfo::new("PUSH13", 0, 1, GasPriceTier::VeryLow); - arr[PUSH14 as usize] = InstructionInfo::new("PUSH14", 0, 1, GasPriceTier::VeryLow); - arr[PUSH15 as usize] = InstructionInfo::new("PUSH15", 0, 1, GasPriceTier::VeryLow); - arr[PUSH16 as usize] = InstructionInfo::new("PUSH16", 0, 1, GasPriceTier::VeryLow); - arr[PUSH17 as usize] = InstructionInfo::new("PUSH17", 0, 1, GasPriceTier::VeryLow); - arr[PUSH18 as usize] = InstructionInfo::new("PUSH18", 0, 1, GasPriceTier::VeryLow); - arr[PUSH19 as usize] = InstructionInfo::new("PUSH19", 0, 1, GasPriceTier::VeryLow); - arr[PUSH20 as usize] = InstructionInfo::new("PUSH20", 0, 1, GasPriceTier::VeryLow); - arr[PUSH21 as usize] = InstructionInfo::new("PUSH21", 0, 1, GasPriceTier::VeryLow); - arr[PUSH22 as usize] = InstructionInfo::new("PUSH22", 0, 1, GasPriceTier::VeryLow); - arr[PUSH23 as usize] = InstructionInfo::new("PUSH23", 0, 1, GasPriceTier::VeryLow); - arr[PUSH24 as usize] = InstructionInfo::new("PUSH24", 0, 1, GasPriceTier::VeryLow); - arr[PUSH25 as usize] = InstructionInfo::new("PUSH25", 0, 1, GasPriceTier::VeryLow); - arr[PUSH26 as usize] = InstructionInfo::new("PUSH26", 0, 1, GasPriceTier::VeryLow); - arr[PUSH27 as usize] = InstructionInfo::new("PUSH27", 0, 1, GasPriceTier::VeryLow); - arr[PUSH28 as usize] = InstructionInfo::new("PUSH28", 0, 1, GasPriceTier::VeryLow); - arr[PUSH29 as usize] = InstructionInfo::new("PUSH29", 0, 1, GasPriceTier::VeryLow); - arr[PUSH30 as usize] = InstructionInfo::new("PUSH30", 0, 1, GasPriceTier::VeryLow); - arr[PUSH31 as usize] = InstructionInfo::new("PUSH31", 0, 1, GasPriceTier::VeryLow); - arr[PUSH32 as usize] = InstructionInfo::new("PUSH32", 0, 1, GasPriceTier::VeryLow); - arr[DUP1 as usize] = InstructionInfo::new("DUP1", 1, 2, GasPriceTier::VeryLow); - arr[DUP2 as usize] = InstructionInfo::new("DUP2", 2, 3, GasPriceTier::VeryLow); - arr[DUP3 as usize] = InstructionInfo::new("DUP3", 3, 4, GasPriceTier::VeryLow); - arr[DUP4 as usize] = InstructionInfo::new("DUP4", 4, 5, GasPriceTier::VeryLow); - arr[DUP5 as usize] = InstructionInfo::new("DUP5", 5, 6, GasPriceTier::VeryLow); - arr[DUP6 as usize] = InstructionInfo::new("DUP6", 6, 7, GasPriceTier::VeryLow); - arr[DUP7 as usize] = InstructionInfo::new("DUP7", 7, 8, GasPriceTier::VeryLow); - arr[DUP8 as usize] = InstructionInfo::new("DUP8", 8, 9, GasPriceTier::VeryLow); - arr[DUP9 as usize] = InstructionInfo::new("DUP9", 9, 10, GasPriceTier::VeryLow); - arr[DUP10 as usize] = InstructionInfo::new("DUP10", 10, 11, GasPriceTier::VeryLow); - arr[DUP11 as usize] = InstructionInfo::new("DUP11", 11, 12, GasPriceTier::VeryLow); - arr[DUP12 as usize] = InstructionInfo::new("DUP12", 12, 13, GasPriceTier::VeryLow); - arr[DUP13 as usize] = InstructionInfo::new("DUP13", 13, 14, GasPriceTier::VeryLow); - arr[DUP14 as usize] = InstructionInfo::new("DUP14", 14, 15, GasPriceTier::VeryLow); - arr[DUP15 as usize] = InstructionInfo::new("DUP15", 15, 16, GasPriceTier::VeryLow); - arr[DUP16 as usize] = InstructionInfo::new("DUP16", 16, 17, GasPriceTier::VeryLow); - arr[SWAP1 as usize] = InstructionInfo::new("SWAP1", 2, 2, GasPriceTier::VeryLow); - arr[SWAP2 as usize] = InstructionInfo::new("SWAP2", 3, 3, GasPriceTier::VeryLow); - arr[SWAP3 as usize] = InstructionInfo::new("SWAP3", 4, 4, GasPriceTier::VeryLow); - arr[SWAP4 as usize] = InstructionInfo::new("SWAP4", 5, 5, GasPriceTier::VeryLow); - arr[SWAP5 as usize] = InstructionInfo::new("SWAP5", 6, 6, GasPriceTier::VeryLow); - arr[SWAP6 as usize] = InstructionInfo::new("SWAP6", 7, 7, GasPriceTier::VeryLow); - arr[SWAP7 as usize] = InstructionInfo::new("SWAP7", 8, 8, GasPriceTier::VeryLow); - arr[SWAP8 as usize] = InstructionInfo::new("SWAP8", 9, 9, GasPriceTier::VeryLow); - arr[SWAP9 as usize] = InstructionInfo::new("SWAP9", 10, 10, GasPriceTier::VeryLow); - arr[SWAP10 as usize] = InstructionInfo::new("SWAP10", 11, 11, GasPriceTier::VeryLow); - arr[SWAP11 as usize] = InstructionInfo::new("SWAP11", 12, 12, GasPriceTier::VeryLow); - arr[SWAP12 as usize] = InstructionInfo::new("SWAP12", 13, 13, GasPriceTier::VeryLow); - arr[SWAP13 as usize] = InstructionInfo::new("SWAP13", 14, 14, GasPriceTier::VeryLow); - arr[SWAP14 as usize] = InstructionInfo::new("SWAP14", 15, 15, GasPriceTier::VeryLow); - arr[SWAP15 as usize] = InstructionInfo::new("SWAP15", 16, 16, GasPriceTier::VeryLow); - arr[SWAP16 as usize] = InstructionInfo::new("SWAP16", 17, 17, GasPriceTier::VeryLow); - arr[LOG0 as usize] = InstructionInfo::new("LOG0", 2, 0, GasPriceTier::Special); - arr[LOG1 as usize] = InstructionInfo::new("LOG1", 3, 0, GasPriceTier::Special); - arr[LOG2 as usize] = InstructionInfo::new("LOG2", 4, 0, GasPriceTier::Special); - arr[LOG3 as usize] = InstructionInfo::new("LOG3", 5, 0, GasPriceTier::Special); - arr[LOG4 as usize] = InstructionInfo::new("LOG4", 6, 0, GasPriceTier::Special); - arr[CREATE as usize] = InstructionInfo::new("CREATE", 3, 1, GasPriceTier::Special); - arr[CALL as usize] = InstructionInfo::new("CALL", 7, 1, GasPriceTier::Special); - arr[CALLCODE as usize] = InstructionInfo::new("CALLCODE", 7, 1, GasPriceTier::Special); - arr[RETURN as usize] = InstructionInfo::new("RETURN", 2, 0, GasPriceTier::Zero); - arr[DELEGATECALL as usize] = InstructionInfo::new("DELEGATECALL", 6, 1, GasPriceTier::Special); - arr[STATICCALL as usize] = InstructionInfo::new("STATICCALL", 6, 1, GasPriceTier::Special); - arr[SUICIDE as usize] = InstructionInfo::new("SUICIDE", 1, 0, GasPriceTier::Special); - arr[CREATE2 as usize] = InstructionInfo::new("CREATE2", 3, 1, GasPriceTier::Special); - arr[REVERT as usize] = InstructionInfo::new("REVERT", 2, 0, GasPriceTier::Zero); + static ref INSTRUCTIONS: [Option; 0x100] = { + let mut arr = [None; 0x100]; + arr[STOP as usize] = Some(InstructionInfo::new("STOP", 0, 0, GasPriceTier::Zero)); + arr[ADD as usize] = Some(InstructionInfo::new("ADD", 2, 1, GasPriceTier::VeryLow)); + arr[SUB as usize] = Some(InstructionInfo::new("SUB", 2, 1, GasPriceTier::VeryLow)); + arr[MUL as usize] = Some(InstructionInfo::new("MUL", 2, 1, GasPriceTier::Low)); + arr[DIV as usize] = Some(InstructionInfo::new("DIV", 2, 1, GasPriceTier::Low)); + arr[SDIV as usize] = Some(InstructionInfo::new("SDIV", 2, 1, GasPriceTier::Low)); + arr[MOD as usize] = Some(InstructionInfo::new("MOD", 2, 1, GasPriceTier::Low)); + arr[SMOD as usize] = Some(InstructionInfo::new("SMOD", 2, 1, GasPriceTier::Low)); + arr[EXP as usize] = Some(InstructionInfo::new("EXP", 2, 1, GasPriceTier::Special)); + arr[NOT as usize] = Some(InstructionInfo::new("NOT", 1, 1, GasPriceTier::VeryLow)); + arr[LT as usize] = Some(InstructionInfo::new("LT", 2, 1, GasPriceTier::VeryLow)); + arr[GT as usize] = Some(InstructionInfo::new("GT", 2, 1, GasPriceTier::VeryLow)); + arr[SLT as usize] = Some(InstructionInfo::new("SLT", 2, 1, GasPriceTier::VeryLow)); + arr[SGT as usize] = Some(InstructionInfo::new("SGT", 2, 1, GasPriceTier::VeryLow)); + arr[EQ as usize] = Some(InstructionInfo::new("EQ", 2, 1, GasPriceTier::VeryLow)); + arr[ISZERO as usize] = Some(InstructionInfo::new("ISZERO", 1, 1, GasPriceTier::VeryLow)); + arr[AND as usize] = Some(InstructionInfo::new("AND", 2, 1, GasPriceTier::VeryLow)); + arr[OR as usize] = Some(InstructionInfo::new("OR", 2, 1, GasPriceTier::VeryLow)); + arr[XOR as usize] = Some(InstructionInfo::new("XOR", 2, 1, GasPriceTier::VeryLow)); + arr[BYTE as usize] = Some(InstructionInfo::new("BYTE", 2, 1, GasPriceTier::VeryLow)); + arr[SHL as usize] = Some(InstructionInfo::new("SHL", 2, 1, GasPriceTier::VeryLow)); + arr[SHR as usize] = Some(InstructionInfo::new("SHR", 2, 1, GasPriceTier::VeryLow)); + arr[SAR as usize] = Some(InstructionInfo::new("SAR", 2, 1, GasPriceTier::VeryLow)); + arr[ADDMOD as usize] = Some(InstructionInfo::new("ADDMOD", 3, 1, GasPriceTier::Mid)); + arr[MULMOD as usize] = Some(InstructionInfo::new("MULMOD", 3, 1, GasPriceTier::Mid)); + arr[SIGNEXTEND as usize] = Some(InstructionInfo::new("SIGNEXTEND", 2, 1, GasPriceTier::Low)); + arr[RETURNDATASIZE as usize] = Some(InstructionInfo::new("RETURNDATASIZE", 0, 1, GasPriceTier::Base)); + arr[RETURNDATACOPY as usize] = Some(InstructionInfo::new("RETURNDATACOPY", 3, 0, GasPriceTier::VeryLow)); + arr[SHA3 as usize] = Some(InstructionInfo::new("SHA3", 2, 1, GasPriceTier::Special)); + arr[ADDRESS as usize] = Some(InstructionInfo::new("ADDRESS", 0, 1, GasPriceTier::Base)); + arr[BALANCE as usize] = Some(InstructionInfo::new("BALANCE", 1, 1, GasPriceTier::Special)); + arr[ORIGIN as usize] = Some(InstructionInfo::new("ORIGIN", 0, 1, GasPriceTier::Base)); + arr[CALLER as usize] = Some(InstructionInfo::new("CALLER", 0, 1, GasPriceTier::Base)); + arr[CALLVALUE as usize] = Some(InstructionInfo::new("CALLVALUE", 0, 1, GasPriceTier::Base)); + arr[CALLDATALOAD as usize] = Some(InstructionInfo::new("CALLDATALOAD", 1, 1, GasPriceTier::VeryLow)); + arr[CALLDATASIZE as usize] = Some(InstructionInfo::new("CALLDATASIZE", 0, 1, GasPriceTier::Base)); + arr[CALLDATACOPY as usize] = Some(InstructionInfo::new("CALLDATACOPY", 3, 0, GasPriceTier::VeryLow)); + arr[EXTCODEHASH as usize] = Some(InstructionInfo::new("EXTCODEHASH", 1, 1, GasPriceTier::Special)); + arr[CODESIZE as usize] = Some(InstructionInfo::new("CODESIZE", 0, 1, GasPriceTier::Base)); + arr[CODECOPY as usize] = Some(InstructionInfo::new("CODECOPY", 3, 0, GasPriceTier::VeryLow)); + arr[GASPRICE as usize] = Some(InstructionInfo::new("GASPRICE", 0, 1, GasPriceTier::Base)); + arr[EXTCODESIZE as usize] = Some(InstructionInfo::new("EXTCODESIZE", 1, 1, GasPriceTier::Special)); + arr[EXTCODECOPY as usize] = Some(InstructionInfo::new("EXTCODECOPY", 4, 0, GasPriceTier::Special)); + arr[BLOCKHASH as usize] = Some(InstructionInfo::new("BLOCKHASH", 1, 1, GasPriceTier::Ext)); + arr[COINBASE as usize] = Some(InstructionInfo::new("COINBASE", 0, 1, GasPriceTier::Base)); + arr[TIMESTAMP as usize] = Some(InstructionInfo::new("TIMESTAMP", 0, 1, GasPriceTier::Base)); + arr[NUMBER as usize] = Some(InstructionInfo::new("NUMBER", 0, 1, GasPriceTier::Base)); + arr[DIFFICULTY as usize] = Some(InstructionInfo::new("DIFFICULTY", 0, 1, GasPriceTier::Base)); + arr[GASLIMIT as usize] = Some(InstructionInfo::new("GASLIMIT", 0, 1, GasPriceTier::Base)); + arr[POP as usize] = Some(InstructionInfo::new("POP", 1, 0, GasPriceTier::Base)); + arr[MLOAD as usize] = Some(InstructionInfo::new("MLOAD", 1, 1, GasPriceTier::VeryLow)); + arr[MSTORE as usize] = Some(InstructionInfo::new("MSTORE", 2, 0, GasPriceTier::VeryLow)); + arr[MSTORE8 as usize] = Some(InstructionInfo::new("MSTORE8", 2, 0, GasPriceTier::VeryLow)); + arr[SLOAD as usize] = Some(InstructionInfo::new("SLOAD", 1, 1, GasPriceTier::Special)); + arr[SSTORE as usize] = Some(InstructionInfo::new("SSTORE", 2, 0, GasPriceTier::Special)); + arr[JUMP as usize] = Some(InstructionInfo::new("JUMP", 1, 0, GasPriceTier::Mid)); + arr[JUMPI as usize] = Some(InstructionInfo::new("JUMPI", 2, 0, GasPriceTier::High)); + arr[PC as usize] = Some(InstructionInfo::new("PC", 0, 1, GasPriceTier::Base)); + arr[MSIZE as usize] = Some(InstructionInfo::new("MSIZE", 0, 1, GasPriceTier::Base)); + arr[GAS as usize] = Some(InstructionInfo::new("GAS", 0, 1, GasPriceTier::Base)); + arr[JUMPDEST as usize] = Some(InstructionInfo::new("JUMPDEST", 0, 0, GasPriceTier::Special)); + arr[PUSH1 as usize] = Some(InstructionInfo::new("PUSH1", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH2 as usize] = Some(InstructionInfo::new("PUSH2", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH3 as usize] = Some(InstructionInfo::new("PUSH3", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH4 as usize] = Some(InstructionInfo::new("PUSH4", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH5 as usize] = Some(InstructionInfo::new("PUSH5", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH6 as usize] = Some(InstructionInfo::new("PUSH6", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH7 as usize] = Some(InstructionInfo::new("PUSH7", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH8 as usize] = Some(InstructionInfo::new("PUSH8", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH9 as usize] = Some(InstructionInfo::new("PUSH9", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH10 as usize] = Some(InstructionInfo::new("PUSH10", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH11 as usize] = Some(InstructionInfo::new("PUSH11", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH12 as usize] = Some(InstructionInfo::new("PUSH12", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH13 as usize] = Some(InstructionInfo::new("PUSH13", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH14 as usize] = Some(InstructionInfo::new("PUSH14", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH15 as usize] = Some(InstructionInfo::new("PUSH15", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH16 as usize] = Some(InstructionInfo::new("PUSH16", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH17 as usize] = Some(InstructionInfo::new("PUSH17", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH18 as usize] = Some(InstructionInfo::new("PUSH18", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH19 as usize] = Some(InstructionInfo::new("PUSH19", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH20 as usize] = Some(InstructionInfo::new("PUSH20", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH21 as usize] = Some(InstructionInfo::new("PUSH21", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH22 as usize] = Some(InstructionInfo::new("PUSH22", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH23 as usize] = Some(InstructionInfo::new("PUSH23", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH24 as usize] = Some(InstructionInfo::new("PUSH24", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH25 as usize] = Some(InstructionInfo::new("PUSH25", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH26 as usize] = Some(InstructionInfo::new("PUSH26", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH27 as usize] = Some(InstructionInfo::new("PUSH27", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH28 as usize] = Some(InstructionInfo::new("PUSH28", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH29 as usize] = Some(InstructionInfo::new("PUSH29", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH30 as usize] = Some(InstructionInfo::new("PUSH30", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH31 as usize] = Some(InstructionInfo::new("PUSH31", 0, 1, GasPriceTier::VeryLow)); + arr[PUSH32 as usize] = Some(InstructionInfo::new("PUSH32", 0, 1, GasPriceTier::VeryLow)); + arr[DUP1 as usize] = Some(InstructionInfo::new("DUP1", 1, 2, GasPriceTier::VeryLow)); + arr[DUP2 as usize] = Some(InstructionInfo::new("DUP2", 2, 3, GasPriceTier::VeryLow)); + arr[DUP3 as usize] = Some(InstructionInfo::new("DUP3", 3, 4, GasPriceTier::VeryLow)); + arr[DUP4 as usize] = Some(InstructionInfo::new("DUP4", 4, 5, GasPriceTier::VeryLow)); + arr[DUP5 as usize] = Some(InstructionInfo::new("DUP5", 5, 6, GasPriceTier::VeryLow)); + arr[DUP6 as usize] = Some(InstructionInfo::new("DUP6", 6, 7, GasPriceTier::VeryLow)); + arr[DUP7 as usize] = Some(InstructionInfo::new("DUP7", 7, 8, GasPriceTier::VeryLow)); + arr[DUP8 as usize] = Some(InstructionInfo::new("DUP8", 8, 9, GasPriceTier::VeryLow)); + arr[DUP9 as usize] = Some(InstructionInfo::new("DUP9", 9, 10, GasPriceTier::VeryLow)); + arr[DUP10 as usize] = Some(InstructionInfo::new("DUP10", 10, 11, GasPriceTier::VeryLow)); + arr[DUP11 as usize] = Some(InstructionInfo::new("DUP11", 11, 12, GasPriceTier::VeryLow)); + arr[DUP12 as usize] = Some(InstructionInfo::new("DUP12", 12, 13, GasPriceTier::VeryLow)); + arr[DUP13 as usize] = Some(InstructionInfo::new("DUP13", 13, 14, GasPriceTier::VeryLow)); + arr[DUP14 as usize] = Some(InstructionInfo::new("DUP14", 14, 15, GasPriceTier::VeryLow)); + arr[DUP15 as usize] = Some(InstructionInfo::new("DUP15", 15, 16, GasPriceTier::VeryLow)); + arr[DUP16 as usize] = Some(InstructionInfo::new("DUP16", 16, 17, GasPriceTier::VeryLow)); + arr[SWAP1 as usize] = Some(InstructionInfo::new("SWAP1", 2, 2, GasPriceTier::VeryLow)); + arr[SWAP2 as usize] = Some(InstructionInfo::new("SWAP2", 3, 3, GasPriceTier::VeryLow)); + arr[SWAP3 as usize] = Some(InstructionInfo::new("SWAP3", 4, 4, GasPriceTier::VeryLow)); + arr[SWAP4 as usize] = Some(InstructionInfo::new("SWAP4", 5, 5, GasPriceTier::VeryLow)); + arr[SWAP5 as usize] = Some(InstructionInfo::new("SWAP5", 6, 6, GasPriceTier::VeryLow)); + arr[SWAP6 as usize] = Some(InstructionInfo::new("SWAP6", 7, 7, GasPriceTier::VeryLow)); + arr[SWAP7 as usize] = Some(InstructionInfo::new("SWAP7", 8, 8, GasPriceTier::VeryLow)); + arr[SWAP8 as usize] = Some(InstructionInfo::new("SWAP8", 9, 9, GasPriceTier::VeryLow)); + arr[SWAP9 as usize] = Some(InstructionInfo::new("SWAP9", 10, 10, GasPriceTier::VeryLow)); + arr[SWAP10 as usize] = Some(InstructionInfo::new("SWAP10", 11, 11, GasPriceTier::VeryLow)); + arr[SWAP11 as usize] = Some(InstructionInfo::new("SWAP11", 12, 12, GasPriceTier::VeryLow)); + arr[SWAP12 as usize] = Some(InstructionInfo::new("SWAP12", 13, 13, GasPriceTier::VeryLow)); + arr[SWAP13 as usize] = Some(InstructionInfo::new("SWAP13", 14, 14, GasPriceTier::VeryLow)); + arr[SWAP14 as usize] = Some(InstructionInfo::new("SWAP14", 15, 15, GasPriceTier::VeryLow)); + arr[SWAP15 as usize] = Some(InstructionInfo::new("SWAP15", 16, 16, GasPriceTier::VeryLow)); + arr[SWAP16 as usize] = Some(InstructionInfo::new("SWAP16", 17, 17, GasPriceTier::VeryLow)); + arr[LOG0 as usize] = Some(InstructionInfo::new("LOG0", 2, 0, GasPriceTier::Special)); + arr[LOG1 as usize] = Some(InstructionInfo::new("LOG1", 3, 0, GasPriceTier::Special)); + arr[LOG2 as usize] = Some(InstructionInfo::new("LOG2", 4, 0, GasPriceTier::Special)); + arr[LOG3 as usize] = Some(InstructionInfo::new("LOG3", 5, 0, GasPriceTier::Special)); + arr[LOG4 as usize] = Some(InstructionInfo::new("LOG4", 6, 0, GasPriceTier::Special)); + arr[CREATE as usize] = Some(InstructionInfo::new("CREATE", 3, 1, GasPriceTier::Special)); + arr[CALL as usize] = Some(InstructionInfo::new("CALL", 7, 1, GasPriceTier::Special)); + arr[CALLCODE as usize] = Some(InstructionInfo::new("CALLCODE", 7, 1, GasPriceTier::Special)); + arr[RETURN as usize] = Some(InstructionInfo::new("RETURN", 2, 0, GasPriceTier::Zero)); + arr[DELEGATECALL as usize] = Some(InstructionInfo::new("DELEGATECALL", 6, 1, GasPriceTier::Special)); + arr[STATICCALL as usize] = Some(InstructionInfo::new("STATICCALL", 6, 1, GasPriceTier::Special)); + arr[SUICIDE as usize] = Some(InstructionInfo::new("SUICIDE", 1, 0, GasPriceTier::Special)); + arr[CREATE2 as usize] = Some(InstructionInfo::new("CREATE2", 4, 1, GasPriceTier::Special)); + arr[REVERT as usize] = Some(InstructionInfo::new("REVERT", 2, 0, GasPriceTier::Zero)); arr }; } -/// Virtual machine bytecode instruction. -/// halts execution -pub const STOP: Instruction = 0x00; -/// addition operation -pub const ADD: Instruction = 0x01; -/// mulitplication operation -pub const MUL: Instruction = 0x02; -/// subtraction operation -pub const SUB: Instruction = 0x03; -/// integer division operation -pub const DIV: Instruction = 0x04; -/// signed integer division operation -pub const SDIV: Instruction = 0x05; -/// modulo remainder operation -pub const MOD: Instruction = 0x06; -/// signed modulo remainder operation -pub const SMOD: Instruction = 0x07; -/// unsigned modular addition -pub const ADDMOD: Instruction = 0x08; -/// unsigned modular multiplication -pub const MULMOD: Instruction = 0x09; -/// exponential operation -pub const EXP: Instruction = 0x0a; -/// extend length of signed integer -pub const SIGNEXTEND: Instruction = 0x0b; - -/// less-than comparision -pub const LT: Instruction = 0x10; -/// greater-than comparision -pub const GT: Instruction = 0x11; -/// signed less-than comparision -pub const SLT: Instruction = 0x12; -/// signed greater-than comparision -pub const SGT: Instruction = 0x13; -/// equality comparision -pub const EQ: Instruction = 0x14; -/// simple not operator -pub const ISZERO: Instruction = 0x15; -/// bitwise AND operation -pub const AND: Instruction = 0x16; -/// bitwise OR operation -pub const OR: Instruction = 0x17; -/// bitwise XOR operation -pub const XOR: Instruction = 0x18; -/// bitwise NOT opertation -pub const NOT: Instruction = 0x19; -/// retrieve single byte from word -pub const BYTE: Instruction = 0x1a; -/// shift left operation -pub const SHL: Instruction = 0x1b; -/// logical shift right operation -pub const SHR: Instruction = 0x1c; -/// arithmetic shift right operation -pub const SAR: Instruction = 0x1d; - -/// compute SHA3-256 hash -pub const SHA3: Instruction = 0x20; - -/// get address of currently executing account -pub const ADDRESS: Instruction = 0x30; -/// get balance of the given account -pub const BALANCE: Instruction = 0x31; -/// get execution origination address -pub const ORIGIN: Instruction = 0x32; -/// get caller address -pub const CALLER: Instruction = 0x33; -/// get deposited value by the instruction/transaction responsible for this execution -pub const CALLVALUE: Instruction = 0x34; -/// get input data of current environment -pub const CALLDATALOAD: Instruction = 0x35; -/// get size of input data in current environment -pub const CALLDATASIZE: Instruction = 0x36; -/// copy input data in current environment to memory -pub const CALLDATACOPY: Instruction = 0x37; -/// get size of code running in current environment -pub const CODESIZE: Instruction = 0x38; -/// copy code running in current environment to memory -pub const CODECOPY: Instruction = 0x39; -/// get price of gas in current environment -pub const GASPRICE: Instruction = 0x3a; -/// get external code size (from another contract) -pub const EXTCODESIZE: Instruction = 0x3b; -/// copy external code (from another contract) -pub const EXTCODECOPY: Instruction = 0x3c; -/// get the size of the return data buffer for the last call -pub const RETURNDATASIZE: Instruction = 0x3d; -/// copy return data buffer to memory -pub const RETURNDATACOPY: Instruction = 0x3e; - -/// get hash of most recent complete block -pub const BLOCKHASH: Instruction = 0x40; -/// get the block's coinbase address -pub const COINBASE: Instruction = 0x41; -/// get the block's timestamp -pub const TIMESTAMP: Instruction = 0x42; -/// get the block's number -pub const NUMBER: Instruction = 0x43; -/// get the block's difficulty -pub const DIFFICULTY: Instruction = 0x44; -/// get the block's gas limit -pub const GASLIMIT: Instruction = 0x45; - -/// remove item from stack -pub const POP: Instruction = 0x50; -/// load word from memory -pub const MLOAD: Instruction = 0x51; -/// save word to memory -pub const MSTORE: Instruction = 0x52; -/// save byte to memory -pub const MSTORE8: Instruction = 0x53; -/// load word from storage -pub const SLOAD: Instruction = 0x54; -/// save word to storage -pub const SSTORE: Instruction = 0x55; -/// alter the program counter -pub const JUMP: Instruction = 0x56; -/// conditionally alter the program counter -pub const JUMPI: Instruction = 0x57; -/// get the program counter -pub const PC: Instruction = 0x58; -/// get the size of active memory -pub const MSIZE: Instruction = 0x59; -/// get the amount of available gas -pub const GAS: Instruction = 0x5a; -/// set a potential jump destination -pub const JUMPDEST: Instruction = 0x5b; - -/// place 1 byte item on stack -pub const PUSH1: Instruction = 0x60; -/// place 2 byte item on stack -pub const PUSH2: Instruction = 0x61; -/// place 3 byte item on stack -pub const PUSH3: Instruction = 0x62; -/// place 4 byte item on stack -pub const PUSH4: Instruction = 0x63; -/// place 5 byte item on stack -pub const PUSH5: Instruction = 0x64; -/// place 6 byte item on stack -pub const PUSH6: Instruction = 0x65; -/// place 7 byte item on stack -pub const PUSH7: Instruction = 0x66; -/// place 8 byte item on stack -pub const PUSH8: Instruction = 0x67; -/// place 9 byte item on stack -pub const PUSH9: Instruction = 0x68; -/// place 10 byte item on stack -pub const PUSH10: Instruction = 0x69; -/// place 11 byte item on stack -pub const PUSH11: Instruction = 0x6a; -/// place 12 byte item on stack -pub const PUSH12: Instruction = 0x6b; -/// place 13 byte item on stack -pub const PUSH13: Instruction = 0x6c; -/// place 14 byte item on stack -pub const PUSH14: Instruction = 0x6d; -/// place 15 byte item on stack -pub const PUSH15: Instruction = 0x6e; -/// place 16 byte item on stack -pub const PUSH16: Instruction = 0x6f; -/// place 17 byte item on stack -pub const PUSH17: Instruction = 0x70; -/// place 18 byte item on stack -pub const PUSH18: Instruction = 0x71; -/// place 19 byte item on stack -pub const PUSH19: Instruction = 0x72; -/// place 20 byte item on stack -pub const PUSH20: Instruction = 0x73; -/// place 21 byte item on stack -pub const PUSH21: Instruction = 0x74; -/// place 22 byte item on stack -pub const PUSH22: Instruction = 0x75; -/// place 23 byte item on stack -pub const PUSH23: Instruction = 0x76; -/// place 24 byte item on stack -pub const PUSH24: Instruction = 0x77; -/// place 25 byte item on stack -pub const PUSH25: Instruction = 0x78; -/// place 26 byte item on stack -pub const PUSH26: Instruction = 0x79; -/// place 27 byte item on stack -pub const PUSH27: Instruction = 0x7a; -/// place 28 byte item on stack -pub const PUSH28: Instruction = 0x7b; -/// place 29 byte item on stack -pub const PUSH29: Instruction = 0x7c; -/// place 30 byte item on stack -pub const PUSH30: Instruction = 0x7d; -/// place 31 byte item on stack -pub const PUSH31: Instruction = 0x7e; -/// place 32 byte item on stack -pub const PUSH32: Instruction = 0x7f; - -/// copies the highest item in the stack to the top of the stack -pub const DUP1: Instruction = 0x80; -/// copies the second highest item in the stack to the top of the stack -pub const DUP2: Instruction = 0x81; -/// copies the third highest item in the stack to the top of the stack -pub const DUP3: Instruction = 0x82; -/// copies the 4th highest item in the stack to the top of the stack -pub const DUP4: Instruction = 0x83; -/// copies the 5th highest item in the stack to the top of the stack -pub const DUP5: Instruction = 0x84; -/// copies the 6th highest item in the stack to the top of the stack -pub const DUP6: Instruction = 0x85; -/// copies the 7th highest item in the stack to the top of the stack -pub const DUP7: Instruction = 0x86; -/// copies the 8th highest item in the stack to the top of the stack -pub const DUP8: Instruction = 0x87; -/// copies the 9th highest item in the stack to the top of the stack -pub const DUP9: Instruction = 0x88; -/// copies the 10th highest item in the stack to the top of the stack -pub const DUP10: Instruction = 0x89; -/// copies the 11th highest item in the stack to the top of the stack -pub const DUP11: Instruction = 0x8a; -/// copies the 12th highest item in the stack to the top of the stack -pub const DUP12: Instruction = 0x8b; -/// copies the 13th highest item in the stack to the top of the stack -pub const DUP13: Instruction = 0x8c; -/// copies the 14th highest item in the stack to the top of the stack -pub const DUP14: Instruction = 0x8d; -/// copies the 15th highest item in the stack to the top of the stack -pub const DUP15: Instruction = 0x8e; -/// copies the 16th highest item in the stack to the top of the stack -pub const DUP16: Instruction = 0x8f; - -/// swaps the highest and second highest value on the stack -pub const SWAP1: Instruction = 0x90; -/// swaps the highest and third highest value on the stack -pub const SWAP2: Instruction = 0x91; -/// swaps the highest and 4th highest value on the stack -pub const SWAP3: Instruction = 0x92; -/// swaps the highest and 5th highest value on the stack -pub const SWAP4: Instruction = 0x93; -/// swaps the highest and 6th highest value on the stack -pub const SWAP5: Instruction = 0x94; -/// swaps the highest and 7th highest value on the stack -pub const SWAP6: Instruction = 0x95; -/// swaps the highest and 8th highest value on the stack -pub const SWAP7: Instruction = 0x96; -/// swaps the highest and 9th highest value on the stack -pub const SWAP8: Instruction = 0x97; -/// swaps the highest and 10th highest value on the stack -pub const SWAP9: Instruction = 0x98; -/// swaps the highest and 11th highest value on the stack -pub const SWAP10: Instruction = 0x99; -/// swaps the highest and 12th highest value on the stack -pub const SWAP11: Instruction = 0x9a; -/// swaps the highest and 13th highest value on the stack -pub const SWAP12: Instruction = 0x9b; -/// swaps the highest and 14th highest value on the stack -pub const SWAP13: Instruction = 0x9c; -/// swaps the highest and 15th highest value on the stack -pub const SWAP14: Instruction = 0x9d; -/// swaps the highest and 16th highest value on the stack -pub const SWAP15: Instruction = 0x9e; -/// swaps the highest and 17th highest value on the stack -pub const SWAP16: Instruction = 0x9f; - -/// Makes a log entry; no topics. -pub const LOG0: Instruction = 0xa0; -/// Makes a log entry; 1 topic. -pub const LOG1: Instruction = 0xa1; -/// Makes a log entry; 2 topics. -pub const LOG2: Instruction = 0xa2; -/// Makes a log entry; 3 topics. -pub const LOG3: Instruction = 0xa3; -/// Makes a log entry; 4 topics. -pub const LOG4: Instruction = 0xa4; /// Maximal number of topics for log instructions -pub const MAX_NO_OF_TOPICS : usize = 4; - -/// create a new account with associated code -pub const CREATE: Instruction = 0xf0; -/// message-call into an account -pub const CALL: Instruction = 0xf1; -/// message-call with another account's code only -pub const CALLCODE: Instruction = 0xf2; -/// halt execution returning output data -pub const RETURN: Instruction = 0xf3; -/// like CALLCODE but keeps caller's value and sender -pub const DELEGATECALL: Instruction = 0xf4; -/// create a new account and set creation address to sha3(sender + sha3(init code)) % 2**160 -pub const CREATE2: Instruction = 0xfb; -/// stop execution and revert state changes. Return output data. -pub const REVERT: Instruction = 0xfd; -/// like CALL but it does not take value, nor modify the state -pub const STATICCALL: Instruction = 0xfa; -/// halt execution and register account for later deletion -pub const SUICIDE: Instruction = 0xff; +pub const MAX_NO_OF_TOPICS: usize = 4; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_is_push() { + assert!(PUSH1.is_push()); + assert!(PUSH32.is_push()); + assert!(!DUP1.is_push()); + } + + #[test] + fn test_get_push_bytes() { + assert_eq!(PUSH1.push_bytes(), Some(1)); + assert_eq!(PUSH3.push_bytes(), Some(3)); + assert_eq!(PUSH32.push_bytes(), Some(32)); + } + + #[test] + fn test_get_dup_position() { + assert_eq!(DUP1.dup_position(), Some(0)); + assert_eq!(DUP5.dup_position(), Some(4)); + assert_eq!(DUP10.dup_position(), Some(9)); + } + + #[test] + fn test_get_swap_position() { + assert_eq!(SWAP1.swap_position(), Some(1)); + assert_eq!(SWAP5.swap_position(), Some(5)); + assert_eq!(SWAP10.swap_position(), Some(10)); + } + + #[test] + fn test_get_log_topics() { + assert_eq!(LOG0.log_topics(), Some(0)); + assert_eq!(LOG2.log_topics(), Some(2)); + assert_eq!(LOG4.log_topics(), Some(4)); + } +} diff --git a/ethcore/evm/src/interpreter/gasometer.rs b/ethcore/evm/src/interpreter/gasometer.rs index beb22447fe4c08257d27868c040e93d8d2d87db9..78a33ef3ead468c9786cafc14f86419cc99b8b85 100644 --- a/ethcore/evm/src/interpreter/gasometer.rs +++ b/ethcore/evm/src/interpreter/gasometer.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -113,7 +113,7 @@ impl Gasometer { current_mem_size: usize, ) -> vm::Result> { let schedule = ext.schedule(); - let tier = instructions::get_tier_idx(info.tier); + let tier = info.tier.idx(); let default_gas = Gas::from(schedule.tier_step_gas[tier]); let cost = match instruction { @@ -143,6 +143,9 @@ impl Gasometer { instructions::EXTCODESIZE => { Request::Gas(Gas::from(schedule.extcodesize_gas)) }, + instructions::EXTCODEHASH => { + Request::Gas(Gas::from(schedule.extcodehash_gas)) + }, instructions::SUICIDE => { let mut gas = Gas::from(schedule.suicide_gas); @@ -179,8 +182,8 @@ impl Gasometer { instructions::EXTCODECOPY => { Request::GasMemCopy(schedule.extcodecopy_base_gas.into(), mem_needed(stack.peek(1), stack.peek(3))?, Gas::from_u256(*stack.peek(3))?) }, - instructions::LOG0...instructions::LOG4 => { - let no_of_topics = instructions::get_log_topics(instruction); + instructions::LOG0 | instructions::LOG1 | instructions::LOG2 | instructions::LOG3 | instructions::LOG4 => { + let no_of_topics = instruction.log_topics().expect("log_topics always return some for LOG* instructions; qed"); let log_gas = schedule.log_gas + schedule.log_topic_gas * no_of_topics; let data_gas = overflowing!(Gas::from_u256(*stack.peek(1))?.overflow_mul(Gas::from(schedule.log_data_gas))); @@ -225,7 +228,11 @@ impl Gasometer { }, instructions::CREATE | instructions::CREATE2 => { let gas = Gas::from(schedule.create_gas); - let mem = mem_needed(stack.peek(1), stack.peek(2))?; + let mem = match instruction { + instructions::CREATE => mem_needed(stack.peek(1), stack.peek(2))?, + instructions::CREATE2 => mem_needed(stack.peek(2), stack.peek(3))?, + _ => unreachable!("instruction can only be CREATE/CREATE2 checked above; qed"), + }; Request::GasMemProvide(gas, mem, None) }, @@ -316,7 +323,6 @@ impl Gasometer { } } - #[inline] fn mem_needed_const(mem: &U256, add: usize) -> vm::Result { Gas::from_u256(overflowing!(mem.overflowing_add(U256::from(add)))) @@ -369,4 +375,3 @@ fn test_calculate_mem_cost() { assert_eq!(new_mem_gas, 3); assert_eq!(mem_size, 32); } - diff --git a/ethcore/evm/src/interpreter/informant.rs b/ethcore/evm/src/interpreter/informant.rs index f07d11ff7aa5f3a86f5020eff29a0bc624efb5de..8ae57a97f1711e15ddbd835206065aa8d99da610 100644 --- a/ethcore/evm/src/interpreter/informant.rs +++ b/ethcore/evm/src/interpreter/informant.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -39,7 +39,7 @@ mod inner { use std::collections::HashMap; use std::time::{Instant, Duration}; - use bigint::prelude::U256; + use ethereum_types::U256; use interpreter::stack::Stack; use instructions::{Instruction, InstructionInfo, INSTRUCTIONS}; diff --git a/ethcore/evm/src/interpreter/memory.rs b/ethcore/evm/src/interpreter/memory.rs index f646d01985d83dce2f1dc95e1b25c1e729ce1844..843aeef3b5787ae3645209c5807c1dba74dbc151 100644 --- a/ethcore/evm/src/interpreter/memory.rs +++ b/ethcore/evm/src/interpreter/memory.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index 160a2e5b1d37a6e507a1a6934a8e6baba34919fe..3af1e34dd36d7a444c2b8d1e12009efaba10ddb0 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -64,7 +64,6 @@ struct CodeReader<'a> { } impl<'a> CodeReader<'a> { - /// Create new code reader - starting at position 0. fn new(code: &'a [u8]) -> Self { CodeReader { @@ -81,7 +80,7 @@ impl<'a> CodeReader<'a> { U256::from(&self.code[pos..max]) } - fn len (&self) -> usize { + fn len(&self) -> usize { self.code.len() } } @@ -103,7 +102,6 @@ enum InstructionResult { StopExecution, } - /// Intepreter EVM implementation pub struct Interpreter { mem: Vec, @@ -125,24 +123,31 @@ impl vm::Vm for Interpreter { let mut gasometer = Gasometer::::new(Cost::from_u256(params.gas)?); let mut stack = VecStack::with_capacity(ext.schedule().stack_limit, U256::zero()); let mut reader = CodeReader::new(code); - let infos = &*instructions::INSTRUCTIONS; while reader.position < code.len() { - let instruction = code[reader.position]; + let opcode = code[reader.position]; + let instruction = Instruction::from_u8(opcode); reader.position += 1; // TODO: make compile-time removable if too much of a performance hit. do_trace = do_trace && ext.trace_next_instruction( - reader.position - 1, instruction, gasometer.current_gas.as_u256(), + reader.position - 1, opcode, gasometer.current_gas.as_u256(), ); - let info = &infos[instruction as usize]; + if instruction.is_none() { + return Err(vm::Error::BadInstruction { + instruction: opcode + }); + } + let instruction = instruction.expect("None case is checked above; qed"); + + let info = instruction.info(); self.verify_instruction(ext, instruction, info, &stack)?; // Calculate gas cost let requirements = gasometer.requirements(ext, instruction, info, &stack, self.mem.size())?; if do_trace { - ext.trace_prepare_execute(reader.position - 1, instruction, requirements.gas_cost.as_u256()); + ext.trace_prepare_execute(reader.position - 1, opcode, requirements.gas_cost.as_u256()); } gasometer.verify_gas(&requirements.gas_cost)?; @@ -225,16 +230,11 @@ impl Interpreter { (instruction == instructions::STATICCALL && !schedule.have_static_call) || ((instruction == instructions::RETURNDATACOPY || instruction == instructions::RETURNDATASIZE) && !schedule.have_return_data) || (instruction == instructions::REVERT && !schedule.have_revert) || - ((instruction == instructions::SHL || instruction == instructions::SHR || instruction == instructions::SAR) && !schedule.have_bitwise_shifting) { - - return Err(vm::Error::BadInstruction { - instruction: instruction - }); - } - - if info.tier == instructions::GasPriceTier::Invalid { + ((instruction == instructions::SHL || instruction == instructions::SHR || instruction == instructions::SAR) && !schedule.have_bitwise_shifting) || + (instruction == instructions::EXTCODEHASH && !schedule.have_extcodehash) + { return Err(vm::Error::BadInstruction { - instruction: instruction + instruction: instruction as u8 }); } @@ -317,6 +317,11 @@ impl Interpreter { }, instructions::CREATE | instructions::CREATE2 => { let endowment = stack.pop_back(); + let address_scheme = match instruction { + instructions::CREATE => CreateContractAddress::FromSenderAndNonce, + instructions::CREATE2 => CreateContractAddress::FromSenderSaltAndCodeHash(stack.pop_back().into()), + _ => unreachable!("instruction can only be CREATE/CREATE2 checked above; qed"), + }; let init_off = stack.pop_back(); let init_size = stack.pop_back(); @@ -336,7 +341,6 @@ impl Interpreter { } let contract_code = self.mem.read_slice(init_off, init_size); - let address_scheme = if instruction == instructions::CREATE { CreateContractAddress::FromSenderAndNonce } else { CreateContractAddress::FromSenderAndCodeHash }; let create_result = ext.create(&create_gas.as_u256(), &endowment, contract_code, address_scheme); return match create_result { @@ -397,7 +401,7 @@ impl Interpreter { }, instructions::DELEGATECALL => (¶ms.sender, ¶ms.address, true, CallType::DelegateCall), instructions::STATICCALL => (¶ms.address, &code_address, true, CallType::StaticCall), - _ => panic!(format!("Unexpected instruction {} in CALL branch.", instruction)) + _ => panic!(format!("Unexpected instruction {:?} in CALL branch.", instruction)) }; // clear return data buffer before creating new call frame. @@ -454,8 +458,8 @@ impl Interpreter { ext.suicide(&u256_to_address(&address))?; return Ok(InstructionResult::StopExecution); }, - instructions::LOG0...instructions::LOG4 => { - let no_of_topics = instructions::get_log_topics(instruction); + instructions::LOG0 | instructions::LOG1 | instructions::LOG2 | instructions::LOG3 | instructions::LOG4 => { + let no_of_topics = instruction.log_topics().expect("log_topics always return some for LOG* instructions; qed"); let offset = stack.pop_back(); let size = stack.pop_back(); @@ -465,8 +469,15 @@ impl Interpreter { .collect(); ext.log(topics, self.mem.read_slice(offset, size))?; }, - instructions::PUSH1...instructions::PUSH32 => { - let bytes = instructions::get_push_bytes(instruction); + instructions::PUSH1 | instructions::PUSH2 | instructions::PUSH3 | instructions::PUSH4 | + instructions::PUSH5 | instructions::PUSH6 | instructions::PUSH7 | instructions::PUSH8 | + instructions::PUSH9 | instructions::PUSH10 | instructions::PUSH11 | instructions::PUSH12 | + instructions::PUSH13 | instructions::PUSH14 | instructions::PUSH15 | instructions::PUSH16 | + instructions::PUSH17 | instructions::PUSH18 | instructions::PUSH19 | instructions::PUSH20 | + instructions::PUSH21 | instructions::PUSH22 | instructions::PUSH23 | instructions::PUSH24 | + instructions::PUSH25 | instructions::PUSH26 | instructions::PUSH27 | instructions::PUSH28 | + instructions::PUSH29 | instructions::PUSH30 | instructions::PUSH31 | instructions::PUSH32 => { + let bytes = instruction.push_bytes().expect("push_bytes always return some for PUSH* instructions"); let val = code.read(bytes); stack.push(val); }, @@ -562,9 +573,14 @@ impl Interpreter { }, instructions::EXTCODESIZE => { let address = u256_to_address(&stack.pop_back()); - let len = ext.extcodesize(&address)?; + let len = ext.extcodesize(&address)?.unwrap_or(0); stack.push(U256::from(len)); }, + instructions::EXTCODEHASH => { + let address = u256_to_address(&stack.pop_back()); + let hash = ext.extcodehash(&address)?.unwrap_or_else(H256::zero); + stack.push(U256::from(hash)); + }, instructions::CALLDATACOPY => { Self::copy_data_to_memory(&mut self.mem, stack, params.data.as_ref().map_or_else(|| &[] as &[u8], |d| &*d as &[u8])); }, @@ -585,7 +601,11 @@ impl Interpreter { instructions::EXTCODECOPY => { let address = u256_to_address(&stack.pop_back()); let code = ext.extcode(&address)?; - Self::copy_data_to_memory(&mut self.mem, stack, &code); + Self::copy_data_to_memory( + &mut self.mem, + stack, + code.as_ref().map(|c| &(*c)[..]).unwrap_or(&[]) + ); }, instructions::GASPRICE => { stack.push(params.gas_price.clone()); @@ -610,73 +630,22 @@ impl Interpreter { instructions::GASLIMIT => { stack.push(ext.env_info().gas_limit.clone()); }, - _ => { - self.exec_stack_instruction(instruction, stack)?; - } - }; - Ok(InstructionResult::Ok) - } - fn copy_data_to_memory(mem: &mut Vec, stack: &mut Stack, source: &[u8]) { - let dest_offset = stack.pop_back(); - let source_offset = stack.pop_back(); - let size = stack.pop_back(); - let source_size = U256::from(source.len()); + // Stack instructions - let output_end = match source_offset > source_size || size > source_size || source_offset + size > source_size { - true => { - let zero_slice = if source_offset > source_size { - mem.writeable_slice(dest_offset, size) - } else { - mem.writeable_slice(dest_offset + source_size - source_offset, source_offset + size - source_size) - }; - for i in zero_slice.iter_mut() { - *i = 0; - } - source.len() - }, - false => (size.low_u64() + source_offset.low_u64()) as usize - }; - - if source_offset < source_size { - let output_begin = source_offset.low_u64() as usize; - mem.write_slice(dest_offset, &source[output_begin..output_end]); - } - } - - fn verify_jump(&self, jump_u: U256, valid_jump_destinations: &BitSet) -> vm::Result { - let jump = jump_u.low_u64() as usize; - - if valid_jump_destinations.contains(jump) && U256::from(jump) == jump_u { - Ok(jump) - } else { - Err(vm::Error::BadJumpDestination { - destination: jump - }) - } - } - - fn is_zero(&self, val: &U256) -> bool { - val.is_zero() - } - - fn bool_to_u256(&self, val: bool) -> U256 { - if val { - U256::one() - } else { - U256::zero() - } - } - - fn exec_stack_instruction(&self, instruction: Instruction, stack: &mut Stack) -> vm::Result<()> { - match instruction { - instructions::DUP1...instructions::DUP16 => { - let position = instructions::get_dup_position(instruction); + instructions::DUP1 | instructions::DUP2 | instructions::DUP3 | instructions::DUP4 | + instructions::DUP5 | instructions::DUP6 | instructions::DUP7 | instructions::DUP8 | + instructions::DUP9 | instructions::DUP10 | instructions::DUP11 | instructions::DUP12 | + instructions::DUP13 | instructions::DUP14 | instructions::DUP15 | instructions::DUP16 => { + let position = instruction.dup_position().expect("dup_position always return some for DUP* instructions"); let val = stack.peek(position).clone(); stack.push(val); }, - instructions::SWAP1...instructions::SWAP16 => { - let position = instructions::get_swap_position(instruction); + instructions::SWAP1 | instructions::SWAP2 | instructions::SWAP3 | instructions::SWAP4 | + instructions::SWAP5 | instructions::SWAP6 | instructions::SWAP7 | instructions::SWAP8 | + instructions::SWAP9 | instructions::SWAP10 | instructions::SWAP11 | instructions::SWAP12 | + instructions::SWAP13 | instructions::SWAP14 | instructions::SWAP15 | instructions::SWAP16 => { + let position = instruction.swap_position().expect("swap_position always return some for SWAP* instructions"); stack.swap_with_top(position) }, instructions::POP => { @@ -924,15 +893,60 @@ impl Interpreter { }; stack.push(result); }, - _ => { - return Err(vm::Error::BadInstruction { - instruction: instruction - }); - } + }; + Ok(InstructionResult::Ok) + } + + fn copy_data_to_memory(mem: &mut Vec, stack: &mut Stack, source: &[u8]) { + let dest_offset = stack.pop_back(); + let source_offset = stack.pop_back(); + let size = stack.pop_back(); + let source_size = U256::from(source.len()); + + let output_end = match source_offset > source_size || size > source_size || source_offset + size > source_size { + true => { + let zero_slice = if source_offset > source_size { + mem.writeable_slice(dest_offset, size) + } else { + mem.writeable_slice(dest_offset + source_size - source_offset, source_offset + size - source_size) + }; + for i in zero_slice.iter_mut() { + *i = 0; + } + source.len() + }, + false => (size.low_u64() + source_offset.low_u64()) as usize + }; + + if source_offset < source_size { + let output_begin = source_offset.low_u64() as usize; + mem.write_slice(dest_offset, &source[output_begin..output_end]); } - Ok(()) } + fn verify_jump(&self, jump_u: U256, valid_jump_destinations: &BitSet) -> vm::Result { + let jump = jump_u.low_u64() as usize; + + if valid_jump_destinations.contains(jump) && U256::from(jump) == jump_u { + Ok(jump) + } else { + Err(vm::Error::BadJumpDestination { + destination: jump + }) + } + } + + fn is_zero(&self, val: &U256) -> bool { + val.is_zero() + } + + fn bool_to_u256(&self, val: bool) -> U256 { + if val { + U256::one() + } else { + U256::zero() + } + } } fn get_and_reset_sign(value: U256) -> (U256, bool) { @@ -959,7 +973,6 @@ fn address_to_u256(value: Address) -> U256 { U256::from(&*H256::from(value)) } - #[cfg(test)] mod tests { use std::sync::Arc; diff --git a/ethcore/evm/src/interpreter/shared_cache.rs b/ethcore/evm/src/interpreter/shared_cache.rs index 30bc5b677d5243a9f6d593f98923e96b680e752f..f4a7f47f90f40c6e43d0623838d57863b9e10f88 100644 --- a/ethcore/evm/src/interpreter/shared_cache.rs +++ b/ethcore/evm/src/interpreter/shared_cache.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -21,7 +21,7 @@ use ethereum_types::H256; use parking_lot::Mutex; use memory_cache::MemoryLruCache; use bit_set::BitSet; -use super::super::instructions; +use super::super::instructions::{self, Instruction}; const DEFAULT_CACHE_SIZE: usize = 4 * 1024 * 1024; @@ -70,12 +70,14 @@ impl SharedCache { let mut position = 0; while position < code.len() { - let instruction = code[position]; - - if instruction == instructions::JUMPDEST { - jump_dests.insert(position); - } else if instructions::is_push(instruction) { - position += instructions::get_push_bytes(instruction); + let instruction = Instruction::from_u8(code[position]); + + if let Some(instruction) = instruction { + if instruction == instructions::JUMPDEST { + jump_dests.insert(position); + } else if let Some(push_bytes) = instruction.push_bytes() { + position += push_bytes; + } } position += 1; } @@ -91,7 +93,6 @@ impl Default for SharedCache { } } - #[test] fn test_find_jump_destinations() { use rustc_hex::FromHex; diff --git a/ethcore/evm/src/interpreter/stack.rs b/ethcore/evm/src/interpreter/stack.rs index cbe40fb67fbaec88c1176de2f8a4965b7e962ee4..3902b8ff7678fae888e9b0a926635c8372319e3d 100644 --- a/ethcore/evm/src/interpreter/stack.rs +++ b/ethcore/evm/src/interpreter/stack.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -95,4 +95,3 @@ impl Stack for VecStack { &self.stack[self.stack.len() - no_from_top .. self.stack.len()] } } - diff --git a/ethcore/evm/src/lib.rs b/ethcore/evm/src/lib.rs index 263a11d6824e919be8960be8022609f5797472d4..cd326a317ecd510c4d8619d8e041a1f24ff1608b 100644 --- a/ethcore/evm/src/lib.rs +++ b/ethcore/evm/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -43,7 +43,7 @@ mod instructions; #[cfg(test)] mod tests; -#[cfg(all(feature="benches", test))] +#[cfg(all(feature = "benches", test))] mod benches; pub use vm::{ @@ -52,6 +52,6 @@ pub use vm::{ GasLeft, ReturnData }; pub use self::evm::{Finalize, FinalizationResult, CostType}; -pub use self::instructions::{InstructionInfo, INSTRUCTIONS, push_bytes}; +pub use self::instructions::{InstructionInfo, Instruction}; pub use self::vmtype::VMType; pub use self::factory::Factory; diff --git a/ethcore/evm/src/tests.rs b/ethcore/evm/src/tests.rs index 9058d073e80cb0c6ad49ce78d3e6182fd459c26f..b62faf87d773b3e7b5525e6b63be2ab05c26c8b8 100644 --- a/ethcore/evm/src/tests.rs +++ b/ethcore/evm/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/evm/src/vmtype.rs b/ethcore/evm/src/vmtype.rs index b3a8aaf3e9facf05a64e24847ef1d7ac64cf236e..feb567b73d9a9127df863e346db65bd96e27c8ee 100644 --- a/ethcore/evm/src/vmtype.rs +++ b/ethcore/evm/src/vmtype.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/Cargo.toml b/ethcore/light/Cargo.toml index 3853ad910ff5a1f99bbc16127e3cd55dd0594199..6c3a454e20a9c80667d7ebc4c2d7e6eb49881f3d 100644 --- a/ethcore/light/Cargo.toml +++ b/ethcore/light/Cargo.toml @@ -9,18 +9,19 @@ authors = ["Parity Technologies "] [dependencies] log = "0.3" ethcore = { path = ".."} -ethcore-bytes = { path = "../../util/bytes" } +parity-bytes = { git = "https://github.com/paritytech/parity-common" } ethcore-transaction = { path = "../transaction" } ethereum-types = "0.3" -memorydb = { path = "../../util/memorydb" } -patricia-trie = { path = "../../util/patricia_trie" } +memorydb = { git = "https://github.com/paritytech/parity-common" } +patricia-trie = { git = "https://github.com/paritytech/parity-common" } +patricia-trie-ethereum = { path = "../../util/patricia-trie-ethereum" } ethcore-network = { path = "../../util/network" } ethcore-io = { path = "../../util/io" } -hashdb = { path = "../../util/hashdb" } +hashdb = { git = "https://github.com/paritytech/parity-common" } heapsize = "0.4" vm = { path = "../vm" } -plain_hasher = { path = "../../util/plain_hasher" } -rlp = { path = "../../util/rlp" } +plain_hasher = { git = "https://github.com/paritytech/parity-common" } +rlp = { git = "https://github.com/paritytech/parity-common" } rlp_derive = { path = "../../util/rlp_derive" } smallvec = "0.4" futures = "0.1" @@ -29,16 +30,18 @@ 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" } -triehash = { path = "../../util/triehash" } -kvdb = { path = "../../util/kvdb" } +keccak-hash = { git = "https://github.com/paritytech/parity-common" } +keccak-hasher = { path = "../../util/keccak-hasher" } +triehash-ethereum = { version = "0.2", path = "../../util/triehash-ethereum" } +kvdb = { git = "https://github.com/paritytech/parity-common" } memory-cache = { path = "../../util/memory_cache" } -error-chain = { version = "0.11", default-features = false } +error-chain = { version = "0.12", default-features = false } [dev-dependencies] -kvdb-memorydb = { path = "../../util/kvdb-memorydb" } +ethcore = { path = "..", features = ["test-helpers"] } +kvdb-memorydb = { git = "https://github.com/paritytech/parity-common" } tempdir = "0.3" [features] diff --git a/ethcore/light/src/cache.rs b/ethcore/light/src/cache.rs index b63fd07576e005fd92b7058fdee045b34418aaca..7b6324a9912cd4b5605153b09103c4c86cbf9141 100644 --- a/ethcore/light/src/cache.rs +++ b/ethcore/light/src/cache.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/cht.rs b/ethcore/light/src/cht.rs index ffb7841f45ad8d99306b5bbc1a6f4dab96a344e0..18b0e5b06c9776fabb6a9c3bc82aa337314c6da9 100644 --- a/ethcore/light/src/cht.rs +++ b/ethcore/light/src/cht.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -11,6 +11,9 @@ // 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 . + //! Canonical hash trie definitions and helper functions. //! //! Each CHT is a trie mapping block numbers to canonical hashes and total difficulty. @@ -23,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. @@ -47,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 } @@ -63,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); @@ -87,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; @@ -144,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/fetch.rs b/ethcore/light/src/client/fetch.rs index 86269c695fc4b6aa422a84cd5987410b52e0d7a2..b0f73534962d1ef67584b55099b9cc7f3fffef32 100644 --- a/ethcore/light/src/client/fetch.rs +++ b/ethcore/light/src/client/fetch.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/client/header_chain.rs b/ethcore/light/src/client/header_chain.rs index 60c7d288a76120c249765b991709bceac356c168..957a1ea4330534070815ce1a117d3277b0e633d7 100644 --- a/ethcore/light/src/client/header_chain.rs +++ b/ethcore/light/src/client/header_chain.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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, ErrorKind, 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. @@ -260,7 +253,7 @@ impl HeaderChain { let best_block = { let era = match candidates.get(&curr.best_num) { Some(era) => era, - None => bail!(ErrorKind::Database("Database corrupt: highest block referenced but no data.".into())), + None => bail!("Database corrupt: highest block referenced but no data."), }; let best = &era.candidates[0]; @@ -583,7 +576,7 @@ impl HeaderChain { } else { let msg = format!("header of block #{} not found in DB ; database in an \ inconsistent state", h_num); - bail!(ErrorKind::Database(msg.into())); + bail!(msg); }; let decoded = header.decode().expect("decoding db value failed"); @@ -591,9 +584,8 @@ impl HeaderChain { let entry: Entry = { let bytes = self.db.get(self.col, era_key(h_num).as_bytes())? .ok_or_else(|| { - let msg = format!("entry for era #{} not found in DB ; database \ - in an inconsistent state", h_num); - ErrorKind::Database(msg.into()) + format!("entry for era #{} not found in DB ; database \ + in an inconsistent state", h_num) })?; ::rlp::decode(&bytes).expect("decoding db value failed") }; @@ -601,9 +593,8 @@ impl HeaderChain { let total_difficulty = entry.candidates.iter() .find(|c| c.hash == decoded.hash()) .ok_or_else(|| { - let msg = "no candidate matching block found in DB ; database in an \ - inconsistent state"; - ErrorKind::Database(msg.into()) + "no candidate matching block found in DB ; database in an \ + inconsistent state" })? .total_difficulty; diff --git a/ethcore/light/src/client/mod.rs b/ethcore/light/src/client/mod.rs index 82b424cc833eedbb3635404c2d3499d4f0e54466..a1625b0e8f3ac1f8fcb1c570b809d03488639750 100644 --- a/ethcore/light/src/client/mod.rs +++ b/ethcore/light/src/client/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -463,7 +463,6 @@ impl Client { loop { - let is_signal = { let auxiliary = AuxiliaryData { bytes: block.as_ref().map(|x| &x[..]), diff --git a/ethcore/light/src/client/service.rs b/ethcore/light/src/client/service.rs index a3ec8a36866f6c25f50b214b57981aff609cf81e..8c6ef44faeffed0146cce8c0902dd59177f77e1c 100644 --- a/ethcore/light/src/client/service.rs +++ b/ethcore/light/src/client/service.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -21,11 +21,10 @@ use std::fmt; use std::sync::Arc; use ethcore::client::ClientIoMessage; -use ethcore::db; +use ethcore::{db, BlockChainDB}; use ethcore::error::Error as CoreError; use ethcore::spec::Spec; use io::{IoContext, IoError, IoHandler, IoService}; -use kvdb::KeyValueDB; use cache::Cache; use parking_lot::Mutex; @@ -65,11 +64,10 @@ pub struct Service { impl Service { /// Start the service: initialize I/O workers and client itself. - pub fn start(config: ClientConfig, spec: &Spec, fetcher: T, db: Arc, cache: Arc>) -> Result { - + pub fn start(config: ClientConfig, spec: &Spec, fetcher: T, db: Arc, cache: Arc>) -> Result { let io_service = IoService::::start().map_err(Error::Io)?; let client = Arc::new(Client::new(config, - db, + db.key_value().clone(), db::COL_LIGHT_CHAIN, spec, fetcher, @@ -122,12 +120,11 @@ mod tests { use client::fetch; use std::time::Duration; use parking_lot::Mutex; - use kvdb_memorydb; - use ethcore::db::NUM_COLUMNS; + use ethcore::test_helpers; #[test] fn it_works() { - let db = Arc::new(kvdb_memorydb::create(NUM_COLUMNS.unwrap_or(0))); + let db = test_helpers::new_db(); let spec = Spec::new_test(); let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::from_secs(6 * 3600)))); diff --git a/ethcore/light/src/lib.rs b/ethcore/light/src/lib.rs index 9723854b8d54985ce8676763a9722fa64f9100e2..24c95cfdeb724518ba9aec7f167e5f02dc312d7b 100644 --- a/ethcore/light/src/lib.rs +++ b/ethcore/light/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -56,7 +56,7 @@ extern crate log; extern crate bincode; extern crate ethcore_io as io; extern crate ethcore_network as network; -extern crate ethcore_bytes as bytes; +extern crate parity_bytes as bytes; extern crate ethcore_transaction as transaction; extern crate ethereum_types; extern crate ethcore; @@ -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; @@ -77,7 +79,7 @@ extern crate smallvec; extern crate stats; extern crate vm; extern crate keccak_hash as hash; -extern crate triehash; +extern crate triehash_ethereum as triehash; extern crate kvdb; extern crate memory_cache; #[macro_use] diff --git a/ethcore/light/src/net/context.rs b/ethcore/light/src/net/context.rs index 613e26b1f1190e7829bd570615c6cb369f0f3996..a49ef79dc241e7631b40e6bab2573bb6a2b642ed 100644 --- a/ethcore/light/src/net/context.rs +++ b/ethcore/light/src/net/context.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -12,7 +12,7 @@ // 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 . +// along with Parity. If not, see . //! I/O and event context generalizations. @@ -46,7 +46,6 @@ pub trait IoContext { fn persistent_peer_id(&self, peer: PeerId) -> Option; } - impl IoContext for T where T: ?Sized + NetworkContext { fn send(&self, peer: PeerId, packet_id: u8, packet_body: Vec) { if let Err(e) = self.send(peer, packet_id, packet_body) { diff --git a/ethcore/light/src/net/error.rs b/ethcore/light/src/net/error.rs index 35349c553925c7e0b396762333314576111d0d12..ec2a7f91c597df1ce52ed81e51d45457dcaa4ee8 100644 --- a/ethcore/light/src/net/error.rs +++ b/ethcore/light/src/net/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/net/load_timer.rs b/ethcore/light/src/net/load_timer.rs index 2846a57384bec7865fabe6b59f5d1c31a5f0d779..0ad96270219508edbe9d0212e4a613648522aa09 100644 --- a/ethcore/light/src/net/load_timer.rs +++ b/ethcore/light/src/net/load_timer.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/net/mod.rs b/ethcore/light/src/net/mod.rs index 27d5c12a5fafbddd06a56296dd71d2405639226c..5e73681a55a6633deea3d15379bccd414405fecb 100644 --- a/ethcore/light/src/net/mod.rs +++ b/ethcore/light/src/net/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -20,22 +20,20 @@ use transaction::UnverifiedTransaction; -use io::TimerToken; -use network::{HostInfo, 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}; @@ -86,7 +84,6 @@ pub const PROTOCOL_VERSIONS: &'static [(u8, u8)] = &[ /// Max protocol version. pub const MAX_PROTOCOL_VERSION: u8 = 1; - // packet ID definitions. mod packet { // the status packet. @@ -648,7 +645,7 @@ impl LightProtocol { fn propagate_transactions(&self, io: &IoContext) { if self.capabilities.read().tx_relay { return } - let ready_transactions = self.provider.ready_transactions(); + let ready_transactions = self.provider.transactions_to_propagate(); if ready_transactions.is_empty() { return } trace!(target: "pip", "propagate transactions: {} ready", ready_transactions.len()); @@ -1082,7 +1079,7 @@ fn punish(peer: PeerId, io: &IoContext, e: Error) { } impl NetworkProtocolHandler for LightProtocol { - fn initialize(&self, io: &NetworkContext, _host_info: &HostInfo) { + fn initialize(&self, io: &NetworkContext) { io.register_timer(TIMEOUT, TIMEOUT_INTERVAL) .expect("Error registering sync timer."); io.register_timer(TICK_TIMEOUT, TICK_TIMEOUT_INTERVAL) diff --git a/ethcore/light/src/net/request_credits.rs b/ethcore/light/src/net/request_credits.rs index 29570b613cf452be71ed2e7bb8629f19a3672d8e..af507b849b571e66aea7335e332c43e5d7ccb5df 100644 --- a/ethcore/light/src/net/request_credits.rs +++ b/ethcore/light/src/net/request_credits.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -141,7 +141,7 @@ impl Encodable for CostTable { fn append_cost(s: &mut RlpStream, cost: &Option, kind: request::Kind) { if let Some(ref cost) = *cost { s.begin_list(2); - // hack around https://github.com/paritytech/parity/issues/4356 + // hack around https://github.com/paritytech/parity-ethereum/issues/4356 Encodable::rlp_append(&kind, s); s.append(cost); } diff --git a/ethcore/light/src/net/request_set.rs b/ethcore/light/src/net/request_set.rs index 27e6c28bc2d1171b5cd3bf3f0f0c4bb78a3c752f..4170f8e6328215943f9e0f8cd5f57d8da95a39ec 100644 --- a/ethcore/light/src/net/request_set.rs +++ b/ethcore/light/src/net/request_set.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/net/status.rs b/ethcore/light/src/net/status.rs index c9ee3d760f00f64ef5160d318a0cf437a7164068..98b29f3e360a249b7c0126eb257f16a050482054 100644 --- a/ethcore/light/src/net/status.rs +++ b/ethcore/light/src/net/status.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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 3c04c0ffba6308606cfb4e8da8ed6f7d28d94ad8..6bc6751b1cdb2e5715a02dd3dbec42affc5e0801 100644 --- a/ethcore/light/src/net/tests/mod.rs +++ b/ethcore/light/src/net/tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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; @@ -173,8 +171,8 @@ impl Provider for TestProvider { }) } - fn ready_transactions(&self) -> Vec { - self.0.client.ready_transactions() + fn transactions_to_propagate(&self) -> Vec { + self.0.client.transactions_to_propagate() } } diff --git a/ethcore/light/src/on_demand/mod.rs b/ethcore/light/src/on_demand/mod.rs index 64794d49e720c630060ab5c646a743e4359c3ef3..c7cc5ef5e7d5162455a1d8b24f5dda32aaaecf8c 100644 --- a/ethcore/light/src/on_demand/mod.rs +++ b/ethcore/light/src/on_demand/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/on_demand/request.rs b/ethcore/light/src/on_demand/request.rs index 18a309ae96bf0e96a358bfeb5803bade11421127..9feb0a670ff4c50c4adcf7dc75def81ee20cd67c 100644 --- a/ethcore/light/src/on_demand/request.rs +++ b/ethcore/light/src/on_demand/request.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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"; @@ -520,7 +519,6 @@ impl IncompleteRequest for CheckedRequest { } } - fn adjust_refs(&mut self, mapping: F) where F: FnMut(usize) -> usize { match_me!(*self, (_, ref mut req) => req.adjust_refs(mapping)) } @@ -936,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/light/src/on_demand/tests.rs b/ethcore/light/src/on_demand/tests.rs index 95aec273f8bddef0be89a5bb2325ab896319ad04..d3cd137ec05663037e1822342590a2c12dde4db7 100644 --- a/ethcore/light/src/on_demand/tests.rs +++ b/ethcore/light/src/on_demand/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/provider.rs b/ethcore/light/src/provider.rs index aaa6f5858ae6f2b3e8b1b157b3626cc1a77207a9..a066cefb529bea85903494dd7995ddca839cde45 100644 --- a/ethcore/light/src/provider.rs +++ b/ethcore/light/src/provider.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -54,6 +54,7 @@ pub trait Provider: Send + Sync { /// results within must adhere to the `skip` and `reverse` parameters. fn block_headers(&self, req: request::CompleteHeadersRequest) -> Option { use request::HashOrNumber; + const MAX_HEADERS_TO_SEND: u64 = 512; if req.max == 0 { return None } @@ -82,10 +83,12 @@ pub trait Provider: Send + Sync { } }; - let headers: Vec<_> = (0u64..req.max as u64) - .map(|x: u64| x.saturating_mul(req.skip + 1)) + let max = ::std::cmp::min(MAX_HEADERS_TO_SEND, req.max); + + let headers: Vec<_> = (0u64..max) + .map(|x: u64| x.saturating_mul(req.skip.saturating_add(1))) .take_while(|x| if req.reverse { x < &start_num } else { best_num.saturating_sub(start_num) >= *x }) - .map(|x| if req.reverse { start_num - x } else { start_num + x }) + .map(|x| if req.reverse { start_num.saturating_sub(x) } else { start_num.saturating_add(x) }) .map(|x| self.block_header(BlockId::Number(x))) .take_while(|x| x.is_some()) .flat_map(|x| x) @@ -125,7 +128,7 @@ pub trait Provider: Send + Sync { fn header_proof(&self, req: request::CompleteHeaderProofRequest) -> Option; /// Provide pending transactions. - fn ready_transactions(&self) -> Vec; + fn transactions_to_propagate(&self) -> Vec; /// Provide a proof-of-execution for the given transaction proof request. /// Returns a vector of all state items necessary to execute the transaction. @@ -280,8 +283,8 @@ impl Provider for T { .map(|(_, proof)| ::request::ExecutionResponse { items: proof }) } - fn ready_transactions(&self) -> Vec { - BlockChainClient::ready_transactions(self) + fn transactions_to_propagate(&self) -> Vec { + BlockChainClient::transactions_to_propagate(self) .into_iter() .map(|tx| tx.pending().clone()) .collect() @@ -367,9 +370,10 @@ impl Provider for LightProvider { None } - fn ready_transactions(&self) -> Vec { + fn transactions_to_propagate(&self) -> Vec { let chain_info = self.chain_info(); - self.txqueue.read().ready_transactions(chain_info.best_block_number, chain_info.best_block_timestamp) + self.txqueue.read() + .ready_transactions(chain_info.best_block_number, chain_info.best_block_timestamp) } } diff --git a/ethcore/light/src/transaction_queue.rs b/ethcore/light/src/transaction_queue.rs index ae3dc2691568ba0e162a81ff49fc12c0dab6edc2..e8880037a171d0d22b4078293aae6859e4499cad 100644 --- a/ethcore/light/src/transaction_queue.rs +++ b/ethcore/light/src/transaction_queue.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/types/mod.rs b/ethcore/light/src/types/mod.rs index eba551b533c396d027c868f893165caba2d8315e..67e54141b27615e34a988c87455be0b289b333c7 100644 --- a/ethcore/light/src/types/mod.rs +++ b/ethcore/light/src/types/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/types/request/batch.rs b/ethcore/light/src/types/request/batch.rs index 21f1264672dd0b97e30cc15db5da35ea4040387a..16843ae02c5808a9117823ef03bbce788e9abdb7 100644 --- a/ethcore/light/src/types/request/batch.rs +++ b/ethcore/light/src/types/request/batch.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/types/request/mod.rs b/ethcore/light/src/types/request/mod.rs index bda992df975109a30145980496a35bec397c08d1..37341e6ffa87c87bd876afef00d753e4241fb65b 100644 --- a/ethcore/light/src/types/request/mod.rs +++ b/ethcore/light/src/types/request/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -124,8 +124,6 @@ impl Field { } } - - // attempt conversion into scalar value. fn into_scalar(self) -> Result { match self { @@ -351,7 +349,7 @@ impl Encodable for Request { fn rlp_append(&self, s: &mut RlpStream) { s.begin_list(2); - // hack around https://github.com/paritytech/parity/issues/4356 + // hack around https://github.com/paritytech/parity-ethereum/issues/4356 Encodable::rlp_append(&self.kind(), s); match *self { @@ -598,7 +596,7 @@ impl Encodable for Response { fn rlp_append(&self, s: &mut RlpStream) { s.begin_list(2); - // hack around https://github.com/paritytech/parity/issues/4356 + // hack around https://github.com/paritytech/parity-ethereum/issues/4356 Encodable::rlp_append(&self.kind(), s); match *self { diff --git a/ethcore/node_filter/Cargo.toml b/ethcore/node_filter/Cargo.toml index 0d204e29ff880e10a7b96db60a451dba5c5268ad..b6e3cfe55e9e57e6b73fe37848d79cec26cda0c3 100644 --- a/ethcore/node_filter/Cargo.toml +++ b/ethcore/node_filter/Cargo.toml @@ -12,13 +12,14 @@ 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" lru-cache = "0.1" [dev-dependencies] -kvdb-memorydb = { path = "../../util/kvdb-memorydb" } +ethcore = { path = "..", features = ["test-helpers"] } +kvdb-memorydb = { git = "https://github.com/paritytech/parity-common" } ethcore-io = { path = "../../util/io" } tempdir = "0.3" diff --git a/ethcore/node_filter/src/lib.rs b/ethcore/node_filter/src/lib.rs index c731ad356ad28d44d645762e3a2e8714ca2aa772..22267ff98d862e12b0809bc57a069cd044f95c53 100644 --- a/ethcore/node_filter/src/lib.rs +++ b/ethcore/node_filter/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -90,7 +90,6 @@ impl ConnectionFilter for NodeFilter { return *res; } - let address = self.contract_address; let own_low = H256::from_slice(&own_id[0..32]); let own_high = H256::from_slice(&own_id[32..64]); @@ -116,6 +115,7 @@ mod test { use ethcore::spec::Spec; use ethcore::client::{BlockChainClient, Client, ClientConfig}; use ethcore::miner::Miner; + use ethcore::test_helpers; use network::{ConnectionDirection, ConnectionFilter, NodeId}; use io::IoChannel; use super::NodeFilter; @@ -128,7 +128,7 @@ mod test { let data = include_bytes!("../res/node_filter.json"); let tempdir = TempDir::new("").unwrap(); let spec = Spec::load(&tempdir.path(), &data[..]).unwrap(); - let client_db = Arc::new(::kvdb_memorydb::create(::ethcore::db::NUM_COLUMNS.unwrap_or(0))); + let client_db = test_helpers::new_db(); let client = Client::new( ClientConfig::default(), diff --git a/ethcore/private-tx/Cargo.toml b/ethcore/private-tx/Cargo.toml index 8283ab314aacc9323abf45c182cab15326ba2620..e547c980870bcde30a1a4ec3bb758933f1662c11 100644 --- a/ethcore/private-tx/Cargo.toml +++ b/ethcore/private-tx/Cargo.toml @@ -6,13 +6,13 @@ license = "GPL-3.0" authors = ["Parity Technologies "] [dependencies] -error-chain = { version = "0.11", default-features = false } +error-chain = { version = "0.12", default-features = false } ethabi = "5.1" ethabi-contract = "5.0" ethabi-derive = "5.0" ethcore = { path = ".." } -ethcore-bytes = { path = "../../util/bytes" } -ethcore-crypto = { path = "../crypto" } +parity-bytes = { git = "https://github.com/paritytech/parity-common" } +parity-crypto = { git = "https://github.com/paritytech/parity-common" } ethcore-io = { path = "../../util/io" } ethcore-logger = { path = "../../logger" } ethcore-miner = { path = "../../miner" } @@ -22,12 +22,13 @@ ethjson = { path = "../../json" } ethkey = { path = "../../ethkey" } fetch = { path = "../../util/fetch" } futures = "0.1" -keccak-hash = { path = "../../util/hash" } +keccak-hash = { git = "https://github.com/paritytech/parity-common" } log = "0.3" -parking_lot = "0.5" -patricia-trie = { path = "../../util/patricia_trie" } +parking_lot = "0.6" +patricia-trie = { git = "https://github.com/paritytech/parity-common" } +patricia-trie-ethereum = { path = "../../util/patricia-trie-ethereum" } rand = "0.3" -rlp = { path = "../../util/rlp" } +rlp = { git = "https://github.com/paritytech/parity-common" } rlp_derive = { path = "../../util/rlp_derive" } rustc-hex = "1.0" serde = "1.0" @@ -35,3 +36,6 @@ serde_derive = "1.0" serde_json = "1.0" tiny-keccak = "1.4" url = "1" + +[dev-dependencies] +ethcore = { path = "..", features = ["test-helpers"] } diff --git a/ethcore/private-tx/src/encryptor.rs b/ethcore/private-tx/src/encryptor.rs index b15acbee71bcc6874fe1a907995d81d29233f823..e64917add0a39f005b3974d89702965c79885adc 100644 --- a/ethcore/private-tx/src/encryptor.rs +++ b/ethcore/private-tx/src/encryptor.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -26,7 +26,7 @@ use parking_lot::Mutex; use ethcore::account_provider::AccountProvider; use ethereum_types::{H128, H256, Address}; use ethjson; -use ethkey::{Signature, Public}; +use ethkey::{Signature, Password, Public}; use crypto; use futures::Future; use fetch::{Fetch, Client as FetchClient, Method, BodyReader, Request}; @@ -71,7 +71,7 @@ pub struct EncryptorConfig { /// Account used for signing requests to key server pub key_server_account: Option
, /// Passwords used to unlock accounts - pub passwords: Vec, + pub passwords: Vec, } struct EncryptionSession { diff --git a/ethcore/private-tx/src/error.rs b/ethcore/private-tx/src/error.rs index 3b3c881a94513a2f3f59402209bf10c4594085e2..55a75d6d9edfcc31be03ca0b79a047fb13c13ca4 100644 --- a/ethcore/private-tx/src/error.rs +++ b/ethcore/private-tx/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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; @@ -205,4 +205,3 @@ impl From> for Error where Error: From { Error::from(*err) } } - diff --git a/ethcore/private-tx/src/lib.rs b/ethcore/private-tx/src/lib.rs index 7aca4c85dc492e8f90a0a5eacb8d6e6f3c80af7d..a661197dadbb5279fb57d729fa4b65d1b77d8c64 100644 --- a/ethcore/private-tx/src/lib.rs +++ b/ethcore/private-tx/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -26,8 +26,8 @@ mod messages; mod error; extern crate ethcore; -extern crate ethcore_bytes as bytes; -extern crate ethcore_crypto as crypto; +extern crate parity_bytes as bytes; +extern crate parity_crypto as crypto; extern crate ethcore_io as io; extern crate ethcore_miner; extern crate ethcore_transaction as transaction; @@ -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,9 +83,10 @@ 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; // Source avaiable at https://github.com/parity-contracts/private-tx/blob/master/contracts/PrivateContract.sol const DEFAULT_STUB_CONTRACT: &'static str = include_str!("../res/private.evm"); @@ -94,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 { @@ -102,7 +107,7 @@ pub struct ProviderConfig { /// Account used for signing public transactions created from private transactions pub signer_account: Option
, /// Passwords used to unlock accounts - pub passwords: Vec, + pub passwords: Vec, } #[derive(Debug)] @@ -121,7 +126,7 @@ pub struct Provider { encryptor: Box, validator_accounts: HashSet
, signer_account: Option
, - passwords: Vec, + passwords: Vec, notify: RwLock>>, transactions_for_signing: Mutex, // TODO [ToDr] Move the Mutex/RwLock inside `VerificationStore` after refactored to `drain`. @@ -243,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( @@ -262,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 { @@ -430,7 +435,9 @@ impl Provider where { let (new_address, _) = ethcore_contract_address(engine.create_address_scheme(env_info.number), &sender, &nonce, &transaction.data); Some(new_address) }); - let result = Executive::new(&mut state, &env_info, engine.machine()).transact_virtual(transaction, options)?; + let machine = engine.machine(); + let schedule = machine.schedule(env_info.number); + let result = Executive::new(&mut state, &env_info, &machine, &schedule).transact_virtual(transaction, options)?; let (encrypted_code, encrypted_storage) = match contract_address { None => bail!(ErrorKind::ContractDoesNotExist), Some(address) => { @@ -583,7 +590,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, @@ -670,7 +677,7 @@ impl Importer for Arc { } /// Try to unlock account using stored password, return found password if any -fn find_account_password(passwords: &Vec, account_provider: &AccountProvider, account: &Address) -> Option { +fn find_account_password(passwords: &Vec, account_provider: &AccountProvider, account: &Address) -> Option { for password in passwords { if let Ok(true) = account_provider.test_password(account, password) { return Some(password.clone()); diff --git a/ethcore/private-tx/src/messages.rs b/ethcore/private-tx/src/messages.rs index f465f752be97b4db80cf9b5765c8b641bcc4662b..57362e7ce6273898c83c625766d6dedb598d1997 100644 --- a/ethcore/private-tx/src/messages.rs +++ b/ethcore/private-tx/src/messages.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/private-tx/src/private_transactions.rs b/ethcore/private-tx/src/private_transactions.rs index 1a018d927ad54430f0388b18be4929a2f05761d7..e16d6ab911be20232c23627bbc840b8bb6d5e9b6 100644 --- a/ethcore/private-tx/src/private_transactions.rs +++ b/ethcore/private-tx/src/private_transactions.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -67,6 +67,7 @@ impl Default for VerificationStore { minimal_gas_price: 0.into(), block_gas_limit: 8_000_000.into(), tx_gas_limit: U256::max_value(), + no_early_reject: false }, pool::PrioritizationStrategy::GasPriceOnly, ) diff --git a/ethcore/private-tx/tests/private_contract.rs b/ethcore/private-tx/tests/private_contract.rs index e7e608c2b610ac0af9896c31456c0c385fa1ca34..b2c08ace215f4a1bd7187a715eca0d437b320edd 100644 --- a/ethcore/private-tx/tests/private_contract.rs +++ b/ethcore/private-tx/tests/private_contract.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -55,9 +55,9 @@ fn private_contract() { let key3 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000013")).unwrap(); let key4 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000014")).unwrap(); let ap = Arc::new(AccountProvider::transient_provider()); - ap.insert_account(key1.secret().clone(), "").unwrap(); - ap.insert_account(key3.secret().clone(), "").unwrap(); - ap.insert_account(key4.secret().clone(), "").unwrap(); + ap.insert_account(key1.secret().clone(), &"".into()).unwrap(); + ap.insert_account(key3.secret().clone(), &"".into()).unwrap(); + ap.insert_account(key4.secret().clone(), &"".into()).unwrap(); let config = ProviderConfig{ validator_accounts: vec![key3.address(), key4.address()], diff --git a/ethcore/res/contracts/tx_acl.json b/ethcore/res/contracts/tx_acl.json index cc924cafb81d9cbe6c023b87081cbc386c41c7b9..e110797d96fb3107d981aaee113072a6a21fab98 100644 --- a/ethcore/res/contracts/tx_acl.json +++ b/ethcore/res/contracts/tx_acl.json @@ -1 +1 @@ -[{"constant":true,"inputs":[{"name":"sender","type":"address"}],"name":"allowedTxTypes","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"nonpayable","type":"function"}] +[ { "constant": true, "inputs": [], "name": "contractNameHash", "outputs": [ { "name": "", "type": "bytes32" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "contractName", "outputs": [ { "name": "", "type": "string" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "contractVersion", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "sender", "type": "address" }, { "name": "to", "type": "address" }, { "name": "value", "type": "uint256" } ], "name": "allowedTxTypes", "outputs": [ { "name": "", "type": "uint32" }, { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" } ] diff --git a/ethcore/res/contracts/tx_acl_deprecated.json b/ethcore/res/contracts/tx_acl_deprecated.json new file mode 100644 index 0000000000000000000000000000000000000000..cc924cafb81d9cbe6c023b87081cbc386c41c7b9 --- /dev/null +++ b/ethcore/res/contracts/tx_acl_deprecated.json @@ -0,0 +1 @@ +[{"constant":true,"inputs":[{"name":"sender","type":"address"}],"name":"allowedTxTypes","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"nonpayable","type":"function"}] diff --git a/ethcore/res/ethereum/classic.json b/ethcore/res/ethereum/classic.json index 928c056d660a47482509128b12da85f50894d9b4..17cdfd300d1fc115f1d50b63ea7c117e1c0a1a04 100644 --- a/ethcore/res/ethereum/classic.json +++ b/ethcore/res/ethereum/classic.json @@ -49,6 +49,3025 @@ "gasLimit": "0x1388", "stateRoot": "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544" }, + "hardcodedSync": { + "header": "f9020ca0bfe78565c7685098b017e32399104274843eeed1fb1cd427c84bbefaf6f1c60ba01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347949eab4b0fc468a7f5d46228bf5a76cb52370d068da0499004e0e047f7c34e1e6b8e873c1829be5047433cc4429935346e43bdbbfc30a06566f1411ae4d7cefdb81be14d36baf1436c2a1bd344507f8d956c94655d27a3a0a916ae91053573cb022d0d78848920ec6429dfe57e4c00c46a442d53b301a8fab9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000869f7836fd69e7835e28018348048d83070cb0845b4823668c6e616e6f706f6f6c2e6f7267a01c3256996334e58c301283bfaf600d82e608ea584f451a65486c01ba4b22e104881716cd90004293eb", + "totalDifficulty": "343601966742385746996", + "CHTs": [ + "0x0eb474b7721727204978e92e27d31cddff56471911e424a4c8271c35f9c982cc", + "0xe10e94515fb5ffb7ffa9bf50db4a959b3f50c2ff75e0b8bd5f5e038749e52a11", + "0x816e7463af7b5d2fcb804ba55f09e8452182b0ba6c995a34e144245d76333d55", + "0x3793af64c1ddc07ab61b2ba120034d91c02183ff788f07d3120fd4e6a48305b5", + "0x14c6106a17e041032210bfa0ca80d11860a1c6d95175d55eff39f97b8d8acded", + "0x396f832bfa3a9c494e9245471f0e65552613d87b6fe62128103590d95de72c2d", + "0xb060979f095c170a776b2b50a1e2ab0ffea80f6e522753fa36ad6f106ee32e9f", + "0x8f452e7cbd8a333ed04d819a143a8d3a75fe8c58418e7fc420bb2a717c0d4d2f", + "0x37fe1b0cf156bfc07571569af210540be753777903a308d5707538fffed75b59", + "0x6f0561d017cfc123b3f0d37b044e4f7231516b8731a1cab89afb569238643c33", + "0x3c1740c410a88c60fe8ccdc44e0ef2cf7f7314818dbf1648c01d0d94fbffc211", + "0xfb98115a7d6df8aaa40115f883014fe97300869bc016648e918fbf2df9608d41", + "0xef1099ab5ca4b79369048678d3ba78122fc081b00b6fd0f6907302a260d58266", + "0x969575f411dd78fdc5b4def0331fc93702029cc3c78851331a0f47dd0faae70b", + "0x9e53053e362be51c0fd25eaafd9e7c5c969d9f2ce8db4b3d4d830cbff347b0c8", + "0xf9de29944954d2b71a93532fc26916ae12fee72d42a79adaf940b0bf75d0ef89", + "0x28b2ce6635e60e06d643750798779023b2a807d9d089ae9ef7f223eebc15a71e", + "0x5295c06cbaff06f42bd8f5d9cbe94a840885caed02f9c9ba6da44a888ef796de", + "0x576eae673a4cbba4c7c7a56b47835ea64ae5989d67d119ebc8e568df40d908a9", + "0x891c0d38bc5e55620615da42ed77ab33806a042512034bcee134279dde1054be", + "0xbab05999d657426a11a902eb4c85ac52e2b72dd1cf38584cf2baeb2c3727bb44", + "0x3bd7e5a966f6dd2dc456948a8efca5584f5a4e0033f3037843a42073dda1f71b", + "0xc4f773ab1e34290f9a3d9ac6ede4749c5dec547353dddea494169d86f71107a3", + "0x993bf037ea9dd58b52027fb6f39332dab867c1e72af34a49d58a5a12f26bcca3", + "0x48b2d8d506eb8fc9dc0402fef26952111449aca0f90d0079f0526435d4e3183b", + "0xfef8f61df240e956f43759d2f481938421e064a9bd6a3be7a53b1213cc9588bb", + "0x5abf01f5066cf1091acdd1f99fbd5fd963633feafc42f9047534a3c1522004a5", + "0xa0f6205842260988161183b51bc36fae458fa184dd61844617d5c5d26fa78346", + "0x77309182fdc26d15dd8d9dd05040d7dc623412785708d8aac39eedee63931944", + "0x661c93311b94b7d4cdcbc0973225c794e71898a2b906922a6c1e8f7e9e289dc3", + "0x9d5d329ee8d9fffaee0111688d31a308dfaac922dcd61f818edd5303d0955be0", + "0x716ca25b184b64ba273b978de098f9946413f6fcc95bfba5cf1169e7e03dd611", + "0xa2e8d5cefa5804894fb42a106340b00de3286fee0992b5887b2cf471539d74a9", + "0xf846e05c9e9e9cb4cd2b7cbae7ae183a43a59ab02251954db632e538adacc357", + "0xbc01b4e23ea082a193e4c1012b1da91f3b4cb762009ca320bc8ed294af874e79", + "0x9218114a32da3ecf660d4d51b101bb51bb17c771561c1946c099be082f0a96b3", + "0x3b4edf03dfd53081cf40c0b90b35c1ccf7c7fe96cf131172eef5eec62f620ea8", + "0xb15758944263c67bdf528d4d7fe05737fbdbf7ffedce5f891a4ddf76177d2609", + "0x1f119374c385240f7b4ba1ec3d502be2c12c159411d5393ff2bd38cf87033625", + "0x8a8d5a93f3475813926b13a4d53f21b28dc79ade2b50830c0b9043e9fcd81576", + "0xcc22f7e2bb9c06c15ca3d82df852ed9097a2ddc687ee389e662de000db0c84fc", + "0xc2047e0dab711db791aadb642f8102abaacf7231b8dbdbe1f60573b0be015a31", + "0x1b4088ceee7783e4563945f162bd5da67020ca377a18d615923e8564d6709f85", + "0xd73450686e33bbda9eef53a95a86e5a0514156b98a5b7dfc6fdc0adb0b83cbcf", + "0xb374076ec961360e38d3486a31c3f72225440984c4c47ca790b4961d94152159", + "0x4f723f4fbd31d63a5421390e68aba0aff97249875688a7d9ab9a339d9aac7bc1", + "0x5fe51ff982edcad6c0052fcdf9a70e8f325c8140ab75848c5d7b0d670bd7edc2", + "0xc3ad483c7cc23bf8d6ae3e3e829bf126d5eeea9c53b566a6da95bef573b9c779", + "0x3c9e50ed9eb57cc055fd9a65a6cdaba2030d8b41f81348f296d7410c1d24ced0", + "0x0c6dfc1f626ff9e85ff072c154152bb3f122a2c1a45bc2d9e7da9b2d5278149a", + "0x92f4452dbdb4fe70e84ecd47af4b1af90975219797cebd451beceb6997ab024d", + "0x9a3d00686736b5b838308da4b8f0aa9edccfaba64621ce2988cea6ea2a267efd", + "0x8d602d0bef069177102726d5ccd93d19805fb5771a350a41e32755ce740b9047", + "0x6681e4097667a22ad3713acc27b6f87abd54583230581933bed9245c2c457ac3", + "0x53077caeabcd926466319a3ee5c51c32e01e1812a65313f113f814d53e9f1dd9", + "0x4dd4c33e99d86ba84f976c639333fc072e262c0b76dfdf2f589300af54048c0a", + "0xbc3b9837a6fa54616dcdb8088080e276e2e99a23c8e7de4109504293703d524e", + "0x24316b344cecd5e601cc0acc91ff94f481ca3fa26d8478644a9d8bcaeb0359b3", + "0xa7bafd3c5f4e3f6b5c078d50eb318d91e867b0e1c966027e3e7458eb104ccd63", + "0xc8da46b7d778980d120357c8de2bba336f5a2ac7a9f4183a0ee1f7597ed47d25", + "0x7469fc5d8c9c648cd10e538710e0f126542e59a82484e7fe56b73f4ec52c36c7", + "0x993bb7c0487ff61c97e4f1533446ae35b6346642e1230f2441da8b354111d597", + "0x90e3944732f86a2254dc4f30650f8438dfd0b777561fb02a8ab1c60438569c24", + "0x4e8472483679b54bdc600010fdd164f54771d7a99fa9272c683b610fff72507b", + "0xf72a861a2ebc232c25529c0f94c59996e64c59c36a1326a183cf171bddf2a75c", + "0x7f222999ba9113e2a64fd026a8f7244e6d2ae8f2a7e7d8d2d6fbde6fdf0b629f", + "0x3304e769f730522c1c5aa745c448075df026b8f82a4dece84fd70d0457050985", + "0x9ee5e3ccaaf94461dff9df8c4805ca831f58a1586af4ece3cab14a45f3b784db", + "0x21e4364859063e20153d2d06eae4d2c9e99354bf97fbff68406d8825d18dbce3", + "0x4805355b72b1b61b07814059f80b4da0351291cc932292f23069197a74127726", + "0x14474f45f38d7ea51418e5f03751c8bfbfb9b3e2957d3051e862aa3c57a63c43", + "0x69372cee3e2807d10ecb72d404a033568a159a5b15d2007537ed9a758164b29f", + "0x147223b51001166a4e65372c9c706f011f1ae94f4bdc9ba6e8960017e8898703", + "0x11a1e48a5c1d7088c0ccb8177d54db9e9f91a99aa7c24f702cd93f4646f181ee", + "0x809c902b2f4b8760c3d2e820c93d6df69a5d184a43a6c654ebe7067e7212137d", + "0x749367027756c27215b2f57168ef15d3b39062c9f79b3777f7fa19e8073de775", + "0x6a9fae37364f97e36e56df97acb1b7d066a608d8366d7e008854756dd28fe748", + "0xdc2f1b7a8aeda15e6bf4f5f424bc54828cc8520e2e7ba27bd8e28ba2b543aae7", + "0xe0fabc892d5c8b4342ff488b76a0400425ea70774f207c546fbf2f9f5b105dcb", + "0x151fb5e02d8eb3c3192cb8c039bcb4c121c4ebeea5e7f98927b85a730a24bbf9", + "0xfeb2f2ea368d0bd4c0b0bd97b444c365bdc0ac9ce2862b0d0162387727edd236", + "0x1eaf828231ebbae54737111bf3c7181fe3d7e9070def1313470d3f81c89f01c7", + "0x8a1b0565013cff488bbe3f35df86fb41c7aedf4d911130802c473f4ddb74d6d6", + "0xce9158b5c903312fa636e074e3efe413184652581a4877d40a0085965dc0bf9a", + "0x1cf602c6306affe2916fa09d3c8c018f23fc44dec8af8e83fa0008c98b4dda72", + "0x189dc4569e96cab937265ecaea76a0880ec97d5b84ac1fbd0cd2d2b36a8c34c3", + "0xd698bd07e485767c1da30bb218265e1304f6eaf426749ccba67478817af84bd4", + "0x47d7e101de73bb0ca97a0bb70094e81b82c63e519a6b2aa5fe10ca7351232870", + "0xb0d441b6c41072889c4a982306c9a40dff77b43425ecc4d771c22f3199eb7708", + "0x7893071deba67f2fc8e1b18bedcac4dbc05a020f37c764c555eadc42dd9d29d3", + "0x3c6d636db3621757d60b2d0e1804e19528ce60c9feed1ead93731820ff19b11c", + "0xde87aaa462b461c4a33e0739ef4cf56d442b7967ac7c5280816a959046b128b6", + "0xb237b17650adcbcf580b64b500ecaa7ca36921a11ad92c1e8992c57cc1a7f618", + "0xec379725db43fefe61f2495f7f7e0531d852e21f896ae806144c4d9b4b986e96", + "0x65ac5548988825831f0887b9ff0f2c13b7f3b49e4a67c39b1694e76414249f6d", + "0x76053b72ec9e6fcf0a28ef273d3e1b0842c3c2c0e905f5b5a3535ffab216c8db", + "0x2ab1e87489eb1daeaf8882c6baa0a8726aeac522e9c4eb4df71e35af2d22cc10", + "0x8c9c6adcabe253b311f6a9b8165ff9c5e26e4cf41f1acd80837e77fc15526a86", + "0xf143155230223a3f126c757b85e193a9129f1bdf97c0ce1f2785f14d40911f30", + "0x8c510d9dca593534f3ed316f240ffb9343d1e3cd6d005df6a75a1b354da0b36e", + "0x3440975cf818a718beff35a85d19bcbbd67e1b16ca9d78af34dcde31a28b3288", + "0xf56ef9c57109f9cb7a925bbb6d453efc19e8a45b331f76153d20a87d86a8b0d8", + "0x19a360772872003f08508a28a362c6e05650b385c24a928ddad4d562bfccf412", + "0x643720694b3773ecf20437d54a6be701810feff233f435dc701dbe88c9a6a13c", + "0xf8c0babe99aa26ecbfc91b304d9cd54ccfb37354c4fdbeb3207bb6d4647fabd6", + "0x481ccc7213d0188e817c071c4cc3a71c96befb9aa98cab964012fd7a8267834a", + "0x02d83ca8d92e0fe6ce7643ae93af60e38ab5659a84c04beba678ceef654aec12", + "0x24e6b4bcd0d97df196f2371532771593fe17be8fcb89f1e1164bcce8616088b9", + "0x3dc91775c50c04812f755f3b48d3d6a0cc599c586ce9d105e2cf4f3e4527b515", + "0xcdc215f05398ea3942d3a38078a3602cbe8ac549d4bf0e4a54191ceb2aff8f76", + "0xee02874e444b784f4265cc60b86a17382d277d03c8bce8a33241460ea8950699", + "0x35c34bc84736fdcbc4d4e2e089f30bcd186a052b2f6dcb639fc45a0aeb6969f8", + "0xbbb3ff849c36659bf2c00feaad9f7b3a342b5cfcf3555b7c2e467a0dc84e90e8", + "0x0584bc60fbe3fae9088c214fb519030646c3240f77180a0bedecd3e9c9f47f89", + "0x9d18a665d89439ad2c97427bdab3e598f5bc0da6a0ede2378f95c5bc31f10d12", + "0xe8a5bdd0ffd33a6fd03cf003c6d2afbe8493e0f0cb69e6366e22b4d1ff985101", + "0x7ca955f4e01eef756b680d09c25626cf50013faa20a12b0a334fd048a04e7b91", + "0x064254551457bd5e7a260a41ed3643746202d503813ceaf42660f9bd1983be34", + "0x1191044e354ea1e3daa25ed2175a6517659e96733d9065d81492ffe4472fb96f", + "0xc823514cf3566b1bb2e19a35e0ef0980bc483fa820d13ae2cfdbf15fd426c272", + "0x413f941f192d0ab77bac68268f45e2c9adbee23a3324d4ae8748d09735355a2d", + "0xa66c94b9603b3058b730baeba1b79d52f548ceeb5bac487903f92481060f6804", + "0xa84d4a8860bdff1fdae6bcefcdcf700fab7857444ef1e76d8259b005872a4636", + "0x9fa64d44edd9c097458d3901612a4b6f655a1421ebb68541cb1a4bdbbe24911e", + "0x402027770edb387510241a68a235723c6c5c95aed54dab058c43d21a6bb48c41", + "0x776281b7e341a66491603b7ae8ed7cc82b99febac43f94cb1c4dda73b17aab63", + "0xfecbaf0fc5a02dcf49095514ce26df927def3cf51f37e04471545aae2364f936", + "0xc477d9293f0ace7243f8b9c89f01210b8f96b4affc9d3332147ea2e2b693c99e", + "0x4a8b9afb9d9097831b2497296b0fd0fae76ab8a596213daed35cf87e6bbefaed", + "0x594c4e9851eddbb4a6c2ac72aaa244ff35d67262efb20935360360d39f7c7ecc", + "0x14b7ef22c46ba8400979b6c06f3b3023607145a5cc6b5b793daae758cb655245", + "0x3a9d233553d1ca4d9862a70ef133a5fb2df75276fb24297b0bd2927a39459450", + "0x22c5e227d5fa7616603bbf36c5e4ee7dbf285fb0cf403a3ae982da70c825cad0", + "0xc2c8d439c7bd884665da56e3b680a5e58ad1e98627fdbec6fa67d7bbfad33a9b", + "0x7d5682cd9f28493ba4b87be141ec99701bbcd1aaadf9840b81de1fc07d4ffb18", + "0x8845f626c5f78d1bea281f892727437f9de8f976e4c4fec6060b2115f1862db5", + "0x769fdf0bcdbaec1ffe98cd3500ce8341b4d7ea2dad5fadb0258212306ccc75f9", + "0x185569d1980147fcdfcd0e0068ab380f0cfa58a690334a558bc1fd0d07897e96", + "0x0ed70ccff752df46f981043c5279ac3f13e7f62c2bdb9a0a9817a1c119ef6402", + "0xbe121e28349e80d601ab997af844aa03ea6492e88d75d3d46517d8f835e3c3fd", + "0xa7aa5f0bb95566292d22891faa75b7ff2020b69fecc8a22d796cc3a60953d98f", + "0xa2611b092b00f78fe639c4fba0274ae474fa448b3f2e4b8aa4d06c654720d478", + "0x8e425115b98f5e41c8b5d03a9e17d56d30050d85dd06cfff12f002c546a256ba", + "0x988b449fbd8c35855154fb4eb22ba6b7b7095be26203d137f484c67facd40dc5", + "0x567c43ac5dabeff01d6997543ec7abf7998088a355a6ba8e70f41a243dd1343a", + "0x6f560cb650142aed532f17de763d61d021cdec2716b0d2cb27b3a64052abb874", + "0x7e4ce5fab8f4f1fd41f9e5f10204032ae7e0e38093b1d07699318975b33910ec", + "0x91a0820eec5390916bf464b1d16c00b5d94386c4c9f4cdf7e0b3cbe40747fbc9", + "0x9c59451a9a242123efa72c5fbd1564b7bcc0067ea9d025336d228ed26b9ba6c0", + "0x1043a5ab3f5a3bced84faaae0e783abb3b81c2b967bbd976042cb5d897d28146", + "0xfc37b3b3c0be392ad2a5e36c120eace1d14e637ac806e79a750b9a6be3c742a7", + "0xce2ccbada44a8db5144073e69914b322dc015273a75b85ea43fd9e21037c760c", + "0x6cf8336b5a410e10604f93351242cb3a6929968212abdf85b4ca9321115b8fdf", + "0xabbe9781950362be1e206d91ea1bdd6f32ea2c6df65b277cb89050ca1deb9296", + "0x922a6b85add6839494c3edff389aa1b054409c330b4a4e2a6c0e4f9bc85b36a9", + "0xc26dcdfa135a09b7eef1e99b445fb66aefb8bceb6ea715b81d78ba87cd56ed8d", + "0x87d647fa7dcde81a0e133aa949d574befefbceab24a42ae4f3809d2bb52a2d9b", + "0x85ee37fa7154568b9dee8a539340f99c7f1bbc7b9be1f2055636ed9dfc074e4d", + "0x8b0114dc9e249f1de4bb3d055790e4bf18aa28a938f39e8a457ab4a43b0dd613", + "0x3be36db134f4c00fc9e1bc376213c7073389c993b0b0744cba619688d6c037d1", + "0xfaf987eb2e066ad8871c489c23102ec5c58add2d13e62d56f2821cc1f4d66d84", + "0x678478da2955e6876ac49c5146e9f7c376dbf2f170f6404054ae4385e72f3f19", + "0x85d8d9dd6c2a8f6b6a1c0fc0cb55ca870d9a7aae1621c143c3176a3a81fcc29c", + "0x76f4dfa4c3387408c823a75aeb872ff39af3820375ff52f7aecb41c96e4faf2a", + "0x6e530647f2e4232063de2fa8f673989d7834d8cdf529791032888f2833880b80", + "0x64422b4dfff6cba0eb6deaeb4593eefc40a357469a7f7c3be078f80c66161333", + "0x5c7ab740510a4183832bd78e6d6105b0f9f928611f7d62ef96aa8dd8da48a72d", + "0x0bbf405e29f015d24e64f063d50ec6c616af64622b1a4132cde86f926e93850f", + "0xd9ba81ea0790f1f8adccd0bd203c7adeec2b490381b822d6b15293cac2f26206", + "0x4f78619baa34f2278022c509671a38d29366936d6860e79ab540ea46b66ba782", + "0x00c1f10211d7604e59a327239f00dc6d036a93416b7871cb214e8eaa52571834", + "0x1b6636708f97485675c0e5b21eb749ee4a5fd0dd886e6690090856bcc5178ec0", + "0x71366e853968c1bbbbf8e3d6e13100dd589521f8db9e561dd20ff8709b5c1a96", + "0x0d2c35a01646cb09e2b56b5792ac03047848bef7415ae26f787cd54ef8f327da", + "0x1c5b71047f99db30453e502c9acdf422d3bf97b0d42b9223ea1b8b9924bb0cb1", + "0x9988eb36e4a669638e3242e5ada3e6596c5e4ef36a83ed2d3348d35fbed4d3d0", + "0x8f00020f98f02af0749df39fb2f534d356e3dbe809bdb3f435c4a575d661d6db", + "0xf70a509c0d1c60afcafc7cc492c5ad575fdcadf6ca8e0e5f184c62dd52021129", + "0x72cdb6544dd469ab42e270e51d136b314c27ed0d6682f914cf3e0398399d2d5d", + "0xd5584896e649b618ab8257859e42ef7798c37cc85103a8019cec10b1524519f3", + "0xd70636cf5cbe78ba86b8de902f83f9c550a8ee31a019da6fcb0b1ab0a02bd31f", + "0x79a506d61c89cb7b1aef845484956389d5f6077fd10f8d1ede1e92474eac15cf", + "0xa66c0575cfea08bc6abbba03b0d10be7bdcfe6c5da9058cb34c22af2c8f3f1d9", + "0xfde316523b6b41fedcf11d776a53bd27fe3058c3912059197cda083a14410689", + "0x6774beba5e02630a7e4379fed7175f0f3d9f8fb5333451f25d5b044521ed38ed", + "0xb513ee7cf03529c88633176792a6b08585ff6163fe174f68e285d6315ffe33aa", + "0x4482f3d82f65f0fdf71fdf669403e0b835b5458e567dbd295b4f51d22f01650c", + "0x1cf0c0859b1839ebfb872a570e0c17886d8d7f26067bcd16af7f9f0415001aa0", + "0x231be14cb1cec949a4e806a7b3aebdb074d58e5a1c48b85c35138d5d3e967e0b", + "0xe8f0a0ef68efb2ea1bfb5d47e3c9446900329ff89a3ab7eccde41e09ec3e79b9", + "0x16348cb5e49e61010da09a5ad3cef83ab369ee3d0f28079584c23749cfa30238", + "0x6d33bc7f502436bfd0d574c3f6b1155c69f8a80e55c42c353e9e68abb46d932e", + "0x0e5d40ed7351b59846ca3dd8cc9c0eb71d4659e0add0dbfb0bb7f518bf45c821", + "0xb1ba4509de4c0f1212b2b07d949740f15ef8df9af8e7e9d765e6b407a0c5d717", + "0xa99615bb15371a15b92c119f8632f1ad7c29d6eb9a69e0ccf33a9dd268cffd54", + "0xfc3601e7f85e4b8e996bddcf1b34cb6c20462e21c715782da12d8e08a01cd21b", + "0x872b0f4f3ef00cc5cc6fdd71091de96c02f5898826fda4f837832f302497b51a", + "0xb34656439e4474e075d8ef523f6f74ef292a22281e6dc0b8fabdfd2339389919", + "0x048d4dc500031aa56d89e799499a86d6dacddea795ddc4571669fa55d694345f", + "0x684b8762b97a9d650f0f0e5edee73b60a29f6e75573bd6244518b11c4a571533", + "0x5d20bbacb93f7b03d92ae0ce8296bfd113a808ab3a8bd7703838d7e8356b6714", + "0x25efac3c3bc3d4f10ed9918fd9581d68eaa18fb72d3ce7ca8e36525d8cdcae73", + "0x48b593a335aa2699a5bb5a60394845c7e4c78046e050aee1c7f8831249f75b26", + "0x6db7243073caa6e5c0442f2f3926885fae0385e0238a69784ea8a00c854ef8c0", + "0x3a104e4932193c644e2135008d78c5153a9331e6d9dde878357c250a3b42b5e7", + "0x74b3b4666fa9811702d4eebf9680053043160be3a6c31a0105c703e07d530710", + "0x179f67ff0710067d3180ec03d664fb3d9936e8777603b051ebad4cbd0aad7763", + "0x38d5fd43ca73f66127a0166ae074324471b1a92e6f4bf99fde235ac408b35562", + "0x1f43748a027e7731c2fe5343ba7b61d7c6c6933ea45466b439a43eee1a3ad398", + "0x6b130b75bc42dbbf76ad97287a3a130ea29122ce7e48c5a8bd1e80a5f3121364", + "0xcd17f77d87174ab6ad6f2dc60d37144aed40b3620a9e6c9ac3e328aeae3097de", + "0x3b7fe9ef499348315c1a2877bd7fa44b622fcabc588687a6de4d2f75aad3f642", + "0x6c73525865791a7ca8410363d634f6babfaba581d7a0252c7f57dc8c8cec583d", + "0xdb16b0220e129be4c929888a8a46d21d422a352ac7b0360711d786eacb56598e", + "0x44fb22efd89e585079bca47bde1073dc052f8ddbad2c27cd8e2839bd4350b18a", + "0x1e6f1395d417a94162117b9371abf3f781a4b05d787f6a38fb0101bc36e548da", + "0x3eddd0764196fe15d7ac7069c04c4bf23070e57931493e9a0127fc521187b698", + "0xec104582dffc06da3cc1af1c8dc7522d26ab2408dc0f62051da2ebae1ec1cbf3", + "0x3616cc0faf8a5f5c19cbeb482be2ea8de01b2a3e81f067366c715607cf29078c", + "0xd37ca9cd5dc7c3c4e2d2f1b3c8db2a016b52444f1c088680c8544b6cea30cfe3", + "0xc3d85c7899da428a305d941e3637e33eb4981f071ee07c1ee1c82aba7c248167", + "0x62975f10a20de37466b1822859f11774efa4f37fb701f6cc0695d206bbb51582", + "0xd940124857e67e220e3d4dc27eb75ff048aadd9b7fb29b680cc3743b3ab6365b", + "0xc89ac3aa4725191e56fbc87d41caac2c692dd5adae638bf741f0ded040ca66e4", + "0x97454878805915bcb60c9915af0fe0558987dabe5d506e03898dede96544dec1", + "0x6ce55ffc54eec31d980ece5204876a3f366f3148a4b8c10cd190153cfc96defd", + "0xa4e923671f4ff6dfde2f11cca452ed4208808e93e1131de4ce0804cbe2e0d3ad", + "0x772d1c2a0e70fe37ac0ea8d7b4a789f92997bd654809f20f0ff7ad76a6d975c3", + "0x8d5de87bc2484465a4876b462ebc1339bc13b8229e6df4f1a9e9b458f5e9adcd", + "0xdb33cbb2dad0eb38613d69392951c6062eb669035691882fdafc526133d15d21", + "0xb22b8c0887f71de2da3d81a5fec2213ccb8a32060211077e2ed1613cf7962e94", + "0xffbc5a82fe0c2b3f3f34343ba6823f35884c8b1dd80fbaa68fd5f33a960034ce", + "0x9640ded5be08a8a7a2e6291a91bdd58bd108205f4cef5209ddd338ad764fa9b9", + "0xaea7f934206d00a592502b8b85159e64b56def4c72db3a790ab46ca81c75d672", + "0xb99ace258fe4e6be541c6e3468913f4f32ef9e9d1375c889e17ceea0c606e729", + "0xc54ae75381803d00b52ea6fa620766662e6f7946d550208743fa64d3aaf22c54", + "0x4e773cd4fb2347b796595cc67eb2b5c7be6409bd8b1944f4cafecb6fc5a60a0b", + "0x263f3826196c238c24d4c792c3c45fc913d4cb94c2d3871827ba43faecbf4d94", + "0x7ae1714256e21b9b45778795cdedfad1160d571004f5ea6debc16406bc2161f6", + "0x0c271dc055d8fb1ba9bf133f3c85628ac3c2b588091768380a881a6183514b51", + "0xa5f41cb430b02fb1027d8e99cd94dd6666516c785d7f618a0894f38f811bdeed", + "0xbf6665cbf1037e0085808897d8b04932a6ced6755fa52555ac00737e8029c7b5", + "0xaaca2ffc61693a6f379e54af473802770b3971f6accef49e5a2e8fc122e0a490", + "0x7a3eb7782e2c02776aa29964689cb1b880201e1b81c8cef39738d7f7235fb022", + "0x7bf417dda75c46efba6a8344775915d2b69f954afd66d8f52576e106d7a7eee2", + "0x3a324507874480d0f4e8466ed6602c99fcaa7907b61e9f2b3f100740f7866fe0", + "0x3589941fb7bfda9bf50ad93cfed18cfdf199a6468074416aa513cf83cc00dd2a", + "0x66b0965611bba105667a3990de5acdbd398d8d6e2cd0276b83814c4647bfe461", + "0x703258ca6154ec4cb1b9162678e3bb546ca6f9e626702f5f62dda98fdc0fcf26", + "0x2a9a8e3537b714cb3e158f7ecc816239786ea3787b1a3bd40482f02eb0b21595", + "0x46104b558f57296b0775d63ee4da42a716c234f3dbd7479204f35b31f4b3d55c", + "0xe7d9d0a86cc8b76526acb8e260de17508874d1db6ad19a4a84210a010212d43b", + "0x04af6e8bd51cf4c4307b2381b2e0c54cd991ca3c7f49b8cdcaff3aead70efe48", + "0xab8fe05db68e486bf2be0c507b834b6e496c1d1fe560cd3210ed7fbf0e9b867a", + "0x0e6b5f226d0bcfbd1f0a2f61189592d8974b16376fef3d0a67f757b796ad6854", + "0xaab68c29b061f8f72d9f3c6f2e318a7125a01010fb0c547835fa31e72d8eeabe", + "0x0446f90437150e4ec6246be5c718e5054d62cbf5878479457d522948c6e87f83", + "0xd1b4669e21c0b175589c0942d4423cd2b438de6665f0bca10818eb6246a07749", + "0xc20d1a68c015d886ef8fc3dede0d116199480164238617667280f833a4dcbb3c", + "0xe67504ba38aee984e9118960827ddce0eaae3d8797bfc87afd4638cb1867e41c", + "0xd3e985af3bf3e3ad0dbcdbed9ff1b04037bd1ff2e71886db3842a29f0ee8c4b6", + "0x8b809d1ae7a835f318f471ce227f7e7ff563a15d1e2463e8fce5852c9a3f9ce4", + "0xc232b56170a5796aa4333d29ad8ba43dab2233e0cf7b48d100aeaa4b2491d6da", + "0x9c338ecb25290e91a83978df4f5b7076b299ba5d87074c36ec96da0b3aa9351d", + "0x616a6134eee1221e531fc6d6b5861f5ced64e9b56505b169da67ca3c47cb54ad", + "0x4afd1e60cbeb40301c2ccc7129042f9a944f4a383a4f34b8acd7aa454fcd0e7e", + "0xd52d1be650ed156ba12b0d6be4b7fda1fe89927bd7626ec0ae45663848144e7d", + "0xa212644d968f7d3d89c6f12c3c3077184943d986dd9cd391d48f8f98eb1bc6a2", + "0x8e3374acfb9d1724fd7f84c22fda25f91737efde3d667f607b364e51beabecee", + "0xd77eb30cd87046093b27be1a09d93cfa5261b780b99116a79d6c16be7db838ec", + "0x05093b9e39e2d9f4fa95ff386cb2af67861359ea6228242be6b323c1eed5c7c3", + "0x8bb25606225d3451a981af24506a549e2bf62a362149e4c77ac72eef6316e691", + "0xd2749fc4a37792b3716634e3dfb8a80ba3e30fd73bc119069d507bfe7efd8a1a", + "0x3b58bef2d77a04b3281e6cf80f984b9067290bfe02a596b2295ccad38e887a33", + "0x2f69797f1800e5da4a4086909058ec857695a220644e61788b24ccfaf7e77137", + "0xd81872c67fbbd1a69d4805cce578b9f36bfd768d3fcbc2fd610182a7696e23b2", + "0x2d3bc9fd303c12ed1ca7efe27d85c7b5ffb8e079e59c86977a113bbbf863549a", + "0xbaef802512a7ea5006cf816c51c35fdae44a86daaeb6e9dd8fd0c37b4f744875", + "0x2e7fb70924e6f0b74541f2f4cb13f49bb3bd577f5bfe1bc29d805b0e7e1a3df1", + "0xe3918602d83478eb416dcf80103b09a051d5cffc71b0cb21461c5031d38befb7", + "0x87dae7dbb38501d6e84f738c11615dd9eda5f7b77e096a765caebea6a8c691c2", + "0xa19f74ad3f4e218fcfb15e4af95713cfff4f5f58169b789167e2b62617023697", + "0x744930fd0046b3f7de0ecf721e3b36e4b36c0f49eb98bb0c9ed33d40e76a2017", + "0x5bc7194687200989382831785b43f7f5efb23105ee2dd7a620a61622a2afec44", + "0x3672af2176d897cb8f64f2decfd924d74581bd85916be85e53f2542a54a24b94", + "0xe2e2dd1875e9265072d96bda4640ec6beefdfa9a91241ae078cec4c2a1c9b8b3", + "0x5866de65d88610e6123b7a57e28e196afac484045261d1a16b83fa232ba267bf", + "0x7224db0ae652be5fe9017454dd40c744c75e513841b5cd11d5fcaff598265c7d", + "0x04438fdfb56d125bb13f6b8bdaced6946299f8a32610205fabf4a8db9c06af60", + "0x9e9af6a569b87a4717b94d8253a0078409bbce7bc08874e091163b621a75b999", + "0xc8a39c68a74f23d615ad49d9d175086bf4e1047a750165bb071e3cdb70e1d639", + "0x10515734fb6d38cbb9a7ef33ec7831646636f845ac40cb24b08c432422763466", + "0x1604dce1fd615791c66246a7cd82edbfe860a5ac48d000cac1984faebc00cafe", + "0x56311f68cc563946e251d8c0ea74adeee6ed8dd7aba8f6ea85367defd5dbdc41", + "0x3fc81adf318fa6db1c4e7ff5424b235943667f2f3dce5119618e0273eb23c93b", + "0x38576704f6ca62083130dca418a9b68e374944d63521fc3f4b7039754d62f63f", + "0x56e2a402baabf470d0f9c3496d75e2c26c26ac159b996c370b118a313a9e9464", + "0x501af705914bfccf4ad29c38eee21641590cd8d334dce9055d90bff57b8fa556", + "0xa734b7f045d2a23ce602b032357a66763714c6e4785768f07d55c22d2f1de372", + "0xc80e2c739a3d142a4018bfe2074da8da33c471b93f5e7b44bb150b9eb63e956b", + "0x7a0b1355d05b1bf4c634651bbb2b6d65cb0a9772c30e4024f5e781e5d404376c", + "0x73827f7c7a15db5c17a986f31dd92de05579b0bb8def065e5f1cee472d00281d", + "0xcd64ee4b2a912d48e6beb06e7d6c9c236b5815434c0ee21cca0a13ff23dfb85f", + "0x768d2fa63c53689ed899f47c6f78844ace885fa18a36da427428f4af46a9e1d9", + "0x643c26723d5a4831d3d07f8692a6dc4456bb6190ce2abf1abf69159942d5d548", + "0x03e20a75c4546d5f54bbd7fd3e54c795c180b880563bf78ec55530a89188a9a6", + "0xa0ea4095dd9fc6f817c656913f8cde4044e2806488be48770de5574c0b5d5f8a", + "0xeead5fac8f3c83c5a10df161d95bcf1d27184c9fb9fbd813ec5f61347c11280e", + "0x5afba4426fcae0f1769e581fa6af97b5ef8fd417771f10405e1c9d09a74357d6", + "0x087f65be7fc2a14f216d7ce418a03fcf1e6169e8620db65c11d1ed6c0afed240", + "0xf9a7e93c40788db39b241e03afe329b6336187fbafa40c97ac405fefc1eccfc1", + "0xb02450b58c5afdd0907ee745263aa6beef662646b96b9ed28b0dbcea4f358667", + "0x5029f1169c92671ecaad7239f40fd93adf3ec07ce2ed0c4cac38b0cc8034def7", + "0xc8465a93a1ba7ec3296d98e0b01ad27bdbf16a347c5517b450905d3c3668d505", + "0xb85cd82c551bcb30a747b2258327dccb04094f918e36c3f120f55fc35abf59d9", + "0x1721b2fb8963696cdf32385fe87e8ec2c2d7fa34e099bb65498e4a030e20a1c3", + "0x6b6dab262c1a32a67353409d2f8b791b1799ee6a8e3c880877af0bc5cc5b812a", + "0xa634110e4766d3451718061efb890238796370da3c4a53a91faa96c8944d2423", + "0x91ec6c6f807285599e0a179d0d246caf10152e733acf3bb967bae35fb36561ec", + "0xc3b2012d5cc8d796d1890d39e2b1730dd53df0b98274bbfef8c93bd969912852", + "0xd036b9b29589cc551bf27ab95b6366d772e7d692d8fba48f473a2fc2d023dbe2", + "0xc51229a0306e56a53bdab1fda497281e23aba6ab17301c2eef3ce3d01f56989a", + "0x2652cb79e0c18dfdf545562b8569cc2775a1b0b1b465cbdc5880b40ffff22676", + "0xf24e0d6c03961043cb41638596c4ca02e2a2522a3e828dc4613a72ce5a535a67", + "0x01725e03a7cbfe2d6c5623829e4d419bbeecd1c7f925dbf1667979bb4da6650a", + "0x3b0c9824b726b2b556c6c46af48b84f856154490a51d775ba06aad48055bcbd7", + "0x2be2f1cb826d7575e53bc5e14f1882d73bfe145ed91b2ff56a885f66e136db46", + "0xd16752cc862f33b14f5976049dadc4f15f147f2fa76c50bafb38a7cb25c8f881", + "0x66b3ba188143bd421009c082031696bfd6d29fe7b9c3345e7e70bf6a470a05ec", + "0x83e017e8701b533c9fd22e30d63c3781b0ac9ec1dff4433fe7fb5c8f6f4e67ba", + "0xe4782b025953c5980653abd26eb95de1bee0524c14a74b970ec5615f98ed6768", + "0xeda29e9b36262e7c79ef9c0b60fddc66bae542b19caeddcdedf439573f773cf9", + "0xbc02ac1f023993253394ca965f4394bb40f9c7822ed6b2cbdd249e4b72f9b637", + "0x8e1bde0f2541d20b7f7e8179014e0f6b98eee5c1e0278ff1de38f4c13fdb4161", + "0x7b762d3d64aded9ff99e3423d7e676dd307b765ca6f1295e079ac53d5a4788b1", + "0x1027bb44ade6a1f82f11e9f298fd3957a9636bfbb97457c319e3d57ce72146b3", + "0x963864b3164578d4a7e58de16593273067a641de752b6df2c9b8bfaf970392f1", + "0x16bdf92929fe3629a57f737d83328d034c36bbdcd006301f28dcf52e1d1cb542", + "0x69952e47225f1aa86d952afb0fa8c668ae710a10cb6a94477d518c8f771f5c30", + "0xe68895f4ae2e4a35fb7e0730a5ef9c3e3030f6351ff6381f77e6311912ced98b", + "0xf28d799eeec538dcb2f371cfc6aa16f4a6808ddef0e6fd0cf72fde291d94f8ad", + "0x5a404922a9bfe57eb85deb66d8d83c869ddf96eae17e7fdfafef19c19efa1eec", + "0x96b735672e85aa95c2f8b4bd5ac80942923cff64a24991b3103e4ee39fb9a8d1", + "0x83d922f50174810fc45daa5a607a9b4fce69d8ab86f428ac57ffdcd9c2ff2908", + "0x3b0ce5a62116eafbf445afff0674112f01e1dca0e2af2b72d0cbbdc452177d65", + "0xe86cc93417c7dbcd4b5f051f4dca1394d272dcc2101a9e94a140b20f5e4c8b59", + "0x99b3e1d593b682e1b6454675593ed6828f8f4c5888b965981e3a7c602d89d031", + "0x81e0eafc2a2adf3d94938c413cd9f588e7525b91f39a689dfc3d0ce6aeb812a0", + "0x699e692ff89a918eee6d19a63caeb07832dabf1eb28d04ec97150c87045d9129", + "0x90ff00b66a14d821b05f692ee6d100dd61abef3234fd29e94bc84574439ed2e0", + "0x2de5779a122ccd84a88c3adc4edf7c1c03dd1d3e89ab45657885aadaa087e833", + "0x775a5587a907aa5ff13bafed032dd96c312b19dcda1b0e74e8a4bd327fe90e50", + "0x4fa48215f975442e6b9ea0629d308667242a7fe89f0cd0eae55ef1d35a3d6ab6", + "0x2e24c24731902f1b9e4042eae9e946b9d884dfa9f733ea5d4f7e778b68daed9b", + "0xf23a4a6061f45b1ff2095adf02ded238b37a0ffa9653fa9c1b0069e37e8552be", + "0x62b94eeb74bca8d9ea91aaeec5c13a05dae022806df28b92ecee99b47de999c7", + "0xbe6c1797cad2d5d9ddac3b3adcbf1622241e2560e3407139e24dde3fd8d3e435", + "0x7df0788058bea0911f2e30133c835515bd777f7aa9cab6bcd27eb3c0a6e360ea", + "0xd87066a4721ce567f44abf179184381d81c1c487158a6c57b5f2455472209a5e", + "0x0aec7d3081c3ee7d61f36e8c7e62ab74e41f00b664b690a341b9ff7feb5adce6", + "0x16345b31779e80499dc01f9ccaa0e9981b2b336500f33cb1f2943b66ccbf74d9", + "0x9ed6c6685dfa2b65903db0b234f4539906121330c5d55e6b2a2fd30549b2dc23", + "0x6539602958d9166335a7a0396ad72be611661bdd40c786cf9b0f382039c6b46a", + "0x72bbb4a201de75b9a4b5cf7381308953234c62f295df08b919c12535febf6fea", + "0x2d37293863f6b90f43979ba5944bec302008957e07b7c7f2292074a0a3934674", + "0x22677859ad20cf8b924d516b9f979652ac91a27459a4eba5455beac7f5f23128", + "0x704c898c04ead58c2fdb2c753359d10934e66b326f104be28ca7a32ef05a2bc1", + "0xca2b1ac29937067b761b57b58ae4069eecc799dbe089342bea274e56fde3d1bf", + "0x4a9773e6a2e75dcf1ff46c8f9931b8170a3609023f47c0ea9c4af000798bbc22", + "0x7e4dcb6c256eca2cbe9d168cc78c2702c373fd6e69c210d0713e2766baba148a", + "0x399ea7dbb66b95bae693402eec304f9cb6f4c6ab729d90ca569fcc2bb24d6442", + "0x49d0e561773458f834c96e8fb9496d4cdf83f2cfab75824cb1eabf8e8962c18d", + "0x80a0a209e41d0c3ff07ffe6a7f1af67997662494a327fa7f3bcb7209340974ed", + "0x2bdd6d6e7ae3f4386fc655817e92563e80f46e1b277be22f81a689de7637ea1f", + "0xb77f32374161e54c50dbc38822760874d966f9e098a2ea7aedf650adf25cc0ad", + "0xb49b1decd65a998a3dae2e4725eaff56276af3f0c50b2a3a35b6e94738d32808", + "0x319f78ae885011458f47ff1a110881cb4ac6a78c7d4d7a2656ddca73a88b58e2", + "0xd9fa2f47bedc0b405df34c98582b553dde76a46d38ac86d9d357ea0aca60ec2b", + "0x4283ac57e82bd08970ada71f4617728bcc467eeebb19c3aa20208a82b18fb508", + "0xf2ea3a5ac3bc77ff64f7c686305044cfe539856fb2833cbefcb283317012062c", + "0x840a9b8c756c3c3de7170c3597bbd085747b97419c01bbe484fc4cc7924736ce", + "0xa88682b957deb995307ed875c4044246d779e3f8c584cad75162fee119613806", + "0x7b9195c23833f65832a44d097290d8573b43e6f3e47dcb8c3826ef9a52fb4ff7", + "0x57bb0076c87f2e7187ea92f9f7643eb5b4b823b8eae9f6e74c8b676dd86b81a2", + "0x68593a8268b245a5c7506a05860755cce1be795994a7d736aba41ead4c025a68", + "0x90e21d5927d39329874688312eeb5296677ecccbbb9c6bdd4400c50c9bda09c4", + "0x773c0cde2d1f44575c89106a01881eb5d9593bc762a40be03ba979496ad7d229", + "0xc1dd843534e9844bcf406cc03b277e71d4e73026635412e25f3555d099f26a55", + "0xdf3f794bbd98096cbfa17e168c0de845383abf52fea618937ed81d31cfdd88db", + "0x1b05b1f316013609fbf813cae674f193a9bd8a75631b55278bbd37513b85641b", + "0x429321ddb251fadec6b6f794acdd8cc9d93512b98af23d20749d93c3c9fdbc36", + "0x6cac90b28ed13c907d094bad45574aabe2355e13e6a9504b6001e5fbb9c25235", + "0x89b43a3f63a2ce4f67071a121f447d7e843948395616116ddeb57a8714becd3e", + "0x6de560c95a0483d51410f66f38884947dfc787e1c61d14421129773010b46e0d", + "0xa0ba45049971dd4b906e73f917fd16312646d53c0cdfdc3eefe53628a58973e8", + "0x3d4a4f7155eac18fb5a126dcae2035155a140a84718f33bb20d2f1461e8cedb7", + "0x1cc19669bd91087d2046770cdc34e8f995cbdf2a0cc62bda70d6074ed58acefb", + "0x7c1c4aa1817de27c62f35d66927d924376798c954d65ba3ba02c0528d11d748d", + "0xf0d67a8f3c5306165cffd44476249c254898bcb26c937f10e8ae244edab1b972", + "0xcc20c5ecb1d3e83bd56e9213761f8320bd40982ab5fb669bed774b4490637932", + "0x7935073eb3e5c37ed1135cb22bfeb0e21727d170d106465fc35de75e8d56cf41", + "0x7d968e74212c501d0bc26ebb816b57a37a8cd2720caddb5bf66f489e13a61bc7", + "0x2c134dcc35d50c63a13bd8868137e0240280f049d7e392b97ff5f76d00aa1296", + "0xfd046f06c1d46d9125a119f786acdd76a85fc596f21cb15f367933b717ba7d83", + "0x9f5f067e4af3c8e92d2d54dd061620f0a13a66006b162a1eab4b1707499597df", + "0x8a6e1fb6205a423ec2920d448a376b95cac7233d5312287bd850471fb49e4f8b", + "0x2a6ea987659383f9885d24c935fe56de39d45caa89e60ba1768189318974ed7e", + "0xc2df6c8a4eae77eeaf11d7e5e2198ec4a33f19f5995caab4db6577fc1ce7b957", + "0x1e2ae8a42eb937749284820e50f11dfbfb606ddac3efb201e0b2664dd0196d63", + "0x4d63bb91f9f8a9965c460326f0604a27ecb0fc56f2126c6b3519b08a895747b7", + "0x9a46c2ec5dcef6f5c5b76d4b08b9d5085709182243cb8308a2863cca8cba13dd", + "0xea57019cc85f7cece4cea7eadda96dc9e464df2689957ebfe8d817b6996b2e43", + "0xb40e930b31dc1508480ffba351b102c8cab53c6603a0dd88bfed1b0da5347153", + "0xf51ceb070d8e7cb998cf4979ac985b4850949b4456980f523d8b9d72604a43da", + "0xddd28627f5c7bd213149bc4886bf4bcb8304f86068694fc743ac81ed749aec3c", + "0x9ef2b3df587caf086f4a9838a829491d1ef45db132ea71c6bc96a4a40d833e92", + "0xc9f7d4e19501c48dda5b0012cd93564898ad080a653e29f3563ecd40d36de84b", + "0x0565db36e6fb7b881eae309fef6fcdcace7c92a7ff148476b627c012aaefe4b9", + "0x08912abab10f16b92ddaa3663375f6e2b656e4ed89f2285aab6e410fc59e650a", + "0xefe9e68ca3bea929722bcccb5150884eb23c32153b14644b1c7f4e033dc3f718", + "0x4b33e0e078056d9efd857f909d1e409516f23da68105463167e23d71c90f6366", + "0x63cd4d1c69c4168798a3d9f15388207ea10ee4dc6be3681b0c7dbce5649d8f90", + "0xc8e7c25854d49022e9a0ae2eda8e7835a6db9ef7d612312e9deae23621ba240f", + "0x22c05e50f27e8bdaf4abb0a045d0639bd7f80057dfea638df6a7184ac49b738b", + "0x4a34356b5a447591ac66c51370fb6539bdf50fda9600082dadd91d33713a74e1", + "0x7147d53533ae40e886f6bc1c3b65c51570d72398f46e3266f2eba7b707b46b3b", + "0x1e49f75a30695e9bef14b036bd1c0f2b322042b2a02ca56604484e913b284c1b", + "0xf2445d48e823bfa77776234356ae0d3c1a850db236b3d2a95e5b00c4d7e687af", + "0x7034246c6342c26f5ae974576358f993d0e5e3c577e6aecdcc182c78082ab181", + "0x965067896ebcb2628ff10127508df1c811087f45ae258a0d8179d576c21e4891", + "0x384ebc34021ebdaf95e1bf0d8d61777b96a1ae65163cd3bd9b4311970a7918b7", + "0x1ca6e203cf1e058f20f5a8b1e33464801bcbbe04c79a7201ad6036bb8aa54101", + "0xf5aaa21a85fa9d502ef278262acf71789a3755d36dd8b3794becab7fb2d338e7", + "0xdeb7dec7ec133b6ac05c3bc0fea3b0002c8ffe58b135f4ae85b71fe0350dc7ce", + "0xd5773586ddb40d4c772541f743f7a4b08e9b419fe5b5b3536afa0b3b888725bc", + "0xeaff5bc016770c7cce7be21952cd8759a8d0eeb1bd849732c15dbbb82c613a74", + "0xb1a6a6acd39b4428accf9120a46d74cca6451ea4a182206425a8a64c6d6be5b2", + "0xfff27e5023fa1fc365db1e79cf3283bee2f51333059bfff47df39f12875e5fc0", + "0xadf1ce203b0acd4cdaf1d9a91cc158a21c823dcfb0740f089ce0830102b1cdef", + "0xcf20c92fcfa22d6fe7a60d1aab2d5a942db39d447d4ba1e9e76888a64694f1e7", + "0x210a684182ea379b50d641aed1baae3bf3752fd84feac4b3dd4e110c5cfc4ce7", + "0x220c5460803cc8db7a2b645dd5a4525b0703182cce173324d20e1c865a157811", + "0xba87b487bfae148239b44f3ad7663fd66cde8e21aac9e1a50bbca7bb7334aeff", + "0x2728161f9f040b4d92ba838d841404604d4d838157fc66f20d6c4c61034fdbda", + "0x3f8a6c7198528e5084b3e8d52d3101c27c5bed8721beb831ff921eaaca4c4282", + "0x2cc2574320b3c7252404db7c67b462fbc8d87bdbeb782ab1bbd257ee634a35c2", + "0x13aae0ecdc6a70d85412178ec12e971b2c4476d5e624938ca0284ccfa611d11f", + "0x6af7161831c3442db94cbe28ee9385fe79339d533b9c0fd3266213c2a5024a14", + "0x06185136927e5bc26ecfbf2299a0fc13cb447df6ca4a60e968be8c2b7ba1c2e3", + "0x70ccc84931d910a2489d50becf82383a836309bb90dddb21026d9e4e4368c85a", + "0x400ae9e4da0f847dcd4bb65e8f9f661a3b0deb78346b4f1f84fc712fd34410f0", + "0x57aacedf503300888fcd8db2138badbfcd663c63c3cf5b3e35979dad635c24d9", + "0x8fea6cc2da76b7cc7062af870cfacf4952b81f09c3c15d31145fbbfe1c0806c1", + "0x5125434cc5d4137ee31b51ed8306b4d665b8dc66504661b46c227e62a9ef1abf", + "0x254bc0b61211e0a57755d73ac618012938472912f855972b7ce62677f5d0e64d", + "0x2d231389c849ea459a7530ac1bdffa4d84908e2c61125a70bfcda932cc8e5efd", + "0x671ae73d4739bcd4841fdff266803117c5684c61031fff16e831a3bffb4bae4e", + "0x64c4db66cae82a96f29296b481619d79a739e2dfce0ac1f659d45f526ae58ee5", + "0x3f2f08ce2f21253f8c9a3fd650a885ca0e77f720a21ad5b4c0867150a0274efe", + "0x98c48268710592ee4c26620375968f2b8730a1bd1777239e6ffb9f116c6e1284", + "0xdc7a5c095c255e1984b4a5fa75c7a1d95d98097fc4eba898e644ff66951d8dcb", + "0xeee7579812ef09ae31068e8087536362a967b2893b709a458822449ea89a48fa", + "0x296e707796c0b9f9a2f55ad06c42d03625dab94af71c2e1c7016a7ef6645bf5a", + "0xd9a3eb363d4a36300dc4d1903a83447c89ec286f8d219f1156335da283992d60", + "0x039adf5a0cfbc394847d8014d64700ac4b6e78b531a1e0328bab256f7c407116", + "0xf9a92c6b1f0b0b3d7ae33cf5ddfddad516bfd7b21842d76098737533efd4f7a8", + "0x5a5d1fa3b8e05a81173e627f14e689c166776b93df401593db8035a65fba58f5", + "0x34f7fda3053b9d06e217223ee06fd194e2962c4a381482429e596df1fe319686", + "0xb4cfd9a71a98ad52c7705d55e96f04cb9064b1c32d3c346be51370b56ebb0f8e", + "0xd46a93765af68d238b776b240afd464a24d8c8bc869280ad618fd0fb6360e878", + "0xf3c622a4ee05d1ce27d59e7b9b3748547f4efdb1d6ff72a58fa93dccb7b76de1", + "0x6cb017c4bd8bb5186590cc4559fd9600399485ca917b10556b98cd7fb61441dd", + "0x7188f59c892b8754845d73f534587f27b7da67f42dcc1c73390fe2970bf0ad28", + "0xb4b17c93af08b9f587963e42703379c5e4f760502870b8096917b09b3950ee35", + "0x03165bf9bc20c87412a41209901d2bf3c8bc03a8586a1706fe1499641cbc4775", + "0x9ef57b2126a38c2dc456c13c272de53366dd1bf1fe768185a93f3562d064fa8d", + "0xbc3660089065220589409f7063dde34aa080179b3f22464fd9df9eed98d88b0f", + "0xbf1cf6eed0e0270d6be602040a97600ca7e1279db4279a9fb7ee643345a264b3", + "0x4cc471987bfae3b32179aac7018ba574c0315b9832915b5d0b804b38e9def6c8", + "0x51351557582b1d821adfdad36536b59b28f9a1f1243115486ce44d4b22d3952e", + "0x66d6b02183b9def37dce37b66ba4e9939241732b49dbc8addd147a89dd9e0517", + "0x47261859ce169e56d4e7dd75c5e2648597c7906f9264710c7e4dff74f353f739", + "0x38edbf1db358c82d0c945a7fc024f7fdc1165331cc19caf6b8943d3ce76b721a", + "0x5231560201678a39175187469f7e36c1c729ae060225012ff4f679f3fabb8237", + "0x763bfbeeab624de07a6e758368f8f61c0fcfc8cda088d2dfcbeb47a5eea9648a", + "0xce910446cce07477d424f791a71a375830ac26a2543b8bd1343e0d775d161e5f", + "0x950ba34133aea3c2947a5e5fc1836375e81c042ee999b60dd4a27e6492fb41fe", + "0xdc24f20fda563bf74ff7540a06f3631af8ab3b3722874a6b383714f463f5fb43", + "0xf2250ef512d3a11144370747f2c86efc73abaa81152bc6083f87aa217d16ee67", + "0x8760d0bc8f28eb2504f3bde3e429a47f0aed1dc2c7abbaf01c68033c07ad368e", + "0x7ef1c11b1f025f7e2aca2624aa9a11781cd860f24ce3fb525e7196e590fc5ff0", + "0x7c4e717fe77c8f9e742e312081d51418614031745b182746c7ceb4ff54deab6e", + "0x56c82f80b8d52128275529fffb3ccf7376f411d7cf9464a15fdecf617b4e7571", + "0x46f7d3ecd09c29d36a62a1a65bd3c59a14c82687b5466c9c130df14c286c2a95", + "0x1d04deaadcfdc7a1e5e612df6eb836f55caafb4f9bf4f1200fdfef4f14229f26", + "0xa0f5e65e99a22e14ebafc71f093dadc96c68883609a7460f904eb15360e3dd6d", + "0x8ea6c444466d4b6916a1b6dadafb87d75e2fa1ddd1836425dbaaad6e99f4d68a", + "0xd53d052bb709813e6dfe218dc4bd99c5ae83b6f5993b182c36a386502713c7b6", + "0x2e0cc1dfae87825d1a1d8946e021dc514dea384241e0a6cb66d5daee570c72fc", + "0xa419612e2bca19a3a8dc7fac4da86c2df4edcc2989e10d3e9050323011676b1d", + "0xe41649d9af504bd273b9da0fde578dc126afb55feb8b3c31a0d4eeaa9c7b83f9", + "0x0121be707b5666d5a78949b2ee263bbfbd013b69caa9566864711bda4c7ed0f5", + "0x788538d654618bcef0a63e31576e19a0872a92733ef7930ef50f8afd6caf110e", + "0x7777a3a4930828cc158f696e6ddcb87696115f473f219ac5582d8a38e0645430", + "0xe15a9f42ce5964358f862fa7a40bff0c8e8d7429a5ca923c9f0d4d0d574378a5", + "0x187bd59945e1cc6a877fb324b1d7ebdf661383ae7e22c56913f2e920de73dd68", + "0x938f100308d20611bd14372b16da0dcbc888868f8bd183d667064dfa8e67a161", + "0x5e61540787c83bfacbb58967280163f55f5ed00e733d6295099588557ef2dcec", + "0xe6625082f4039ef9dccdbeb9488baedf75fcec616ed9d5009deb4eba95cc680f", + "0xd01542aefe234567f106a4f057173b4f6eb5733e0ab9537af2db309edf38763c", + "0xee0174f3f9218a3418b8dd2bcd4132821eb91b31391b7c2c6e5a84d067d21497", + "0xbe26c679aafdea135aa493bab8ee348b255f50bc69592bbe017dd96b0da58b1c", + "0x297e6634c06193ed4725942cec32ccc9b4e77b5d02fce2ec9fbf580e3dfce248", + "0x820d98bcfbc008480ea32b162d15701357f094b1d7c99a1ff92fc0afd9708a06", + "0x82bce2be0a2d468b2fe0d3ba4ec1e5e8eac2d83f8b2e402b3043119a59cafd51", + "0x63ff3569d9a5661b6773a1a5fc10a522ea12a22399cd337ffef75a0d36735ab1", + "0x8431746d8239126bedde7d5c58aaf7f733dd1542c942d415d876ebf8a062f032", + "0x6bfdf119b93ef4da6f48265f4c526f0837a10c8db9c518d0dfe1edf40ae5fcdc", + "0x55aaba1f40c9089c65623f67eef8cdb827282a39cd0778f26e2f73106d3eee3e", + "0x0022a0b29d8188251bf5c6f37c76368dc9c7ed9e00376901162d1fff111273b6", + "0xf4bda8d3cb5b7ad50dfcf2668253e44b98e87d563ce17720dd1eb1a4e1c32628", + "0x994315a889329452a3e08ef029e7d902308022b74aa5a4eb2178929425c90a84", + "0x86a962d1d436f43f6fcad5b61b615f2bd32f10fe8c62428854ce98f4289707b6", + "0x3ce476498f26fd1d0b276ea639d438d7efd3c10451949efee1c91f279ef15ed9", + "0x199b2fef89c1edbe547e8c0b666b7b138d6f94fcfb2f09f26edc429ac163b127", + "0xdf3fd62e7dd0133ffa23a0da13d720373b57e85c28ee97890c355c44323ad592", + "0x92e0cc3bc262330ed8a1f42ad40a2db6c4e75e2d39e24a6ed5eac0855c12dd05", + "0x5b46f058c21b9447f8faaf78b2549f7f1459fa5ddb4211150bc26dd718f8361d", + "0x316b4f0e5b50cea376307236de36f3a1ebad3c59ae28dcf7838339d8711047e6", + "0x2b72ece0cbeaf94140b99cd9312eb891a1264a4d31fd839017e22cd4cdef058a", + "0x0c86b9b2da38f00150d49ac53ccb43a88a44181c90b492e886c54b0d6a93de22", + "0xba5a671174dfd7f877bffd7fb3179b1f3f8444ab14eaa9a0488207141bda26e8", + "0xecf73cee14b1a8fa5c2de5d78c058bd04772666ff455ca4225ac419606041f2c", + "0x1947b6adf9abeeeb55a66cad4afd016f6522faa641c4e14af94cf6e610959ad0", + "0x5467aaeb96dbe111a0d36fa66a71f489fb33ab8d95692695c09f4680086daff2", + "0xa21fd9195eaf856bd048bdb258507351e9a2c168920fd0c550a2340b5176ba26", + "0x9b0cf5690d3c3764f5c102fe1d5139202a1f982bd5afc8967eddaa6bcfb3af42", + "0x32bb410896733f9f6080a5b574b07c0af3e5ecaf69e995751e392c3905c11d20", + "0x5e98b3dbf58bf5adc0ccc9269aa10f9921afd44283837e7cb419ac4fb89f6164", + "0x051cd6e01ef3ebac9f27e1d473b0abc00d870a78cf894cfa8222d00976948b39", + "0x500edc8298fb83a103f5bf779d1df507644e054ef27ae61ccf31d883d85c2a0c", + "0x80c8fd7e50aaa14da3af3ec622adcf89eea9760ddbd5232a49ba55837be5805a", + "0xbb828dd031299bfd428c22110ff5d9f5612447e346e98401ab4a01278834e476", + "0xe2c5f408029af25cb9c130fc8fb5118660d08da399dbec0fa1709d1c0583de57", + "0x1be80d06b4ec5ef612e16bd8d842484039ca5663234174441f0722ca521958ee", + "0x21d755042a542493e44e92b4355af2f06f161c0e2583aaf6862730be7e9976b2", + "0x49b993b77606eb939ae485e82243e530e392af6d68be4ece5ace66a675a7a70e", + "0x954823b80bea8f2007503ebda5a6ae4610f94cc2c9a6ca22088a52468a960524", + "0x2693662c6c0961a92566deaa4a59204a0c436aadc0581b799e6255fe97d26331", + "0x4e80abe082c0b8ae0602c232ab0f766aefa702e744ff142cb9e101a6050acfbd", + "0x9c47c762c73836210a6bd78e5ddf9f2e817951d52b9fea0c823596c3df2a1fc0", + "0xe86094c8da0212cb0cd96f54c9f1b22c11feadc5599f6aa63285971651f11278", + "0x3031451f37f3e0288d61580e5b20e008a2ef5975e5d12345056949dca2c1d421", + "0xbdf90347d794ab3b41da6fb75b5d8d1f426ca2c4923216393e055dcbc89f3cba", + "0x4f7a0c9ebaa4833e7fd0ae0f3ac8dbecf3d97d0036a41ef30230e634142247e0", + "0xd1cdfbbf34bfcabe4a0eb90fb4d8592738203d245d68b753d418c4bfab8ae4e4", + "0xaa56db3fe5b2edc2ed277656deb51e15f86182de49836b4dfe2636de5488a86f", + "0xf67b05c233797d61eaff641e5bd35ee830bc1a8440e06f85e034902bd1023ede", + "0x49bb9be0064ff46c4b7820e7dd08002f3914fbf9250c96873bb3dcc7bddbe3de", + "0x594efbc23c0a371e3e5478c599466ff3a8d985444583b70f275afda13cc05c9b", + "0xd1dc59771492ee0881398f87a7c90db42874d720812c1e105b1512531d9fb1f3", + "0x7462bfbf8457d1df1288cbaf339861dc91c02d772f3c1ff8c215965e555d6905", + "0xee62a752465879dd62d08d7a15a54af1e813a1bbf2035384289bd634e2e99524", + "0xc7c66334011807d017e0df794df5f2f36c4cf496ce0a3589465662f8aa5433c7", + "0x839af48e65e3e1fd3d177d90f1dafcbb0209b107bf882cfe2fd514be625c1396", + "0xfb4eeb8514ede5bc952beee0e7e78c6d7ae544e6c4d935a6c92375b224e40c3d", + "0x38576e990356b7c44eb1dd531fe28420d01d80130e0ef0a42b9a8b01d2687822", + "0x434bb4312789b8cd93c5f930f4305760f86c54ab225b35bec70954aaf2fb4c2d", + "0x19ae08dadbf2f7da90ce777913d59e74592cacf6f385600f7d50cbbf7c4137a9", + "0xfc9a8ba8d7eff3a582725f8fd1539c4f77a87ecf23505de8a321ec6d568cab5f", + "0x20fb269b1a7908ccae92532424cc94604ca9a0908bd7c5e446a687cb3be9e0d1", + "0x9fe0a0e3511056762698573eee8ee2b0b87a8b6daad2141a9ad00c5b159521f4", + "0x3630751af37fd3ae22e78198868341e86735b03432879fb159628937c6bc28da", + "0x427789cffa2250d89b99d50969d8dd9917b5f4c721ed9de79cf81dc59f94d81f", + "0x5ad7e16bd42e35671230458f8f97c18baa5a1f81b675df259c9d2d7cbb09fb77", + "0x3d58c8ee704a934f6de776ef8373c653140e089b85aedd53219dc0b46ff03b58", + "0xa5a0719b16d8771b34e050660ba965b0ebfaa06bad1973033cbe2fd69fac5886", + "0xcd66e1ce23416fb4662d2b29dd72d9f8f981c66098820058451441213f2947aa", + "0xc7eb6f1df45136c9adeacb03eada4557326aa0a22f9ac0d73df25e21beb6bc0e", + "0x890eb4c610c7036e1494514e1f7ff72f414c51143fbf13cf2cd03d8d37a03662", + "0xa54328a1d2ffd9aa3f38a9e6a0539ad2517c4f6129f01768891acc0a2b2a721f", + "0x147644decd98b450b284d05d7332629e3c6444846f7c71dbcc892d3191f2efdb", + "0x1a19c1a8fc7f9d838cbd736243e66b1f637f49b1d8734c2af417227a11623b30", + "0xa8c14722a6f7e7efe695be4e6a21f2d1c8b8d71e2cf69e7645ecc5cdc7b6355a", + "0x8eb33cc1490499aba376f581b68766c4fd40e7d6027f223eb46e27199acc8d67", + "0x1b6a906a5321b057f453624693d4ae6abe79a5b8fcd63a777dffb8b2ea4184ab", + "0x7185ec1f19e7a84c9f914dd223b382ff56464b01a1b88dabda415a01e1d0a1c8", + "0xa172df0cb06617eeb95d362bb36d5e5ac52cbdb2e5f3c2cf3d9b78ef28fad82b", + "0xa11941ce1c866d077fdc995acf3ff2ee0ea0481eddd142f9b343c8403ed606a2", + "0x1958ac9a77c5b9825c401b204001dea8ee2520983fb3e738a467980a7bf9defb", + "0x6b24d043eab24359787ed7e93543967c9f9b7ccf99894c1ee7768f6235cb0cfe", + "0x6ab8c28ddda71b937d1a6feaa67b071f78ff7ead3a192ae63dac34ff24b8d929", + "0xf101e3da7546249b5b6d4dbe960c713cf152627a7482fc3377aa31f430c54530", + "0x22628e903ea9eb3eda9c93ac92d77b1b8a5ee62706dc5ddbcd079c57d5b721eb", + "0x0050467a543fbf0a232c8ce9f66eaec6c38c3c31b8ce3d590d1b07586374c1ed", + "0x4235a1330a45838b2d2aa9873dfbd59cfc0f0cd16e13ca9292f8342eec255fa3", + "0x2049ff9cebd379b51308220449b3568c6d7843f5b49f61b85808287f3d60441c", + "0x50c2ef0e832df29297dc524fcf3af4cd0988fbfea71987f3ac5cba8d4ec34102", + "0xe7260880b2d822d18c9ac2224d09fa18f5c324fb421470aad5af6c2605b40985", + "0xdf51e1b441b9809b26cd7cbdc4df27eb9c7fbb3bf764971684aab6c63e282a75", + "0x597b5c48840a25294feb135e0318ba6d6ca09aac476b1041748738963136a0a4", + "0xc710bd4b45a991f7f1387c25db70a1964ca4fbab32b738424d35a6e06e2483b3", + "0xd67460a50ec79c90a97e25d4cebdeafed6c897593fe8b24afe47a71c818a55b5", + "0x0ac1f2282e4491fdc8d28f1697026b7fa88f46204610cbaf8811d38dc84539f2", + "0xc3352ebc532273e4224dc0e94ec4cbb83afc2b5c364d71534344793032441006", + "0x42f3d39c81e118a7d515d82b6880104909a7915aeaca8ad64fe74d9fe88a7f45", + "0xac6fa42771e9cd6ba31dcff2455d2234c53c282251ca2399c727fd5521eeff0a", + "0x83ae44822213f59d34543a6d4fcf76b4e22cbe5a90674755072613550d348551", + "0x99cdb65200f9d1c602c5c2ded67a8cf2722cd7c1ae3f11d29a2c1b702923df93", + "0x2adda7cfa12bf5ecbc74ed4f4ea419ad7cd3e7cd03a0e2b32e924aa2ab98ec42", + "0x3da7434a58c60b7fc7fee8e30b3073ff4d3c381288fe6ba791f68d74d24ed19a", + "0x9dbe78f9121e6c0d99fa6d441f6aedf54be14fb39a277cbb5f19fd0b846305c3", + "0x2ded5acc49e2e1fcb57a66a81f59405febb50edb6b41d0fa8e445477028f422c", + "0xa46310f11937ce81ebe8d4c60de1a5c8787a1aac35ff3b6e2f0cc793112b7df2", + "0xfa693856fd1867458c335c6e903e5745a950ddf8a43cd9ee76ce8d0b3070bcbd", + "0xb374a194d9edb55d2946d40a16ac4617e4d0674630c6a970f58db17f21d22c12", + "0x651032646288a0b6fb5322626bbbc5b6b87dc5a5d59f5f39073f2f9574646c41", + "0x7f4346336c95c7fcfc1f849cfa63afd46dde8e346ae0801aaaffa9069f989e99", + "0x8bedf8e9f5095b4275635525fea6169c5afedff2ae434e42c5cde973de77ae3f", + "0xf92ac4f6fdd7801f15c8e0ee163241542d1359372d2189d8cd2a33f925933cd5", + "0x806d437ddf966fc6631a8f81a54eb82080fb2ade64a2b715872d8f648d23b57d", + "0x2151451d68f912b58bb510002407943ef6f2cc87a992e6df0765a4c239e63779", + "0x6a02bab7734d8549be10373e6395c368492b8518df793821962a940d5cf93654", + "0x4de627f1d096c86c1c1dcde2a314ba65700b1ac47b9db95e9ae68f8d28f52b16", + "0xeae202c747b699171115bb56652ed534d9ca6de0e8c3d947d63c6d60b5d658de", + "0x7bddba4a7c160445653f62d27c1622323c784461d52aba5a6f19964194a063c5", + "0xddfcf0c5ff899f19c4ed0604e7b4cc645ce5bdb7b7c7d6bcecfe7f2cfa3bdc0b", + "0x7d27d279f52b83afc9a115c71910d06a054fdc2e20625cd05fe35ecb03734f5b", + "0x415f6bcb216ad524eebd7bf177bce80cc3d5fb3e920ed65a8ba6c02f59fa88ba", + "0x570daa81ed1b593529a07396784c2996d5703f4124f941e99e8f9cf6b608b1f5", + "0xb9da28526fe8300989e16c83c4bfe418c74878be1bf3af12ff3b9a098a4c92b0", + "0x691938f83dd63e39be2fb03422682ee8dae8e0a95bf4d09b4727f8162b2da11a", + "0xde168c58358db826c9c953895b7a0419066e65eec0b7fa479c328719cf70df6b", + "0x65a7b2207932e96c427a6c01efd0c3f01a37e02e7dd98b18ea559c2a6c83c8d2", + "0xfe54ee65b1b8e21292fde2eed9ddda163036cd6745254bc7cb9f3dea737832fd", + "0x543d64c2a6b763cabbdc1a9316f37115fd572d96b5c75184c155e68532fdc8a2", + "0x31b41a4f481a786bcf4029b19e84729c699a8d742fef50040221ddf6785d7335", + "0xa383494d908727fc6198035c24afb3f352a16b29b0c1639062e7169618bcb38e", + "0x3da745966ebad677a703f5db94777fdc307f6e3e66a7c3c5ca24f35cff3f43bd", + "0x32fbcb24d42beb2128d95055706b767f7df7ce16c1613e3195342db84dc9955e", + "0x1723ae6147425f5b01b68de9847d79b918ca0f85a800d981029dcb5e3c62eb8d", + "0x997f18b9977469cbeeddaa1bb31472be3806c03ae77973c857e32d6fe2c4d740", + "0x6c27575f33b1d85fdf9643c9ddd27085f4241518cbd5b776e0d2bce19b152ef0", + "0xacb86fb3209fbf57c42eb86d2617eb631e0ba36da7de5b2c7ed63f168a7b112b", + "0xae02559f4868fbe4f114eb320ff0f3a38086f364a2ee537e6051cedfcee76d6a", + "0xc96e439aaa996d4ea4c276d1592fcc06e829d5f3cebf163aeb75f590896a2648", + "0x87debf5b6912717ec3c0846fcfb5b459a15254660cd5064180c0c514b4b15f59", + "0x37587d340df2b40b3f14746b72c5a72c5f51963d208b02c9671d6c623079b584", + "0xdff2805c029c4e3c249de3aa9f5cb3b48daae4f4496deefc91ebe3251c18629d", + "0xa84f66a457869dfc95d625d40496250ff33894be23a43e53ec892481f1eb4fa5", + "0xf8fb34bf78ad6d52be6fbb5472f13322b506f594ad3b585c04f56ed8d0d9afa1", + "0x546937b89a4d3b59817377b9c2ffe9579d4650cce71aa26bf2c76c571ec495b3", + "0x5ac921894e98005d03aa42e8fbde7ad0af0401e350c8ba98c01543a93b37dda9", + "0x3cc76dc057c73f0e0fdff28d484a092747ca42bc10989c599d0f597ead6024d9", + "0x1992cd7e94e9ecfaaebbd08d91519d6b67857db87e2e67c546371738ae0d2d0a", + "0x3604be694574c05c63d69cbfbbddbafe3cb425d75a13e69d61b50fd8d9c947a7", + "0xd1c82e40206d2a89e3a1a40c4a1b63c62ea6fa0847ddc2b25f63cb9bbb4a55b5", + "0x66ba114d5bf45d50e9ab9beaa879ce18d02a8b4f989c29ea7e9ae604593e860a", + "0x94f74c09ce5fd1c8fcb9cbbcc476af20fcfd9cf01c7ea65c14917da7b9560ffb", + "0xa4e154ebf83215c3843ecbff1dc8f646f221505c21d2a76f47d55466d895f1a9", + "0x28c20a0e95e23a023678443d7bf5b2421975b827dbd617239dcf26bf6db9b255", + "0x55d8ddf586d61e137482e3f4bfc1904ce4e04d21c6e7ac4d8c7d29b1483c8c0a", + "0xa9e1aed191a7a1a92bc99604e3b24c02356ea378b16de109362aefa2fa978451", + "0xd543ad635db78b2518681654f98a32d227fa6a1fa9b7043ad12cf58c91e8f729", + "0x102fb87da8b57948fcb763d7b797233f21523545f78388d8d05c6d7f2a4b388d", + "0x4e7273e2a92e897590988f38f8b899879aa1aea754fd5165364e8b98a66e0d62", + "0x5a06544527f88d9fbbc5905742863d873367d99e574d75496c59caa041e2b612", + "0x6a8957954db14594746daa61f907e4694e2a749ff53ea6b1dbe77d7d1f378d22", + "0x0debcd48486aa0d33a783caec0d6fb1256ffcca39071041fed7f047eecde8640", + "0x9d0a9b13dab1888bf0eedda217c501d76f587ee9a8765bb455cebcca0b705599", + "0x30693bf8c9bcb6bb4187606f98e138700e999d8824cada72d3d07f8c104fd263", + "0x494ef870dff64d1d65b4ae4b49ff13c145a6058876eb657751d58c06f62b5032", + "0xee4150e64f9ead8124d50d56fa4b6e6d185fe8ac385bd2a9db7ee991f6e34c02", + "0xb859d7db7abe48cbb9420d008d94e8d47753cc78962e5dabdded9438bed56b1b", + "0xf8b1fb734c345111704d73fe6944d0a274964a347d7dc5c7cb8677104829f5ce", + "0x5dc002623d9b3b872900b0b313ae8520009de730577b6eb2e2de18ae5cd4ac94", + "0x4d63e346ce7e654db6f067e8348c539ccf622d84020812724b936c19ff4f86af", + "0x2ed43f4e5d6889f5379e42d4a06de7c343080da74ff353960e4cf980f750fb90", + "0xfc61d0c90ecb073c022c87098045b6ca3f2b66c94f3723c679d81ac652b16f72", + "0x7e69914b56984b8c7cc9db1732c3d2d32969a58d6662509846e6faeb1305586c", + "0x0ec9b1b68efc96fc7d831ac7316e0ac0d908bac31be330d905f87b136556c241", + "0x32fdf6c25f6c741dfe468289cd7f019ec3a40c5d8fe882ef662b798491c0dc34", + "0x1ffbc6b29826aa58595d1a412fb90050f2bc3cf0ebc5462f308d4c8d85a1eb59", + "0xf0fc93cc2868cb9828ce16463e4cbd59637672d5815dff03aec7f3e1424eb204", + "0xe404321694894ab375f5a65c339f2cd2a53fb5a10f312082ce019681f6ed64e5", + "0x81ab1f93747c4804a85f56b0c6eb61491b958504ef7b898fb1362eda9b394e1e", + "0x1535d439d0043d1436de963e3eba47335bd7afcabeac4d3fc3f342396d3538be", + "0x42da1b95481bfab6cfec59884bb1ac7572636c8f489df2768fe2140cd2702766", + "0xbc3fd861f6e09efac1782d9d383c4ddb9b4268216fbdf3c25689162628e36cec", + "0xcc74c3d8b44a8cd23676babb4efb0e67871582cd5686fde9de6a052c5bf91ad2", + "0xbcd7fe80e95bbbb5ac93b1df5ff0b8e921e7ebc4960877acc1a95c478c65d64c", + "0x045e5918fa69606b9546f5fe83cd9212000828c54f9cab856f85d3a22536a751", + "0xc0f74dbb5a42bf1656698c37aeb904a33e969099f215a7efeeae0024c3a409d4", + "0x36d537998634f2dcab43b387edb63119c0f4cc68b1979a2ceb373089c531ecf9", + "0x87c20426fccdd225bd3b961c7adc1de3f9ac9640f6d26bd183f6e528089922fa", + "0x195ee1daad5c3d0052d6d633eda1c9f7160d488d4bc54f4ac3babdbb678eeec9", + "0xf9a5e6735f9c5577283e8cd717b56f69dc8306b23781755f2e513d15e6738cea", + "0x3e5bc3e78ae33367ce7450c5da7436f1faf3b1a62d238208df207307762688be", + "0x123e7b4f7e6b9338df2827a238a266376a20a1fd065e9f8a4446fcac4c6c92fa", + "0xf4eb14bfd197d49c42daa919322f18228d2d9ae2dac6dd7113c5e7d12d2ef866", + "0x78836678c20a40fbe09849fe190a9e74ee070f2056d7bef85d0f124676a93130", + "0x7986f7321971519933aa5dd507074c7b007328a7dadb8734eb4aecf732703fed", + "0x14485d24b7e90fc39d91ad6051b7f596d320b1f88f54fee132e032753e59a766", + "0xa80a9a5db758bfacf831a54022c85a838e30c8611ab4b17bda0641994302b59f", + "0xedf1814fb78abf675f3c5671c3618e5e51105647997d6dea6a0cfd1f0330bf6d", + "0xa91e9fcdc4f2b5e029abdc6b2523079bb4a2f5346d8a5a674e3d5582b8871d1e", + "0x3dbe468159a8c068285c92360cab488a4c1ec37487dd54cdc0b70e6d7cf074dd", + "0x69877439effb3388639ef6e1cfa132bc605bd8a0da053bcca23d82aa453d0040", + "0x6751d32ee3a1244532e6698ce57cdd0a59f99130e1e7e004c2751bc49d10b355", + "0xd1760a4f6e5a7967985125d2deae8bc783e47b1b85e19fc273e33eb2ef88d271", + "0xfa934c087923cc16f636615657477c48c082623d7cdd35508571655dc14efe57", + "0xb6b1e4387e04c4ddf88ada0aaa162345cd43e54482fddb4297e1eb6f8ba1ce74", + "0x3988089edd46b57c0bc83b1bfeb0050b503cbefdca83e96f1c12e7ea80688a79", + "0xedcb1bd8b522ba5155965cf18c25a090be2f8d7871ce60f0f371cd033d5a31d2", + "0x2f887b56b317e9896698ec9059d36aad63d54d95a01d389aa196ae12e562ca2e", + "0xe6d6b89e1d851fd24cf54f6b60c6c93a8b014ae30906c156374d73605aab3028", + "0x177928968fef8c6da017b177f6be85851616775be043b64f72925e6b8a4eeab2", + "0x71a3de323d9a600e15c25a5a6e05089d849defc3830fd69738f548fa4c57aff2", + "0x8e7d92f316f96b491e4831f52a799846810dd032bd720dc891195739192f3955", + "0x12a3433e8cadc005ac35da334d557c8cdad63576613f07df8c3ec9f528e846d9", + "0x1406da1f5efe9d3de6a829f1219f731f3ac875c7795f72b5a9ad25a57970b9d8", + "0x15a849a0ea56a777e00325b4af4d9996747486cc9893c08b0773210306193521", + "0x6178e69be88e7e93878b731d062b29a34bf2951082b947f35f60fba2c8de62b7", + "0xc4142d4fe01091e82626178b66c13243c9b35de0f07a49e3c5f2ddc15b39feb6", + "0x8abda6239557236af27a2cdfbb4fb91a6b136931c53067739578ed13e1b0a2ff", + "0xf85615d9337092e25080430cfa0b7a24c97effd422a1947a4c07239d5221418c", + "0xf9534d7db3b5fc1bcd7033ade59fd66bbb94a5bae91c4acebbb1540fc8bd3b67", + "0x5ed0f8035d3920d6e94b881cafac324ce5688f8c97668715733e0d00733b0fe7", + "0xeb6c474a0adfd84c79b86090c793697c0bb39d6cb007c725c2ae7afdc98df5a6", + "0xfbfce3e019b0b29ad03fd9146fa368f9965050b40733ce297bce6acefc4668fe", + "0xeda9ed65fbb1c7fcccc91de519f69933ae66c8ed59fb65f64751ca8aa06030c8", + "0x359ea9df33d466b5dc210ef0e99f3b4416ce03a5439f49b4cc4c1b98b22a21b8", + "0x14b2e8729b70abac62120541229182264b78c7ba1a1a379ac8a582aa0bb0d739", + "0xcec0dbdb55f92191974c2c8ed716578c5ba04c4584a0770fc0d7d5cfbdcb2717", + "0x07334b05a08cab079354cc1f7a945caa3c633de89a89c18244de81ed56da850b", + "0xc58e0bb71287fe92564d00b5094ce36b7899c346679011e52b73eae45bace19a", + "0x9dbef45ce9abb762bb9b30b61456a90b74b0b6f5b41af9500699542d933f9535", + "0x3cf848f770e15e7f682075c77f7e980da6750d3d4cb038479983e341eea3c354", + "0x608a4c5958ef3b0a324a7cdeebcc3abae89c1371c949d6b269b2d3936d9fbdb2", + "0x66422fbb9044305317d900702c2f99702317a8a83ccae0911a2832f623356c8f", + "0xe977f86ae4c5b350b350a3d6af7fffdc9baa96d9a7cb24834e5dc4797fe39fa8", + "0x6f56fc66544e099797cc3b0879dd20b21796ace01a0029e0d8464a3764d1e858", + "0xcaef7878c703facf29fde1467dcd08b03761872f598f42f5c56b4cb367b97255", + "0x9055cc0c11cbbe8477c7dd35b37a57e7994248c6bde9ac05e85717cebd2b970d", + "0xd7b08c0ca8abb9f07e3df1c4ebdcb03b0ac2018a905d1c78e6825d2bb5ea1ffc", + "0x0184cb109267e58d5bc0193a04548f0c2b87286ab6b03a1ff7b6d88a725662ef", + "0x3005e0af1ac0c5fd6d58328c06cc7f5d89c8c4ad173106fee1a7e37c9f2dcb95", + "0x8f7f8800d29c66b4fb12334b622fabe1cc4ef06e4ded44e4315efc381987cd56", + "0xdf74e3be6d22159e0e02ce3b8f0b405e6469557ecbd12e4432d52f4ae4637bfe", + "0x2fa9a889f958ddc41bae5916657f946273447add502464674658bcc257f1af15", + "0xbfbdf04ab62a35b2f7b038b02d8c37ee946cfee18e10ef8a4cd5409a5fe81d19", + "0xc4e834510182950161a75a843352b5b46e246a05b7c7e47240b6cdf7e18b4de7", + "0x2534be362fcc238c530f2ce8f64a3366d4003a21e6f32493a082b7efa1d413d3", + "0x628e5f76af96e64ff34c52cc5d07562e72c53e7bd4b7585cbc83b7c9951d0d2f", + "0x41687c81b22f67e4ab6ba0163da6d58c81d94c5db20569b4a42fb58b7321a442", + "0x50f55f58cd9768b611fce3ff13e8da9195b1eef5d0a618fd27f7052f88c8fd84", + "0x1b64cdcbfc12c42e9dbc7a62a1f8eeb0baaab8ccc867f7a7308c88e4968eb9a9", + "0x77e9fd9a5d64b66cb901c5795b9f66424638b24e457024b5e71ffbb79ed8a863", + "0x35644de61c2108bf9d49efef164414cd2594ad4cca6bc421699458c9bace5491", + "0x172ded87912492ee521f79c1ef22e42b1d22f17c3286575a5d419fc00d928199", + "0x3c8fdc337338b107ff5879b3e95cf285b5128ae395c4b89ccfd05a3d942887d3", + "0xf4b22643ebb6d46cf292531792543f9699a99674978045b0c911818211be6017", + "0x783fdc538e4505d4187a0f341b066007caff8030c3bcc4bf49ebd31a8f6b4794", + "0x38e11f176844f680e75b65d5225533639eb522f39495b9ee426135097e5e8fab", + "0xc5e0da94d4dd6e29c8bf3684177a62051e7555ee87007fb07581c885be598edd", + "0x317dc456dd095f9eef53781c214806beb31351cf78cb1854be257b4039324b8c", + "0x5bbf954741e453e3157dada0a69bafb9ebc63c3dbfc0cf6e3fc937a1b14b7356", + "0x56a5354de5acff2b904c5b6b976c473277ac2364571c54583bd682e76bb3f43d", + "0xc37f17385f4e6015cdc8083fc750499ec8c9063544102eb0e3e3b7e0b5046946", + "0xd616c205adf0ecf00c7563fda837e94a4f48be8560ddd15d93988cfd3242b40f", + "0x1ecefd5cb0c61b120c227274dd60b42e6d25229517b20dc3e37a7c3b436f0e92", + "0xcd447982c518db12b8aeba63b68d8caf1eda6bcc44400c9d83c4e4d64b4e949a", + "0x3763ef2d96a89a302260ea66e22e3255001ba2f003770c03905d4f39d8ef6501", + "0x2fcc41e9b574af5402cdce8dc66d79488cbd5cf960209918863ac9526bcb6a70", + "0x17b71848876a6e0a8857f1e5d04762734678ed1a8addb7e378915a7c3f37c981", + "0xcac9e4641f50d52d77e0e77b1a1b5fdd25cae239864367b3d99026d3fb973610", + "0x55eabf50cf101f65e51dd3a54321c1897a67c50512c534ee9398a716a790ffba", + "0x49101d5719e4de5e4e88645de3c22cb3ab794df815555d4f22d54ac6a59f73f5", + "0x509cd8530c28cc098b0aa80d3006a8f71ac7ad56101b880288658917173b8c8d", + "0xdc0e15e6d321519f34d40c6b2cf5f6955c15af815dbe02d84606ed76a01fdbb8", + "0x0b8e107e7abcf80e85b3288786dd79f949449225315c9125730d7d42f0ab9cb6", + "0x07ba997ea28711f221ba26d724a09a52b2737b8aa8532e890490ad811ffa792c", + "0x713775500194ec8691fb540d63e99a70cd443e5539b5f8e2a993266bb58266ef", + "0x3b2ccbf35ac833e845f00329c1f8d130a3f804c55aa83c35421adb83749213bc", + "0xee82c15eb18a075b00de8fd610621683dcad88a19c1c507351b5be0de0c6c4bb", + "0xf874298782be23045971092d8305c469a309a1a33f6cfde7604e6499d2384cdc", + "0x1a9d88cd641f6468fceb32eced3710569d511848f393c2114ae33d7f36c12f3d", + "0x5b2b8c2ba5d3aa8a0503d14e759154d1f2f46d819b363025a77d4cf5e3d83586", + "0x0082bad01acd43bc2c504f66ae28056ce352257b7ba7e2c27dd36d256c079561", + "0x9c6e4e01a831348ce64da4e4bf04cad5f58749573e54f1062b0e2921bacafe74", + "0x600e1b0101161721066952d71401f8fe6e689b66b26e2e74cc924f5e914e8eec", + "0x8720d215255e4d5e2a688096506d5b25c3a79c511d8c0b3dd7ad3ccf542e9abb", + "0x48baaec9724cadc4f7cb8f10549b8daf87b2572151cdf9308b3e96f02b048f23", + "0x2adf0f56fb9bcdbae394025ae949e694e01599887e50c355c90c3ee5ff32eac2", + "0xcf78410476d781bae1567f3d763af732d2ecf56e741cffd1bd3906af83de1f2f", + "0x4e7e223f6881065ee722d6ff9603f1786e4e99292e9caaa75b7b1fe9aef00109", + "0xfdf0b390b0395f007b1b342065096e0a8da957b26ed4cdcaba432a202ec12b65", + "0xcd40d2df140abc1228b2e1f45b5d65a0f3e2ab8b7e740dfb5376b036f63c1c2c", + "0xa491347f128d31f68cd1ae536d8f982fbfa5b58d855a95219f104db741d3d2ad", + "0xaa91fef9cecb842de4df61fd1650267420c8336758fa450f87ee867ff1520905", + "0x75d1574bf7b23319a7c8ff6a0a7cae649313aca8893ccd223f1f77fd71c9b8e1", + "0xc72491916b25756e3f505081b7f63e32f3289b86cbe0181ac9d33d29f666b9e4", + "0xd446465131b34f091673736f70fa0508ee7065c4011359c302a603b6159cb52d", + "0x1380689a50696e1cf0c19869b9773528f01cdf20b8f8a6c6a7165fda31ea49af", + "0x01cac6d9deb56473681c02dc753351feda402a1a1cc2b4cc8beeb23884f40760", + "0x3f622e134dc529c5cfbf58a3ce91d57850578f45b77c4683b2dfe4530ba0826c", + "0x016c95fc875baa0a5d1ae22c8772eaf574a6c918510875f1000d65f3a779dd04", + "0x86e5f579f42ea54a96e622f4a6becdc5ae85e0d0af87997fae87b6707abc8d28", + "0x53d403f0d0f1f30d919ad7212cc5e2e73cb4870c4fb4e6d260d2573e9bc5575e", + "0x961cad0d17fbec30a8f614ff3565d12698af096e61836cbf1f0ea125ae3ed72d", + "0xc9dcfe7844bb4ea845125bc3674f326c0f178c5cba4349b9461e40bd6ec68c3d", + "0x894243ff80e90c4c4676583b4e428f13e077008d225790a234ae215dc53d33a4", + "0xe5fddd80d3cdbafb53e0cf3c095d33904ac8db83bdeef9816111d20384aed444", + "0x5c7ce294d82fe6502045664f7d13d02063ef24f0f4960e4fb62bb6abf08c63eb", + "0xb33a5699ac121a51c0074b4783545a86a428fb239b4307f1e45108c85af88617", + "0x37168f3f0220f50ba3cad0a558cd8b01a7a435b6c3c5cde98b420ba3b54a1cbb", + "0xd50928e60d00c23adfc916e7f9a5363fc8c94c8edb3aef41ac1dc719041f92be", + "0xa08b27f437ade4d527d883194f79927053ac55a3293487a65060aeaf4c4e5147", + "0x326e2d1f45438741b63d346f0da55066dfe0284382f1b4ee54b1d5552c4f7d83", + "0xbd96baee5835d9d6007b0b5957e452d71d1ee31aa6fde99796cce59b17dab703", + "0x1cbe90df49f8929ce1052049bde7d6169efe0b289ad4e05414a8e7bd61788900", + "0xa0b914df37895be6f5341f3f4013ce5c61f108203dbac4ff205d5f1a581712cc", + "0x1582e61974c0bb5f9f2622d70e772f3e9ce145be97eaf5a87ad794268cf352ab", + "0xe946dda774c96c7878a0daa686e4a22e0d9d36a88dd9c93b1776432adbfd68a1", + "0xf88a07db8c0fd2a1354c38617c16b4d2e4f8bb43d9049321ce47a8c03c8430d9", + "0x2adb489b34c480267927daf3ba3ca7567d542edb83fa82e8040ec57e25e3e6d7", + "0xf1c28c6daa3e97466d50d9780bd3335f3dd096c3389b906bcc12426ae4862a99", + "0x4457a8686a3839b7d3b592a1751c25b216bc64e9d0b8a81eec55601ab8d8a98d", + "0x0ea5d5606c5e81f92d31b49b2e54ce6c6314b13ac223c83094280d0196e003b1", + "0x33a91da49deed50914d998615077c5192be56e482ab230bdb3d480d283502e2b", + "0x5385496abf2e351c0cbd7f6fcb5bf5b5345783b4e512bdfa23b9736e77ea43f7", + "0x98f808b18e5778a1bbdefa3f19991a3d008c27e9976db0ce77ddf9e4e21a0feb", + "0x5381dab139fbb0ad6b61afa35c541aba559e2ac25c4ab1cf8a756c2f27c6bba8", + "0xf4bea5f3ab0bc9ba3ad00ad79402d1d62da125d311884f225ad8abe9fc36d56c", + "0x6018a9f7edb5ee7ada70c3e85f22ac88924d06031cff3f61104ef52bf0baa2f1", + "0x01cc4300f1cd2bb4948329d42e17a277c7da52696d46a60442b6f5600d869faf", + "0x330240c95bec1ac1a476cd202aa74e85db562750f860a9fbd76e813f16cbb639", + "0x0809c487d45161c3b85cda014603ba7efd6b67a8c7aaf314cf20c880ec623a7f", + "0x653f53065726f9a7c1b96ce7d836acca515f563a47c9d7d47aa8c5c030a9fe6f", + "0x37b8dd7b2a844e519f9eadab305efa5d112266cbbc76bcd5afc119e0dd337ae5", + "0x385b7031eafc345ed353d9b35dc53010496db172cd906f8e0b7b891b84a65e4b", + "0x38259038fbf1ab3f0ffac98e6b312457f6b2631f68ae477b9302fe740cfb8e50", + "0x5a963aaeadd708291b41bd419cf2ce0585e162e0d46635902b58ee85e317adc3", + "0x881004f4fabe3e7642c8cb5e99dc3909da28451ec442a299f331790c8065e049", + "0x3c721f828959782052312d30d8256c9351a141923a9c2e2ca5b605f3a92cb27a", + "0x3429b149f860e963ed3819ddf19164977d637489eae313331c71165c7eb8f824", + "0x44e291345b79ff4116797899da20baf28fb9d4d2a5d6b1661a0c83b8952e481c", + "0x00078c007b6c0b3b6603b0838b03ee9e8944fe16f99f0a35eda286a288594806", + "0xbcd3506338253f0df5abf0c2866cdd319fe75bad7ac6f18d1f8201164e0b9986", + "0xc047f5f06cc54e4bb54c8e3bf22245d68c18b4787a01d324deb2139d7405814a", + "0x77ec49a04762af36eb63e2bb5c5cbbf15b580020117639ed5546749e34285195", + "0xfce516ae95eaee4067e95a5752494974ebdd182fa47deab70fadc5afb5ea8648", + "0x2ee54548e56d2cecc3e6cff4e60a7664e55d9b1c1c9a61be74bfff7635078cb3", + "0xa79dce8f10567e060638cb2f09ead0b191e59d972c532a7e91b33d27151cc23e", + "0x436b4cf10f5cdbde72be02ca16602190a56c77f1686533e643c885351d4657e1", + "0x9070c78384138f5e17cc9e6148c7cb7591eb9864f042b82ad38ee263383496c6", + "0x12a8d5285c871a0b05e370a337834458ae2159b5d8cb4bc93b6cc83bf7351b68", + "0x3c07d35ea209492f4aa811c51202f081a3bfd6e31705ffec497d70bd59b7a6f2", + "0xc0a99b851e0fc4655cb3cb43547f4ae6c36c350aa71626b61ed3ad3492f04600", + "0x064404380c5969d8e43d759ef990658d7cf5bcb7b4f8512fe58a7e994e199707", + "0x3d3a61c95ffdd3c7f05b3574370bf4cf0eec605ca27cde051b5d77e062315f36", + "0x9259e0113f1e009fad7454eebb238e0c7f4b7aee8118b63b6c05aaa2f0bc39df", + "0x76ff9818e62b25fbd698ea021e200ac9314090b801e000ecddb71bf4829aec8a", + "0xdf0031d6e1c55717102ca1b3a0bd389cc0d227f0f804396d4b84b5dd26abb1ea", + "0xd0220e77632c2353d51b92b1638e909c1f41a7ab0e6801b65e344ab594f48881", + "0xb15fccf30f298101d5ca0034cb8585cf14ddd76d58f3a8ca71a60aff0d0438f8", + "0x5dcb3817ae05b8c8490e197cfdd3f0b701e61d83b8f6423b3f24f27ba0f4c668", + "0xf3bbdc6651a4ba011443f6c6542b3f45b8aa2ba8bc719e7220578d6362cc441d", + "0x1edc95bab3c88a66246393058ad1a9557b371e726adaf261a5faa535cb8fab76", + "0xe02975b5ecb9fb8abecab35298704ecc476d2e6205c2df900312359d5aebdf9d", + "0x2a5c9b033738fe9e7ba6949df526b5a735753464b746e7d1faa29491a8e5f57b", + "0x46ac373df276af8af25aa1407659a8e85ae12b51ea6ae0150ee2b80a76ea6d9a", + "0xe85513a38b54114f4b6cda2bc81a4dcedbec22749cab6676c061d95c7f38258d", + "0xacfba9967af17aa94f0bf73c3b1cfff113e14625742a7398a25a01aa29bf02e3", + "0xd589df920ebfb3c3c1660a16f74213dd6d487ee577bdaf18f6279eefb9252c57", + "0xb2b66c26bd139976ffc2471f8ec71e353108828bad5094a324d1e4762f5547e5", + "0xeac126eb94bb1ba443373fb2556753d95804891d4763a2cdd1d297f1eba0fe6b", + "0xfcb52c727793003a70941fb01bf6c184890a691b70c0aac3b11feb3987de8628", + "0x1c1b6aeaea826ed0cc776a322454663ef555adb0d3c6f50480957ac4ab7f0672", + "0x187affcea64fb6195ee27cdca1096142898be0fb8f216f10913a744f2005f7ab", + "0xb4e42e3a4c94477a6d5d7f3de429edee7d92cff93b647c71d7a20c1e07a35117", + "0xf960751197118967fcea65f10b51d9568c184a8bc968c609d093a0f6c15a71b5", + "0x0bb9ca3521abf8fe971d371749e5c2258b1fd4c681ded047d6dc7820d303fa9b", + "0x52354e8e99ecb5c2dcc1214c08901d715ba62a7463d56c76a6bd1287a74f5c38", + "0x8768dc0cb22a0ea9fde00170783fe3741501d958c186e2c636d03fdf8a995129", + "0xb4204eddcc9c75372de503645bddaffd3f71e8554c3bca09ec700d928a9664aa", + "0x97c94c63bd30754d51abf48aa830bac3724cf77e366965e9f61a100cd0136714", + "0x60dff72f08506ac9ddabe3f957f88a1ef4935f187b6c536643500d65512fd393", + "0xa94f4c353581e474a091655c78c491c38315e93e287f848c17843d807aae3527", + "0x09d90469c97087fd45cf1a2c5471c6e81e0ec1e7850dd76b0d0cfa9fd49aa13b", + "0x298d03c60b8dfca9ecac182b5c0f6818a4c3d84e55314c083f8913a8746fe335", + "0xbfa7ba8daa97bc681bc6ce413494b85ccfbc10e2bc96e148713e0325e21b3b60", + "0xe61dde9cf0c1c6fb0a37993df24dec2f221f97bdd34f607de13fb1f947e7f284", + "0x91e9a9e65d5076819146b246647b9698954bcf55e7f059db32854f93b325d35a", + "0x7bb2fb25b881772f318a10b6ce8896712c93cc85ce9c7c371337020e86817a3f", + "0xbfdda2258ccd28dfc81f83ad7cba81967120257392279c7412f0bb116605a21e", + "0x0a626f29328872380ebf6a10468307abda5a02c3a7b9e04763c0c8c83f903df7", + "0xaa8ee86e9446a125356a96f8ed47c3821da54b003558f68c823c4ac1ab966c81", + "0xe26f3cbd95e0a26683c26adfb71b6d4fc82b034171f29836cb9bf391cf172376", + "0x7cb80eb383da7d8c1120fbe79cf3bff3e5bf19b9f57aebe11f79ee23dd82e611", + "0xc9b85149830b7a2dcc1f613f40ae232bf5cce7770780bfa7c77ecd25ae0bca6e", + "0x859dc28f93d2f3b17e176aa8248d6720be498fc85017491c68d6af5f4798b437", + "0xdcc4dc79cf88601caf6e038bea275a98208d221ac8d3efdd5db3d2181c14c947", + "0xe1bd63a920d45b05efe5d2fb99437a26bb7049ea5b183e99866d6dae947ff724", + "0x4aa94bfe1501f4d37b0c55d77add7bee9bc7f24d444a3ed1c6cf27d67026bb62", + "0x10931498b823a9784c4aa3ece5e88b477050927fe4016e4b10de7e2e0eadbdb9", + "0x7f30cca2119b5a4107cddca59a88f10ad95cfaa879d97bd1e50ae6a347e71b1d", + "0xcd8a0dd7a4fa9b97641d5288375105273c9025a2c9f3d7d9d04179fe3f55143b", + "0x6c8ec850db640544b7e5b22c19253dd1595899a7663d40c4fe13de4258cd60ca", + "0x06ec895b6dd7f299edab3e2e3a65322fb7f8fa8c9a6182b7af4f0fa25acdc45f", + "0x45f6d74f05f7b366770428b49630e836c2fbcc72133ef03a1bcf9953209e693f", + "0x3d868a3921aede543f2bd8ccbe3b51468e7a87f8278e4601c4a8e740e8c339cb", + "0xc808c8fa7b02023e5c64999a141edf6e0ce0239e37656e0fa7c5156443f555c0", + "0x82c273cc2afd955663515932357f19d657eaaed2824551814706ae3843fa1739", + "0x5785f16929a6a73b4621e75d31958e2e9b00dcbf3a6b38bf3ed59672918b68b7", + "0xc8f84b888e55070682103999cfc315ea3d157d0771f0f035cf2ba03f6fe1b1f1", + "0x343a05e1a5e75e09528f194394caf6ca8caf94904d54d89c9d22abd5cae0d83e", + "0xddca7f95c2d9cfdc9efd9158d29045ba92a71d45488c40d28b257425c1c56bfa", + "0x008a2b681c4691d7e0de476180c969aa511467f27755d0d498eb22c9b5333835", + "0xe33fb40ffd6253b5701d24c59a4e217197f9eb7caf7c2223722734f4c74fca4b", + "0x650e8f1c6c4dbc76ace7d6c29b9a659d520af9b291b389bfe3812c1ccbd07c58", + "0xf88c36b8042df77734f99395eb68aa9f4b67a21891c42350e4d5e3e6d8fdf168", + "0x882c68aaa8d1f6acf005ce2ad3a6fef7ec1212ce610dfb8a7bea9417d87431fb", + "0xda73d75513895d5bd5174814da25cddac9a633507960e78ae6884b92e48ee699", + "0xf07d98594c0ecb16cfed18adb9f7b5b1055630b43444c70e6357cd18ebc09392", + "0xd70c5886426c55dda997d615d325b5cb5b652f5673601a045a113d94a17715c1", + "0x3e8dbda1f53c55fa4de65efc7d294a02d78c69a98d59049dcfcdfff6b7eaa521", + "0x67b14249f9c987298fb00e0bf560a976dcaa7fc0d02e816f84c3bf7a4e7c6901", + "0x4f8affa83492afa72e95a36f23356b46e58a0a19ecfff6960d4d6e5b9877b1d9", + "0x09cd2a17655988d2d8cd5fbe44965a6c15c3f123b75e1229621b9ab74d030e53", + "0x30693dcabd19e89bdefff4753cbc64d00c65a4af98f782e6e67b4e84f6b015a9", + "0xf67db822aaef8bdf7967c0dbe25015ff6cf88ce21e8bdd25feb764828ee64951", + "0x9a587510721ee914cf8b9c863859629ca0c8ed22b0aa023e9efb0756d3f9ee5a", + "0x5d00c0a840b96a19679736a7ba555f3e9bc5263b4b8437d6c3779191eda0a7c4", + "0x3e01cf22757510938a5aeb2ec6cf5046b7d3c186bafad7d57b81c7d2a99415db", + "0x0ff2d3ed3c5acfa5db9f9820a1a314865e266a823ab42f40bef6b0276af0a108", + "0xd3207e322207667c614e50be784f6b4d9c3f48362dbb65b17c62f5f33e631ce8", + "0x2c3330fc9f6394c0b8eaea0d156f2b9e2d2da0ddc8837e0a28d373aa779df9d8", + "0x56c8542686730adabbae6717ed8cc8f0b974037842ea5d1c80901f7c85eef3fa", + "0xc51d8a382df91e9f1fb0dd72d416a7d094aa3b8ca4f90561e82fdbb9b78c28c4", + "0x6507fec75b170f930df2e28dc75ef3dd7313834c8a8a2ec837d4ac27fdc906d6", + "0xea23428fd27ff3e5c6681b0640264ff22964c49ab0aa41f592280ae25d380c83", + "0x8e2a629fee2ba03e333bcf7fa0261dadff518dfb0e386b21cac0cdb2c7c514cb", + "0x4b00742b5349bc9892f2d36abe2c723a30c4a20ea5b899a7fee8fd759f066fbf", + "0x5b8d880357c44a79c0d04b5d347dc7c012f2f5cd7679c4d4131e5c481b45f1af", + "0x65d2859128eac961e29c063fd918c7a2b485bf72743cabb0fae8bb288f155dfc", + "0x3db9720d20d90d7d1ea448488d02015f4b1c36f556d704749723ae1c3a35aab5", + "0xd9676bad19db9f6896b2170e6cba496f5714ff9a70252fa1d4c82029435871a7", + "0xa36e49e6be40418bef884caac3b30e63fdaa1b8f622c70ede69e6d7c9c6f4539", + "0xefb40f7d197a63927f761d99596439b7b69cb7a39214258b372450fd471ebd88", + "0x7420e77f7230c7458f728f7ae5f63f0bb9182fd11ccb9a82bfcad17a8d1b4f76", + "0x7ce9551cd4cc5009d28a6048701049a5decbcf7e11904c588107da90f57149ed", + "0xafdbfc0bd5252cec1654dd24c375bf9f4af647cadad403923d6aa525fa44aa85", + "0xef0a4ef158ab6b06863969c24dc7ce5fabbd36181e9eb6d1662ce227b38f8e61", + "0x4e6d1c00feeb4218a0590fe046705fa35929767430f2c33b2176afb45f26a71a", + "0x604a1bef767235afcb7f84a20ef59d39618593def34034c67cdabec8f9436ea1", + "0x5c91553855f3a32f708dfd76c83a7d7f23aa80e5a6d2a7e9d83e82a333c9e267", + "0x48e35d198e8194ef83496392e05e3e14cc9c7ea1f324fb259c08a0f8385b422b", + "0x9df1a27224c2a20b229cc8686d95efb1570e822402c9df4db0b47f190c33dbee", + "0x020eb0cf345413cf0324f7561031eef27f188de5dc41bf38471547aec4e716ed", + "0xe9f7708c2cc8ee4785ed54a0c153730103fd92c42bb71eb4f86a93111ae11018", + "0xe7b3a27e3f5ff6fcf2925db134ee5db522a008db4d54627b729d5502f3968d08", + "0xc9c4b33c131365224675a89e4e6833181ae50661b114da50b14b0669d6ab7155", + "0x8986fba93ce8e336542d3a640d156029ea1cd99c2cc4e946de6d46e040e52bed", + "0x53b6ba779e5b91b5abe44eacd354f6f9b5b2343e66d60bcf5083ddd1a5147d21", + "0x854e090d7d5cacd3e52fed513055b51ae884965bf1146a629825269506f97371", + "0xcaae36c05b0992f80bfcc8f1c5d3a771feb88aa67f2c87b770637fa24000d84e", + "0x6992bffeb071ba81b30b8a6b19e9335f8eaa2da4361844bfd57f08488dab5975", + "0xdb63608d8eefa64871fa9fba1da1776a67d0c0495502c8eb4005eea4a0089563", + "0x57071fc1829365707d66abfb8e388478cf61a14f34af2c864b7299f6bfc2322c", + "0xe077cb6b750e158f666ea79aebd5e19e25b9d3694ac7a44efee1fe58f2bff202", + "0xc8180f9a9292284d2ba09dc40f89595ae6b554e6eb0c96aff578725076881102", + "0x89eb01b1cfe4089ded962a36ddfce84eb0c4337780446cdd88738e7241257c30", + "0xd1bfe1dbb1c9b6a06a1c18472ed66a82ca5c7ea1fdb5dcb9af1347e6ed97697b", + "0x33695a8c53e9e16e1a2255055eb069d9fc59436ce0ed698aa7323cd7e078cd96", + "0xa1c746d3df0eb28100b84c6c91da402c5c0d6a8aaee66bc05095820764cbdefb", + "0x3dd355f33c841eab61323ebfbe4a608b3dc9779a291651b885383ff70b8418dc", + "0x206c8095f502a995777d4756949d8fa7deeac36a106721d6bd1c536994fc8adb", + "0x95a9ffc34a966a157c5e797e3a1d0029bbb86999f1716cbdcca9bdcc5e77a5d5", + "0xb2c4e8a21c25d7cdaeed3a42b8670602580bc99ae5e85d4e36771e5cc2b7e0ff", + "0xc34e130d5fa9ae3df02c54a5eecf210d8420db5342af4041d77b8ade44d2c67d", + "0x5d733448fdde29b3f3749e70addbf4fcde659aeea24f90dab23997a696db5daf", + "0x8d63fe21beb60523466595253d20fe518dda259cb44fab5945943550b4e960ad", + "0x98e584f6dc76ddf7ab116d2e9244d0a0ecd99d180b1916957054f8440623f727", + "0xeb66965a23c4413fc5adbf4925ec5d133d2579c1f7764d6199eb4f7a5548aacc", + "0xc95df33729fa401a40bb0ca23731b61d5225f3ac6d159f243e1585440e16d529", + "0x2052d0e9ec0a62dcc0d0c892e7e704ed0ce03ef8a8e9c898a3691a571abc5c30", + "0x1f8567628ffc96390df8b7b32ce8ca70f6d8bf57b2ea0bd9e724c521ecd4747e", + "0xf2b48a4fef4c6c6127f7194ac76c57167cbbd65b9cff702daae1ae21dbc2896b", + "0x38dcef1bcf7600494424ae0b24956deaf664b92f3dd60b7a941ea144d789dd99", + "0x267d1afa22f77c5fb78434d822ee1c3fd24740d6a30f3ee4fdac95949ba8c044", + "0x0c01005442f62fd12a49115bfee0faf89d2da7572dca5b0e8eee445a0de8ddf7", + "0xa8d05f61408ed491620865b2cef9548d88182f37784e190b46c36bb09dd2d7e3", + "0x655eba047145af7d76cedf34e144040619d2d416367b57c7b7d9362a9375889a", + "0x5233ac6cb0ff6a892fa475b0074f4b6abd8e244f2a665e6649232e528bfa17f7", + "0xea8b2976e790ed22d708bca311a5b26c113e8c0ea4cae30607d94eb232ccb0f9", + "0x159dafbf20b2e624d22018f214cbbfbbd83de406e9bbaaf53ba46041fc3968c9", + "0x4d34b229e010a2ef72dec76c1449cce6f61d9cb17701803560af6b2072850ef9", + "0x32e7064197d2f739695788a00113452e03306a4f73f80ca62fc5e3ec223aa176", + "0xd1604bdf1cf9253b7b0ae8c92d09a2edec43221394c258d29707ba850004615d", + "0x07e0048d3913db33c6a9b45a1b232a2088341441d398b09319b455f57c18628f", + "0xf6492cd50378901ae238c91685319405d9779a1b78f22bf36129fd31fe709cbb", + "0xecaad91132667d0b1a283da22cdac651a4036224bd0efc79bb747d0c5e64b1d7", + "0x20565b022a8a8429a79a56aadbe2e32db24748238fab33eb2b0be5d83d1343bc", + "0x25e6d936a7b526d45ce1430744f5f4b41cf694d2cc50753cc88330e3e2a0bff2", + "0x7130e4b84c6efae0653dad6e16ec677bee7060a8da8ac607bde7a2b01b7511f0", + "0x93a8bf0a86793725e09b480d9098a43fc30a8420c5c2c2bd01ba8afa837c2371", + "0x2690922d4bf86c9a35e982b10f723edae97bb2a842f362036337396c7d9f9d16", + "0xd26efd262c6605d3be1ccdb03b96318613cf2d5b80350eea826758b9fd8bc28c", + "0xd3b2c89961d6cce736a9994f8707f78068a9806044cc2c96004d659f82753690", + "0x0fecacd3eb8c415a8db644b4dfc0ebf04a27f9b5e53bdac80fb927f40da4a8e5", + "0xd5600a3afd0eaedc221893214d629260cea97d7d5335e361d43183b4dc678360", + "0x340558e8951e1af701e95a963221109154f12c5870e9c9b9c4d7f9975d18ff89", + "0xb2ec154d6a59610822ee2318e3f279e249067893f806b129f4f0497b42aecff8", + "0xcf13e6343d50af1b2ff792e5a694531077e67858d76b39262ad19d6194e62df1", + "0x39db02f0b3f062645478457da8145fec8fbbc8a0981be9183365fbdc11a622a9", + "0xade17860c7f456c0b8014490f3cd15cb5f080e7112b789028f1e86ef428c06ca", + "0x1ab544445bb5d499c541c4fa02c5f850b9d18988e94ac6992525e2ad372d4936", + "0x2c3b4b33a865fce54d1ba1909924b0c6cf9a14a8cc4e3a42e1b4eeaaf86fc50d", + "0x857bb3e657f86c864407a7caf0c6b71e42427302adb85c853f330d00433ba077", + "0x79e42bfeb2cd1191783b7b2bea5e0e2693d9d15ce8d230e03dfbeac2c90451f2", + "0x5ec96430d6d1c1e9395a214e1a685e92c3780a78ca94a173d0e38fa6bca96461", + "0x544858c87e845b1f80043fb44f54a2449d31a0018025f1b41309a745415b1e7b", + "0xa26f04bcd6a580b99e9b81ed739ece117ad357facf1ecea246f891ce740029d8", + "0x857eb2767e67873c3f1ee4659c778feebb69b248950068a828d65750002cec36", + "0x7d6ad830b628a38b1753a33e5df98269d351b42d5bd60329e4c205ee5f30584e", + "0x6cbbf7d83f87bba0d4b4997bf336ac52934866cdd77e7dead51de84bfb717fa2", + "0xea77b839435e70cac6a89e891b8d1c495b39d8d6db38c352e10931e70502ec20", + "0x4d6a29a4487600b0e05ebfca7418dd6b43746ce96a41d4f17e25cd6aa1a2b733", + "0x3e8223ea6ca4ff147b59b025237a2a477495e746e7a551045374b27798ece58a", + "0xbf880aea05a3e440f31777f109995f2a1967272eebd9ff0fac241bee8747a8da", + "0x028cbf04056dc0f407496cfa901a4491c659173083ad73f84d457f016e0431f6", + "0x68548e63888fe0f203a333f5a5c950b36aa35e083a0161304a2b80aa626358b9", + "0x385546df2f083f4781a8b9d5b645516f5a77883eb7dc8d5e399f4f563e8956f6", + "0x358a0c7c14057fef517c38de9e2af33ab44f68c5c99157f9429db596e822c842", + "0x5f89b867c11d5258618595e2afd3f783e8db81dad073d8871a33d179f537cfb8", + "0xfd7328d25120390f5982919333df927ba3c63331321678906256c1ac02af9a45", + "0x406a9797947503dc57776a5c2ed6cad71ed975c05e15ef191b310088049c11d4", + "0x6e719945fb48d4db24d57a92e4d6da5cebc1a3db4a64792dad68b06f92c69c87", + "0xe2e7b80879a7ffc1e4e3f901ac99d252c1625b6824000ffd468b2d09d2cffa25", + "0x179979b54792b23d1f1940550d7c961a1373f6dda048817d087ed6d731af73eb", + "0x10b1ca5637aee0b063bf3a2fe5cc1729929b9932cecad392d7da6d567ca82d65", + "0x89edc6ecf4b7f292dc26c29515ffc3367850e5a8dcd95979244f5c57f81003d7", + "0x2cbdbde44b43c5dc078433925dd423ea51886e880b04e90b156957dd6a057d1f", + "0x6953ef4d3aa2abeac14fa44a0be4979bde0e579cc591370b08774f4e65f95d05", + "0x0735cc7c85194d5abf6ca0dec712db94b6b009c9ed74ff6781b7940064cd4626", + "0xc3f9b62bea678c0683ed688b77767b3fe3e4fc86456bbaa8c0172240321242a5", + "0x3640c7a7a1c2b62492098e0b5b9f4c482add16a86c0f88f8a60eafbf28347ccc", + "0x73820554bf239c8e1b92304f3df8290d18aaf765b45c8820f618d05eeb80fd66", + "0x8b948d61bbdf95e634d5c3827c66266e3ee42b49dc0a29100efe0f7028d100d8", + "0x8c422f252ce4e7c981b93c24db0984962019394f50ef5b62cd34e32ba7602026", + "0xd250921e7c17e016360e0b79d61d6c19ca40ca2d84c9a7c8d9da04ae4676c29f", + "0x4e71a2075113014494b5cf8504d48cefcacf14ca6be5d99f945ddafed4b58079", + "0x40d0dd35a9c91dbb1de1df4202a50df1745b2a5e80b256c3542bc0cdd5a2c524", + "0xf77e21f9edcadcf7753c1daa00720e024f56250766ac6c31a89e8afde10c9056", + "0xc70a38751d11c4240f2e94698c0a13a62d0b3cd825527c1dcc5e653186034f07", + "0x0f4f7881dcee934f71ab555428e89e26112ef6e99935761f3d4f314bb5504a20", + "0x82febe35f996dc229d6f6e89ab4c15f5659860505d64d454f625c95284a307b1", + "0xc557d10c1d19c90ccb9a504d31b0d91bedfe9a82388824fe901e8325a9996dd6", + "0xa241dbe076d02feb2b67d606b8592c970d193b84309196191b19087dd74b5eb1", + "0x4f687e1fdd09e68deac949de2738583e0dc2bf245790b5185e2f4e00f5e8da67", + "0x076b44af8dbdd16f859d9604f91e8809f929024eeaa6eb457c30db2657c03430", + "0x1bf2736aed60997b49084afc7a3d2b429d8b8836183c9ba71fd61afbcd1b5f0f", + "0x18ef59174edf670a07ed5eeae04eaaa08345d384d33cba45abf2a08af2415a5b", + "0x30f123870658c6cb69ad9314e6260a5ece2d5eeb4964601d4243aa1b56f4e021", + "0x36ac3e3193b6fa52a7134b9e4c7db6ce746619bd7f4d07201362062a3f98be0d", + "0x6a9250440bff309071b1493b2db2b4134c725ae364fc8a8add7e108f7434de4e", + "0x557876702f5bc2bbe17f13c76d0cdecfa68b0fe281f084b2f343d130405bb80e", + "0x5bb14f5bb4abe8e79909035a11109385ea2fa77c4208946841b61f1dc8a5366d", + "0xe7602f83ef13f3755b1f99c740fc46211f7ade9088a1942b8ecbd5a33482c093", + "0x30b8ee6c04d787ab137e7bd6cad1073e4e77a74db657798cc74c79676de337f3", + "0x01067e41f6b5fe5a26009378b7ea4b0515aac9449eef2730de5efc22554ed10d", + "0x73dc8e186c096c752f8dc2a69805e1b24eb5edc7553be26d36698b25829ebfb6", + "0x23eb0c950ea1467134caced1d86eb89d4addda6f8ebdbcb85d9127a5ce0427eb", + "0xbd0f1080cc7c2adc0874fc6d89207221155bf414e1cfa3f9360fdc98c820627c", + "0x0bdad5419ef94ee6aa76e4971981e54f7d6560f3faa3531f5fede35cb2e211bd", + "0x8a339a58e2ffda5cc2ef1e18a078fa09c3aec4b2a8cf9b6094ff620fb88860dd", + "0xc9a633a65b909af3133befda06a57b3058d625d816ac978f01894fdd7b3295e0", + "0x6dea631bfde98ab2b7db165e29ea75316ea50137d15a30a9a3b444d50d419e10", + "0x0a74031d338957b9564500f28f0e45aa571f48e4c85cdc52d6ac8d472fb66661", + "0x5f9e646f342e665b2fe387bdcabbb381a71e54f766afe9a5ca6c2cf999b50e4c", + "0xa8691691561a9e3236c0a26593f1c49b42f03c94ac3124b16b4aaf07fffb14f5", + "0xe806b7ac21b2e7d80f0e4583dec620b2b3399f4c1adc82a246bc77c847024310", + "0xd588437c72ddaff5ad3a154915700ade8da4023421008956b1b3d1bf164705e4", + "0x2f12257a5c3c0097b274697e648df08c31a3f8cf0833e45e45fe76091c7e22da", + "0x88eb766b8fc471e455e50a183b728e6e7fd3b5a152440bad5d1c7f49e173dafb", + "0xeee35cb04632e48f5b4c94aae1a40c372eacf5ca773c9dfc2fb3378803a6fd2c", + "0xcf9d9bbdb883ac7d171f808738dc5ad4e632d91f45737be4de2f9a2605141f81", + "0x94ace01f0f2f127e2cb47dc05a491df26fff49f68cd4f382c12e7f332032bc09", + "0x8f261b4ff772d1c675fe16f0764ae644d198231daf66a600d56526c1288144bb", + "0x95062df2fc6e23916b7ec403eb5dfdfd8f0aff49ca15e0b743e5a3294552d619", + "0x9626d392247cabfdf89c0254dee12f5d82118b5449059b78b4fdf7ed62ffd688", + "0xc7b341b1a1464207bc1996364debec53e55a3212a2e18211a994d2c8e864e234", + "0xa5d247c7e7511015cf63aee2909dc9ea7bf56b9c2e15f1603b229dc7ed11a6b3", + "0x551f57a199b684836b3b5d6e6cea2c7cd58f830e870d1689936ceb93c652ad8b", + "0x0f0a17a40f9cafa38559a7b8a1b3848514f4b5dad4c4565f8915d04163f1b51a", + "0xd4ffba1b3fbb46554137cb0114feb898c9a1a689c0fcb4dbdea49a313c593aef", + "0xe72848f46d7f041226ed0cb38549fad946e14ca379fbba4cd52a3bc3d6b94c55", + "0xe34036fa757a07055a5ba89f39f90066237152468c6c3fd8e60484000dee38d7", + "0x0984ba7640b44fefc22e2b53463b91b6686b909d038a29039a6e5f84e25e1257", + "0x2fd4072edee29b9b611c38972835d3cc985befaeea149311fad80dd0a8bab088", + "0xc64954228a4067748447b768bdb34d5a434cfdfe01acf86a11d8a278ee7d7433", + "0x7b10e8fb7d81fe90362c7d3af0c153460ed3df92c1c50b6f9a993fc81e0f29a0", + "0x0c33f7aefb88bb9f6cb9061adcb5fc535b2a3841a6ad94b8a4adce1954bc6f25", + "0x21460cc4c2bd2d828027b9c04b047c06b1eaa83f47640639463cbcf603e4b7d9", + "0x9ea560bd5c0c6a0fa9cf2e0e14ddde39cca6c24b11e02b635bfd4ba7ec826e0f", + "0x47c9dc525e0e1f71e159ac75943a32d541596c9b479639e0e8f00a171a29057e", + "0x6f32319d8d958c89295e38c41c2a6106d9f6bd86ea19ee6cd3df34931a2701a6", + "0xf90b80919f035eaa3cd56d1c54f9c69e60ab2445a4995c7969a4826a28220398", + "0xb9ba6d207d1d7866e6205d540abc36bc3198b072aa5d52378a1148f6a61210c5", + "0x2f494b0db620ec08b2961a12d79585de2f6939bbe679a8ae1a580535437bb0e0", + "0x65ecc619942b4fc71b4477dc5929244161cffe2933c84ef8e2d5eb443394e0dd", + "0x12f573e148bbef501d4325a52b737580d413c8f999cc86cd0e497d9201a006e9", + "0x709c2a2f2276d712070a10d20baeb7d1acc602e6cd0d27438950707175f68faf", + "0x472db00ea142b38a076569205123d2ae53f42c1ff86d38100742039440fef89f", + "0x536a68e966effeda6883266a1f6f00b42dbd874d83956a3312ac30e430607bbf", + "0xfda5031fc6bef618ec55de146ed9834dac41afcb0d0521b34e141cbc0617d14f", + "0xae912c6ae86e69a59c61a3fb95c9a60b37c17c3ce2b6e9ae4930dea5fb5454a9", + "0x426c6889a4d6f3896c5209b662d9caa421adfa1f1770f33262807a3c89983364", + "0x6e72f8cb2b6cd35fb0c090f8be71b1ba790cf2163d0cc18dc0bf62fcb0658fdc", + "0x7259d06d38028ec544eeab2e264f2d4ff975f245c3697ea8e141ebd59733a2db", + "0x37729ab26688e0399334fa3cd2748818425b3fc41304fca56881658dee0b90c6", + "0xcbb02add11c0edd8105b440cd44a041b6f55a94712ed12ffeffd1817ae8a8044", + "0x156e069b3b63fb302693018293bcc0ab60b2ee2cc8aab43e1cca3774e0b743b4", + "0xb3a7a06a4f2c1034ef5a2fa5fde7554f239b0193093c74db11ebb5d9b1a18f03", + "0x323b6d191477aac18e4761baf8ff9ce70b1274a995aad02fd582f87285f8a0fe", + "0x7e4d202c5dc858e3a3c45a5f43b0804a4ff5ed53bce625ced7eb65db74e908fb", + "0x75446e5cc0142cf4b0f26f560995f257f87023312697b3574fe0e1f558bcda05", + "0xf53cfce4dcf415ea49360d84188b33a1b6e3c686c6e59f1a7385f68f3e160a7e", + "0x43ee5e27e64e778f31d641050b5c975fdd9788f2d5821bc8e3c188a91a86ba9d", + "0x6a3a73772d1ed7ebeb82eff2419e05583049939493e4ff396fbbce7e2012ef05", + "0xf976ee31f6b27e1e0f359e1f96b5900f34c49c89e81bc753456599d2e5f4a097", + "0x00ec8886d567bd489582441964bda82f3e297801ab0c5d3e58a3df29f9004a4d", + "0x9bd7ecb0d91d576640cdd3022ff0bfa64838f057e55cf35ca945d47f98d8d107", + "0x1868b1c9dcce55407f81879269ef1296c5eeff32ef4f7770bcddca4bf972df14", + "0x24856220dafd06f20fd0914d4468713654f6d9a8a8472a3cba537c6db45c1981", + "0xa05130241c7260630ce231a427081969d4428d33dcaeec08287e7aa80541384f", + "0x4812c23621b2399a68e81d9dd6fe59b0f0953b279104a69047d0df3678c8b628", + "0x4c00bb65a14a1b995a38afe285ff4594c51c8b10c137e73376da3f2660f00044", + "0x3cb2cc9dc9b1c997b8e73ee151de0cc23f5bc0d7dd27d0402b6d79e1b50ef441", + "0x25c0bda0d092dff16a5cb70ac082a0e3c17a42d74191c9c90d46deaf34c85ad5", + "0x8a75c8a0ff4aa70a0f1389f5ddeb0a1b7aca04b94af03e7c2f3986a6a9e8f8b4", + "0x9d9c63e3b449623e45de0542b1ee4d102204137a2ac36a25442f3797668058df", + "0x932b4ab5c339c9654cc1c5e343aef426dbfee3a98b7835efdba1bb583238aaec", + "0x8001e5592beaa70277723223f033b9f830a23d4dbc64fc42efbb80bfbd7e2a22", + "0x1b84fbbecdf3add7f514e0cda2b1c88b21a65d82da4264d06b332ab216179230", + "0x79cb6fe9cd675e096bc92d449093e78e59c6c4c813b550c25a76c2cdf125e582", + "0x4fad1261fa7d06941dc436c1d38188e3660b300dff7f2001a7efa7b8678bdaea", + "0xbf81d3c1b1e781a706c6acdaa23c12f5e900fc3f191d6edcd1636beb3d29a6b7", + "0x36cc017579e8daaefb5592bb0c5b2d2fb7df5afba9fbf02d0c750287c2353b78", + "0x0cf0b82b4a102f35a06f590481b72f93d570e929bc43fc188e829e01fdf0bf9c", + "0xc0b67d7c6100b042bd39d0b4747e854a0672fa2769dff0dfaea01e05621a368b", + "0xb8c49cfa2147f651bbd73f97f02b694a5cc3cf9fd79d47bf34857804206296f9", + "0xd3836371f2d0071e45176aa82ecb05b5185e06e79043f69fff184121380e1093", + "0xaf9e77ff0a9c1bdb16afd7c1d725263ad04394e4b73f013829e63da9600bb35b", + "0x43082e5b9b11362b6b5cef0c5614848ff4c8cc9dbbc7e2b179330b46e7b3652e", + "0x6cb6fd2e7bd5550dbe63b9875814764e64036a921be1e5413ab1355d771cffd1", + "0x1631a928685b0fe688899b105aefa54fe61e564a4c9d8dec99a34f5140e6655f", + "0x095addeb9c0d14bc7e18f547259a68ea3dc982e5256f4a97e3f627c3b2140be2", + "0x520f53d82a67e09c157f3480b4f504dde53d947b9e2238f814f5832f84b8eedf", + "0x433777fbf6cded05adad6e5877ce0ea3e34342af6f65042c6141b4f4201103ba", + "0x077878ad6fd501074b5c713905aa3caeda3237a1b58087e6275328d9482b0577", + "0x6037000d2014c601b14bab5bbf758098b300e68fd3d6f2a0d5e6ced1657cd6d0", + "0x481b8e11fe6ca5cdc881bb6c3d7a0d96e8cd2aca705f950ac542c089d7ca0cc8", + "0x2b070c54b2af6cea0e0ee76d37a92ab3f4e9e04f3b581f41ef2bd5d2631b8b87", + "0x01ead0aee81e4611b5ff7cd64037ec0039a05bf0d02b18b92da6acbf45d4e6b1", + "0xfdcd33327deab31927db501945c15a82f278f34a09112b2d7f74219e9a364555", + "0x0fbf377a65289b1decfc2fef4614b1e5b3404e0a0c9c7d0d147cd86bed55f23d", + "0x8cef4b3d09f838d4acb5e21f777fbd906358a2759d24b055756e9d154b177ab5", + "0xcced9e5d45e86423eddcdcae5fb2080622279ff6f08a0ee47012b33af58f820f", + "0xb1e6b5dceef79d8ebd0b84a8990f724fd645be2434a0a8339e78fe61c2ad3186", + "0x24a11c3547f5fd5e5eabda12369f90b8f5c8ddb82568631b6e704c2ab5c94ec4", + "0xd6cc197005e41f553308ebed885a4df650a2022d0d40d25f37bfc74a94e5b04f", + "0xcac28ad9ef5e3f9b0d2184fb3427dad0838122a44538bb1e0ad15baf08ed7312", + "0x8070860a9337d8e6e016e0ba5953968bf410100bcfe5e567d7562e74b95b5d0d", + "0x8ab5cf8538537e591e95fb1dcb9522067ab5ac783bfd622e6c9bb131d3288ea0", + "0x345a12de03af922ae9e6651cdd4c4249f75bc2aef1f1651692dee6d27a490813", + "0xe9cbfb97fea7afed66cb3551d9b5f6ba697a4476a5dcb3ecf25bf9a41e54bd85", + "0x4028a3855c3b656c1de109e250412d9596cb6fc4aed22b8bfca6d2a60b1454c3", + "0x85591c0037f549f6d807c91b929fb0290c1b53f23e9305bbf4feed86d5483cf7", + "0xe3178cd8d8b7d9c71d9614744a937add2ae6c21f6eddf508fdec243c6408b647", + "0xcf40b5e2f93922022aaba8558b17b193c50f6440359826dc78b58e9b9e34074f", + "0xaa30846598de0f132d8c18084859e6c67189f9489a2b8019936a151e7d0812d5", + "0xb908ee8113c1e60abe60fcd0d7fedfef07ff0efa562673d0ab86f6399812a8cb", + "0x8f9d9102f709fc1b4308b677e515173a1db857b4989b1de2961b801aa8b39db2", + "0xd74e36d71447b437a4a4405dda388a9779347fe41152b7c5515e02edb567b5ae", + "0x5aca44d35187500d73b544e71ea8a12100cf011c219fd8b83e44b4792204edd8", + "0x7196cd91ee48f598c11527924c83431dec39ed7cd67a225b64a9d04ad23211b0", + "0x52584327a0b33be95ebc7040c0dd9b60d2bd0d42d1247b8d2ee06b0d6aae9f58", + "0xe2517f4a4218e9741b501cd6fdbc7e2080cc8827bea231d829d1717d24ce4e3c", + "0xc94771be6c7b5e858823a03e620670cc604cdba8092da13e429c76c2077eb2af", + "0x3f7f556817b418fccb808f7ede824ff17b119e7fb02ec1a4239a71835af5ac5b", + "0xd611cd2fcdea70eafce698fe405f361ca95b67d5631a9930d858f4a7cca46358", + "0x5f2aa6ad1fed0ce4db64bff6de7bfa68e060d357ddf20414fe5f10b4211bcf7c", + "0xe8b5d5fae7903602ab3699ff27f159367e2fbd8fbdb4f45e7b1628b563081940", + "0x31cef735663de763db98bbb0846d5a1127adf45ce41837aa77dd5e4008718711", + "0x58f0b43df5b6c2527dc3e22f2f76cdf7817e23d7c3b9a9732fb91e6da9a537bc", + "0xd13734d21521985e4c6c14bcdc34139efccf1f0a9ab92a72e0b9e639321dce70", + "0x99b982d744b14279defa1771bb358ab55f4f3730a8feed9e14023b39c44f2777", + "0x827078f5ddff2088e6d16039c439492140337ea661cb361fe87e0bb7fc785bc2", + "0xb1f7f5fcb807c343ebc587314a28ac008f849c24753383c3e40c9a12826c9f5c", + "0xd60f786c664eadca5ba1af303f8d8e88d781ec3611b9f781cffd5b17610c19b0", + "0xc514f1487e061262e2be76dd593300b8402df6812700c41a2611ff5aeeddfe45", + "0xac6350441c04277a76c019215cbec0fdab8f6e46087704ef0b75cad0356dfc32", + "0x724a5ff7c13fe6d21249b47f47082797b2470159b298ea281f9616d6b5c5269e", + "0x70dba710ff65ecb7c9fef28b366f5b175e12a63bd1f7530ec18da36027033497", + "0x014f4aad56ae3ececae45610e6d28475e588fd39897127d20675c1ce18479939", + "0xdeffd38ba5e4e685603ea1da27571d48830018be17755ef7c08db7f6dae63647", + "0x1e6e324967609029e28e768443d11cd5d99ca713a88c9ff47144d0b16b9cefc1", + "0xb2a2a5d5583ba070ab2b8adc6f5eca48b621b5244433a5e491784ccdac2e64c8", + "0xdbb937edd70b36b566e397fa369a5a3a0b45e606ed012277c64234eff00f2157", + "0xf043662cdf2a84618401c619fd8aea26a54519add9f72e43a520fc8129c02000", + "0x9b84dae2d1a0d7e23073c558e13e16ddf3a28daab3569c89271e0f780f134be2", + "0x93c7258e9e78238eec47497c842a643b339ef9ce4f236ac2c0541872a427a1be", + "0x8a8fea29216df1683fedc14a7a066226f9299d1be50021d3d2aa4c0585b29f47", + "0x85bde8bc039cd1820bc1b1262545bbefc07b03de47090008becd1417ad3b997c", + "0xa7758356e4555d213a19f5c343de9cbb986509aade6d8237baf1fc6e07084b9c", + "0x546bb118d2a1176ffc967f90bc342edbab4350f28294ad6aa29eec2b0c9159ef", + "0xcb50bf5a5a25b95962b6caf51b5e23fe60f6449f69b4df5d6b6d7fda2463d5bc", + "0x1730541314d8595b13f01281189321299fc3d2e9d0b9aa354099d6d83538570a", + "0x5b57218719bb9816f4341ee1938263fe92cb95e798193cc2b24fdc3836abac02", + "0xe0860d86c780d3bd7375ef6a0d75eaced9fbd90283f8ca8335205ac3d3a3dbfc", + "0xcd65eab452ceadb388b945eab3342dee7542c76bc912dd738e86bfeea1588f96", + "0xc15efc0c25c4c019937ad27026225024ee6992780b9ba02d3c70101a73b354a1", + "0x30e8665a5ac3f3eb1b9c2e67d61dc2dce761e4123ed801c1a6f207aa3828804f", + "0x6c3b5d4f836b7d349a089280c1f4488de60461c7c1a7a5fb3ddcc69c1366195a", + "0xdca4d348f2b9806cef16e320e0b21a539769746679c1a45a6145f2298db496df", + "0xe8fcbceae567fde12d871fe54233ece0d74ba8508fbfbafac0f154806a9462aa", + "0xd79328e9ca262b6a91652efb67dac1fa5e8c3282dbcda58d4b93b8874d226966", + "0xe0fd3af4b67510c68e8968a5e25e741e1ef71c9347e18b8de6139f918a62f6c4", + "0x70731ec895bdb4914a76b97ddda78a8805a39a56987aefe32556b93e2c085d97", + "0xb387f307e22829ce20c5d7906037a5bc202950197bdd75ba59999c2a09778864", + "0xde1ec63948e3c4aaa005630545cf73bf9d20722a1c35b8176cf44d80f4cb7f0f", + "0xf9156bb506ad9a12b3b2357450c443572a3e3399e97f68cc0166ea22155c9277", + "0x3d5c1ac62e043661edf67446ac9f96b1c887d07ebcffc2faeb317b5c3ab596e8", + "0x70e9f96a6d21fa71ec310b99db848e5dde82ac9410ce8c6d24af115421527223", + "0x366fa3d63bfdfd2fc10ce44522f36ca6b8f815629bd36a26c0a5fcd6f95fc5f1", + "0x34b6b13187d684972edbc097949de7ed4f7ad2658f9889e1798e955845f0de36", + "0x1ebf9da97a23393f6dc5cda5c54718f273eda8ac6d1977981a0e1570863d9833", + "0xcf8888cc905df1ee1127f59c8ea7f9243c4688daba7890908949b027f4af92e1", + "0xea4ba26d5fdff1daaa42625fd88aabf7f91cd400829268b9beee5fc09875c630", + "0x639faea36eb1a652b024df696454c856be53c3667e88c7af5299c050c1092bf2", + "0x1e67283656def3ee933332600071fde44127ea3caa9c42f992ed16e33d1122c3", + "0xa4f53ce6159cae14ebc60a69e9c446a2abdb4f4f5cded75b1c5814a84c487528", + "0xf2840725ecbeb6e7396551fe034d21e75a5d34b4cbf8b3b18dc5ffa06a3e2d85", + "0xed7396b51a1b0d93b2288a4bf60ad49d236bc14b0cfeb40dbbdb6e9682d3fcff", + "0x9de490ca8067c84f922547ab496e57b3e1fc4685b744de22f1cac7dff687b930", + "0x3c3f7c57fa9ef833accca168540766407bbdd2c418f13adac42838f205199462", + "0x14257d1a35fa99b3cdab74c8445bed9bbfd25d1604e1b9123fb5c5bf88cb3a29", + "0xac74953d33cdefa9037a415336672144c53310ff50f75d865272ead5e0460799", + "0xa94b857f4dab303c1d4a5213c7bb8b91a441ee8279e69fa92057718f3aa40a4a", + "0xe7c67bb2e440f1062f95e28f0924d0b29bd789103521cc13d13a95673cc49179", + "0xe90ea613252541d3c5237a27d4d23780b579cfda48c057b7304ac14751166031", + "0xd85a4fd06114870b3fe19cba9924405de1e14e026372e84b24b4ab39e7879545", + "0x7d65651c6e789a3b6113f589f696ac6595f279bddba74a17e955ae6ff93a1846", + "0x5e44df731c9b0905ccc33ed49669b78834d065fe3fedcbd0fbb7df95f706c51c", + "0xc90d3dc4bff702b9f17930d27b039bfcb1b7879076bd82a5650177252a526dd0", + "0xb5d0f4ea7136a5f10e47f6a802b46ba0c7dbcd4ee10b4be65ccd55fd4c940bdf", + "0x4f7647e2529b477aded041ed2f4c8e01d5219839950aca43723993c2432105de", + "0xddf89de514a09c21918af718834060348ad0bfd3b86e0953c247834634eb841b", + "0x325b15b05b3c863822647b25ddb970cf9cb52ecd32cf58e6c5e8cecb1beb9c89", + "0x3cae2ef569b1e74770ed80bc31da2addeeadd59d8605eac8edf3dad0fa9b0c37", + "0xd7409a715ae5f091fad14187121bad8263caa2f60ea0d0bd7c524065defb564b", + "0x5cefbb199b507e3b64008e5d639cac8f623e9ace1292fca190bed4b7aa214899", + "0x2c2919f07eecf553b473f98d06171449838bb03c0a468d8a7cfd8062a574df1a", + "0x5c122d8416b78e0e7328881efaa7fcf61be6851a5b7572ec5c341693fcb9c734", + "0xbb81898e64769f0a6f1c20a2472a5128e969f737d1cba5be885372453ec18d1d", + "0xbe203e6f7c0c86ba994fde55d0daae0f066814938debc3b5a44884dda70e3ac3", + "0x73c7842f2480e3d742aed1a1b7682ca1f322d4d2555cb7fa402313024c2a13f9", + "0x5b95cde26a2c2be298a03252ce36514dfd3c9e84f5c5ffb75a050bb5752b6247", + "0x9c7cfa9294869c1c42db3cab3bfb737696b8f81500742bfeeaf29145e2b5c79c", + "0x6cffe595d85a32ad1656c81c87d476e6e7f602609fac052a0a3e3a951d11eafc", + "0xe2ab30bf8127106a4507034cf6b3589ea3dd19bb10c765434fd3f3f7d75c1a4f", + "0x01d7bfcc2d4c6fccf5e0599f9985af838cdc0281c9c8cdd7006b3b0abc775cbe", + "0x004114dfe63995fd66e6932c62cd7b3f40108e5e2f6916d19dc436cf016392d5", + "0x068c036ea74e85ae8d8897589a8dc775c8516e38bd619ed584ffd51021393fbf", + "0x682f4444c85c46d28f5858a91874e0c903e97def4e2a4302ca90ab69b54b4f49", + "0x3fda79ec159c2878e9ce65c575157daaa9561f17a14a0003d95c0c4264985707", + "0xb41874256b5cd3ef80af1536a45a8016cbade06b4a06b1dc0942c27124d934b2", + "0x0eac150f30020a7651a006324da1ae240d4fe623f077c061a954122b0e17b0a9", + "0x0b174907572651a2453a14e0326e7ba836781dbd939c2d75db84d9b481391824", + "0x082beb1974f7201be32469b9df42d9c30a520f4dfa696fcd991ef20367cb6eb3", + "0xf3c3ebe6040e1ce5c5ad1f6e08965ef387adb6633581ce3fdd1858f1da4547c9", + "0x6ba341211e75ea7346853a3f63ad5502f83aeefeac98a479aae546a70141af99", + "0x3962cc5bb73ab7f48d98bf65f3f7f41a8f3c52b4d7d2f12a0a89cd876f875bcf", + "0x5b49809641f72f5c96bba6b27e0331ce7fc7dd3ef18a4463c93d1f685b7a29b9", + "0xd2b2e8eec102c4b68d94d8bacf71755386bc3008d15d6090772a4739eb763300", + "0x704bf1701cee4f631f4de0e330873b1621490faad46203fab288cbd0892da567", + "0x2f7d29943c2b3ed9f59a66ad175d298f1e4761218e3fc52b9a67b4ca7107e93e", + "0x2b370002b007d4df272104b77c1224c24eae67de3e12aa599968b190e8d58c19", + "0x1f25435148cd815f4549de1f21ec227d42f360d207aa2f7de5466c4d28afdd0f", + "0x86d745be32470f409b5d77f92f2412aee084fc523a7ff7e57b53f39b11cba2b6", + "0x86d57512687518e3db56834f819bed57ca4f2e3845ef6affb15f29d1e166c333", + "0x9ec0e54aa6361293f68c14b7ee9dd32abc52d9649522b0d62637ac25d3a978f5", + "0xc2dcddcdd616160a196f1336e9f11c7685c5eaa4d3f5ca7c35d7eb14199d21c4", + "0x03a14db3cd22bffc91ce24e510421d60431db71bd68b8b040c89f85f7664967f", + "0x3cfa17c8017ee8692c5f440e6ff825b2bbfbf18d01466234bf69ec85c3c793e4", + "0xeb12362e925a0b082268e0e006165720dfa72ec2628dcddb6cbee4a4a0ab7bcd", + "0xb8c68067329a16ccc14fa3a5bb373d8281c79a20e1a15f74dab053efb881d13b", + "0x282be7cff399ee51b3b8ba7d9ce73daf0427cb11151b9a81ee0f6efd837c6f6a", + "0x357989e62c038a11c75120f990adee58fcba6e7fd49cde265296b2ee0c7f6db4", + "0x3ca8e01da313e17c3a089b8b99ee118d10140a497aca58d62c25452f1361f0c0", + "0x9778186733b0e642156d6af17ffd8161608a2ad791cef0dc5d6f31e5ed4ccee1", + "0xc309f7651776d4510a9696c89aa82e8720ebb2c41c208e7ba8ccdf1d26dcfea6", + "0xbe30023b89befe4495b15daf4578f415e8cf25087428bb25b1af06b43b04b114", + "0xe7246483ab7e0afa2a6ebe69819744cbdbc588a5294c1c59cf04232782d89c1f", + "0x54e18aa712987567ad36173ccaf070b127277ad6e9db2bfd1831b7868f56c660", + "0xe5c6a4c0f07bcf3dab39def282e3af9f7dce84a7b2bc71c9bc3bcaf35bc6bdea", + "0x5d78d891bdbb232e7d90370b5108ee03ceb0c5abbd5bc1c49c53431a94fa2309", + "0x91f3efceb05e5c6114ce0fa2477d8e2a6d9979ab1d3cef4d964d7d804399ac50", + "0x29830ce8ede37d875e7203bfca97b104b002aa474fa9aa9fccc11b2baf665f83", + "0x93a0646400cf92d5e7490638b12408ee9fd7696f15005287d23238ee5fdba9bd", + "0x47273e8e24cd886a25e278d327bc0b07e4c3a6b27634fc17705f46a019ec042e", + "0x3469aeb8bb2312fba8a530a002d75b75bce0a4b0e7f48d3e92d595dbec818594", + "0xfa8abfdb2535d9f04933e924e967d97c248b62900ee645fc991a47d5ecde87d0", + "0xe9fc29b24fa7b2a6cff23170d96faa84aba582f68792dba4962e7fb53922c568", + "0x506d80c18b5cd845e0277be32d0553130549a976f781c315c674545b1087516e", + "0x676bec126c59b4f69ddb2ac8141d9e90b78a2aa1b5e55e6458cd479fc7f98a10", + "0x4a99d2f7be333ced3b6faa2aaf15f792e00717da5cf15ba2e9b5b7dc02bb1bc9", + "0x776f5be74f05d1200273ea3c9b1919637fc911c76d1a9c3e1e3accbb9ffe6e37", + "0x09b9f219a053c0c3c56581e32ac15fc6bfb4fe69208a5291dd4860cfee263d19", + "0x65c9e06136563c4648b76cb1e7c5d46bb7501773825a10c610f2b63bfd5ddbdc", + "0x2e31a4c4d6670c2155b3ba877cbc6f086c18059b2903ebfcf2cbeb6f73e67bd9", + "0xdeeccdd2dbb206be5fe2bd4e122d6cfa556d00ca0021384138dd914fa3aa2413", + "0x0c24527744343d79639a382412ad22e5ef2e610151e1a19f09f725dfce287ed4", + "0x4fdcebad349c83d27457ec443a5103b375f26b6da958227ff00916cb900643b0", + "0x4b06063a48575a6f89ae7fb8deeb316c30e6ecd080898c47f24d9e7d4f6db960", + "0x463b0fa1bb74f1473673a2760a7e447def169426f9f7cb57ae4c6d417f58d829", + "0x01050ce1aeb140cc812f24c6629f9a171ddf4891b9150b43312fb052ecb29de1", + "0xa9e4bffd5ca3834b5a80dd84bad6ba4dd71138f02cd386668aa8b73f437f3e0d", + "0x379e501e6acdd0f94195bc851c50e7674e103ce8563bc61d7b0e6ccdadc18def", + "0x8d93115aaaa77767f70287e025a445cf6a4c7f455a67615f38c42e827c95912b", + "0xde2d4d8337849ad10a32b1731a0c281eedad191a09b26764568e7cd9769200df", + "0x575de523f7dde0e52b68c15646d22a31e245a037d1218edf86e295fba9b201bc", + "0xa545dd5a5e5dca568a5a28bd387417bf3743e184189106670b03b423b9e5bb08", + "0x044d13ecdf9cd6989d3e5a1d8354d4f5a7d29439a5da0c57505496fee7b6d054", + "0x4d99efa30d95ba2f0002565ccdc0ade2bc3f21d3153c638fe8ad9977f1da8360", + "0xc72982c95de4754f8b0ac62113a71af4c760c3c63f18d230f1fdbbe3c0b379c9", + "0x7a2dc8e509b0901646afbc1a6f9b5b27ff69f2fdaf4377ba027be555acd128ea", + "0xa3656ace4d66ddbf55477ce61954f2e1f165f570b5c7d028d1653e9f879cd080", + "0x47e4e4bbbc704f65e3979494487b0dd51cc56a928f26f97d6e29d76db80ac14c", + "0x5cec964b6d806da75f96c67c1db66d7c539593c476c69a2207be25934443c82f", + "0x685e812268ffe51415ef5e540bd4d2d65c2f34977ffbd54be14c895e4f004abe", + "0x991b2344ae224901f5ef89be9ed8313ad2c217e3727ed8d24f3a35fb71df3982", + "0x1293f5ce59c36d3189ac40e05bd8c0fb4b69008d8d457b224df1ef1e0285b553", + "0x3d41f27e644e2f7de5173dfe7004e32d6dbc8cb56871f578c3b2b943210a4c47", + "0x2decc2a4e91de0ae9a5584cfb03f6a7a4e0a867e397dc74df8f185bf241cbd96", + "0x0aab7f05bcd3b3633184b45c81dffd70b3f1b1b23f28d46747ecaf54fde443b4", + "0x8bbf3aa92fb9ebba36c5a2756dd394adf505cb753f8d3809393e1d967f78e075", + "0x13544a2979e57f73bebdc7cd1b2a1c9cf8911b8f24868aa1e775c8c53d0e2572", + "0xa7497c9f04590c706fe0a3909bd4af5bccc7ac31d7162b2b856d3a36bccfcef8", + "0xb80de8392864c859aa8e9ca078c258a6992bd848de129350ba29548db6aa4afb", + "0xf334d02277f55288c189e6ce79942ced25ffb9ea7bd5aa5ae562a985eca6e57c", + "0x83a563681180ecc7a1fbc6e47e0ba03f5004a87167fdd451d559a573df30533e", + "0xa648f1462985ba8ff73c7aa4d19153843e6a9a454d976533b08f7a14d2fa8902", + "0xede4ba72831451bfc8651419aedc62e221bd8acfd8d4ebe426d5b84d862d3b71", + "0x2ab8f2dc9b620b637aa27f9303068abfba56bb3438905d29c9a6faba4ad014c2", + "0x225e5b7232c6edb127a71ea313501e49dd86f4df0a037b9c97dd5fffa8c08cd7", + "0x85606456efed98380428d075ac4791140c9595b83707a397b274805c8fdac4ba", + "0xe298a5939a283d03311d1a19f83805f63c83efd2d7affa7586be8868284be900", + "0xfedc0db97df763328cd9a8c8bf1de73c420ca33dc3391acd6e4e847eda793d7f", + "0xbefdc3c7e7ad41deb07ec2821d0b84893440f797fb1603863e274368008b8e74", + "0xba3b21ae193db8215fa341504fc5ca46b58df994c473340bbee3f3fe90d72497", + "0xc45fc6625b0f784ae2039747aa93495b05243c00dc5c2bf46dc372c62beccf4d", + "0x32d182e51018fd1e19b576670ec68d59810c4bbfd406e2bd162e1f17a0555f67", + "0xa8886b1a9d7bba27219fe7f563ac0b592b82a1411392ea71a4a5bb288a98d6a8", + "0x396bac50aadd2dfc853c144091324a12ab8661590fbc738d3cab77910aa2d2a2", + "0x50e35af52bf6eac228c5fbf6fe5dec85989b76f44811099f2e8f4950e4ab86e2", + "0x9ba2aebd73945b6dcb9f5171155c0fff29db8cf40baf83b1689a7ad1004912f4", + "0xfb1cb1ff78859e3d5f0db0656821e12b8d247ab3896e6670426dce2055f1ff8b", + "0x230a6f6567f066e76413b72e7650f7cba9315090abc1bc7f93b861d85aaf0c68", + "0x4dbcac91377ca858927a01f5a5e8659b4e718ceca20d4962c43fc1688c4d7574", + "0xb13061dfac0e8f22dba518fd46ea95024cb97ef825c970cd5e452ccb3d7fc6df", + "0xc5af27a85235fd0e1da29b5afe6955d72fc2245c5709a0f29bebcc7c49eb4a0f", + "0x7937707d20bed2c7b68dcae39ebcd93b84bca9f471250e20f86f8ba58bb10fcd", + "0xe1398b71406488244a0c205db9c793be090349bafd87fb147c1aafb9d7d7deaf", + "0xb383706e1aaf7149b1ac3d258f6628e8e6d40be0dc096647b4bb82a08585b707", + "0x2c07639c073fd57cd719e5c67371e5c8db30f34855ffe0d985070b4b36e27cdd", + "0x7b264ea13f78fdba57d1097be39b6b2dbc614ae36cfea1f99d44b9966b3db035", + "0x04d942f60d32a80d93d12fb7c8ef95439e0da5c8358df2c01e7547596461ad79", + "0x71c93b0ec1e403906ce7e5a38d168b72b14cbb7cd0e832c2a7e73f485c7d6567", + "0xf7060c7f697a68824bbc178e02dcd6b12ca204da9bbf2a17b69ca858e2ea9574", + "0xb3b616f183145bbc77d8e3610504189e00c0aac3e15975e4e01f1b2b25c5b5b8", + "0x137f77c2fa4e911b6915c5a84588bfe78bf54ce39d09ab07e495da9283966d19", + "0x5949274e5465952855c28d70a4089644200927b54faa67d5aebbc4eb2b891aa8", + "0x1c695bcec5602b15de8099c550a3b738aba98acc46377cff7a5e58bd7f402ce1", + "0x8d1ffe39767f285d7f164018cf2fa4ec6509194c086c33af7ec8132e3572fc9a", + "0x31331d50f79ace5444f242b279be905e076d675fe4d4e1d32de728e2654a08a3", + "0xce9c3e8fb9a75e284c81925c6ef742c4f34e6f0bef11578a61be5325692a3a60", + "0xa4cac76b0729c42927d1ffb0c870983830ea66636e9abc6138b943301c59b96e", + "0xbcc505e608198cc3546899012cb59a3da60839c9060d2952f8ecc178be4bfd82", + "0x1b5ab87cc34a38f4be26c5e3e05903538e8e3af350f6e2e1258b0cf344ad9f39", + "0x85849c1cadc5d3bb555b88b1e5720110a1d4f7b79f634427a1f8d7e88c2e043c", + "0xee63ee939a6dbc6678415a1af9969526083bbb754a8c55e97cdefbd2f02900dd", + "0x50c63ebc1248164b057854b8ab8bdee0510a97f75e864e1d83feaf59541a64bd", + "0x58daea24885faf1556b3111c06351fa506b40b9f1ed365633a2246165abf3819", + "0x0357ff6bf4ef1b1bab206c3c3efe770c6493cd85d0540fa29492428d0a878c6d", + "0x52963cc6bf51a64c1f8ccc21c520ed95d5ecd0e43a86b85defd7b0113082e9d5", + "0x5cb8353b62e27e59824ee43a4bbdd384a2af41b52f9ea5444a1a180482ae7856", + "0x2815152239935641536e549578cd0d33c74a377ba350a36ef04b038e5fc49142", + "0xe6df1f1b9949e17e0a683b6fb7ec9ede2b49ca3d479202226ab4180445f86d51", + "0x3af2498e3ae79447c4b6b3f025a37c790622e2979462dee5913fda778882e5dd", + "0xd498a21e50c930d1f0fe0afa65c6f977ab8da037175f34f4478e52f4c1631d01", + "0x12478043148cd0413f56918565cc2fb0fb9802dab776f0a055093ee8ac131da3", + "0x9acd35608a37ac8e309e884b88609957ed24ffcb5816477788e08a874e6c5a61", + "0x53ecc517c7158fb6e99863c54795107258b61399279ecf74f443d49533a104b5", + "0xc74f9359d1b15de475fdeb56497a5745a93c741e5f2c370656b2e7c269c06511", + "0x8afdda4ce115a19309597eee883cfd257182db46070c7cb1f24955d9c872c8f7", + "0xc4036bef9a9e692ebe72c946161b3ce5c588f4421b7d6555b5d65f3311a5b0fb", + "0x4b64a608ae22b5a655cba7ef78624eb69f9f8e2b2f7aad8c04cc6ee95386e9ec", + "0x4b5506aa505815e519b5008fa8d23488b642a1f347f6cdbf53975636a677a6df", + "0xc251b21563070f1b3895bb4512bdac4395440217c5ce01fd85e89399dad72b53", + "0x07a7bc11d48537654d24eddee78d35e4510f22b755f1f36c3b81e98087a1ce68", + "0x66a0e9bf542363d8660cf7817ccfa3f4262e4817fba45d2871d0154b6fa7e969", + "0xb2493d6e033e1c29f62a409342beb82f692e565638736fd088d80acf7666b9ca", + "0x4c55f2a4ceb60544682cded4ae8b23bf217ce7d87ae90abeba156d9b1005f397", + "0x32b3cd5438edac8902527ac353356e99effb1dde5209fbe1015673778f7c5685", + "0x4066c6ad2c7170b434bbf3e7ca0fd678803351c3dcf1c56e84bd6c14ac2f7712", + "0xe74fa1fa353cfe643ad94f6a609726fd3c4b06f9dd7503431f84b13bfd87b06a", + "0xc46c3e5bc3c3cbc604513909999f1523d704578cf5f025a33f1a5273ff6cb81b", + "0x261b489751092cbd70d6d3010b5c5dd68c9041063c3f998b742e81060107e17e", + "0x37992c7e208c0b09309ece681e02e957f6310c6f42401702b31f752646fe738b", + "0x2b09e6bae0a34cc6c8c83e97c3369bc847ef6410551494af91a3a39929e7d949", + "0xebc85167d3a2fb3ecdc5b07d78b6ba3a0d8294901f75d687087449ed78b305a1", + "0x8fc0dda2085f4e515491cf0d5a525f10d50c58a0a86a58954b07264425bf1e16", + "0x5acaad0dd003649ef9705e73232b4f9598c3fa14cbfafa1691d0f987639b914d", + "0x41cb16b9f5120095aacbde94f52b635a1ea9f347af8f4092660e84a1b87f8535", + "0xa5f2fb17e7fb322069fe66bf093b99f54ffd9949fa4cc983d2266013d2dac2ec", + "0x014582ecf0cc003d21b02662531b8c0422d499d8b74069533ee24b9774c1b7ff", + "0xda9554b8c2b3fde14390f91282a91a9eded5473cf58dd2f5a6e6168cb4d24d3e", + "0x55fb7a99e9e6e3d9fafd8c9f65dbfe821598f2b5a63435204c063cb4477b1d2e", + "0xe54e3c51b6eea19c23875beccb7e18094e4db26f3c94431df1dec26e6db98773", + "0xa7c04b495735a1a829c64f06b94c486c0880a7c54461defb31a420fe0104e1fd", + "0xc7299bcf0202163a946ddd5d8ceaa209a1d81e28a27e5f8fc660c00505df769c", + "0x2526f9fcfb45966a26370e08b26cbe29fd5aeb568b0f945399a6ace1778ebb57", + "0x59b3d302dbf5e3919550c0c1b75bf111d513f2d0d948ca8cab6c44fc38459b3a", + "0xa73fc3b85209e722b88374b2ef3fa3df240ef81c9f9e0d4e7e422ddd124a5ae5", + "0x0dfe2812db18ec7836f8d2227e35263eb98fd2046f597c203f2b499b538a308b", + "0x1f7c6caf872ae90f4cbd92c7adc49ee2ddce61baaff37186111ba7d5347bb4bf", + "0xd67aa89ad3f03b9d801d3f1cb1ef58a5d9f6b8e4cd9d6fe9b862b697f60951d5", + "0x9d760e7ea703028be2d197a0ce28d4057bd8fd7638781e9846cf5d5886ef6611", + "0xe9bfd8ff1dfb81f4f5e5c3a3f821384f98d7c6b753ad356952fd10527e08ced6", + "0x95b6333df70dee92ff0d880239c2ec7a4016c6192391c08e797fe24e06bfcd0a", + "0x56651120494e23767700b82c6718a9c1abe469da49c38937582d08220330cee2", + "0x70d3bae96dfe1a093bf9233d9f8f4c149fe4079c5f40087dd49c6e524cdd96d5", + "0xd29445a1ef099b0ce227c88efef59677abe47763149e034c3dc96d999b66cad1", + "0x7e2fc31ca7a02f965757f118797ae5093cc95a89fabac7e25a22193f2346ca57", + "0x3b7ceebb659eacad955fe0e95a6f141eb4f59f4fa70e52da5c85d7a9467b9298", + "0xdabfe5efdd2d7a44022fac35b13c8acc8c3c1d69ff360d45d997887feedffa93", + "0xc883f0d5c38f40861f9466fdc84170f7605e9af5ea4d6f9aa5088c6c9e482b7e", + "0xd5b14197d738e2635f7294eb8993b01db1ec02de38a545fae881a3f11f3917a6", + "0x5d2b9e3f7a490660bc2592cdd4e04fc9f5e32de1de4c9a8c223b177627708bf6", + "0x2e94c911c88a1cd80e94acfc9f27bb5675a6ca79dab6f70f38a4df99f84f7bbe", + "0x23fbe80ce230e0cbf881279ff259642d6ddb579f0711c5f66e93db3896ebd835", + "0xf1eab3ddc0e2c231cc78d123e20f4195808a88f79c21b9ec2149e3ffb9b1d5cc", + "0x5156b02d5fb9cc38a14e3b4cef86fd99d01db773f681404889e6f7b76a6b2d51", + "0x4bef16dfae5442b8d2451abc13f610acb565fde8400ab2ce52c44f54f68308ad", + "0xa726272620270e5649309798d90fc52ab80b779fa03fe639fc8ef14256d5b1ee", + "0x7f327dd9c23774439a2c080274d3111e0487e1e9c848a9e11c14b2e5a9b307ed", + "0x711fde0a0f1474e0ababf802d8cc8da401d1bc4f836868f117f8ad3756179296", + "0xedb4b7af3699fa441ab53a6afaf380b5760fb86c6b5a0f2d73075fd9da23c8ae", + "0xd7062907f805b2b54e9573104b7248cda283ff1af3d86b7d77b4f9a94d420200", + "0x540b2ade8a4d3571094a14e7e337cb4ff66a86e3cc9fa5da85e93c21edfb69bc", + "0x3c06c59332db001ac1cc72e9b07adfe31155df74c920d7a897592fba0d265a48", + "0xe24179dbc1457c23d05b307e0b42c1ab276db666e49b48cd3e1b3dc82e285de3", + "0x70675363d1a4a6db8b803e3876b171c4ad70b25a56790ac7e4cf011ded4c9c9d", + "0x80dc30723f933aee8e126815fbc226186c07d724cb13c60bdd55cb470f159c4c", + "0x9be135832d600074ed784053d80ad3fdefde87db55088a545a1f8403429d86f0", + "0xac742c9ddd3e59c3467473ede8a794a8b5d1c8299a471c7510cca0b11259ffec", + "0x3089d8ef215e1cf33020d6f2dd005c96d9e7c8bacd2e272c788b79e3fe016caf", + "0x7b22b3b82634041abaa917ce6ac8738e1ad5ada1038bd1a583c84f2765640e0b", + "0x5812d6270239d7566288bdf58df80a2f692731062d3a0aca56d3df972616b553", + "0x0cbac8f96a15a1f57b3ea657e5888598f7350466f40fd46735f7a8229ae7c528", + "0xac6d9f1c216f28da4b97cf2f78f4a7d6ab38636e57fd9a4db71bff191a8007e4", + "0x8dace71e1c1a12a57dbb4794cc92d3e6641201ee75a8304b28b670719cd9a179", + "0x03d497bdc46d7189b30bdcea32a7d93ae17aba1851da4b5b7baa241f0348649c", + "0x9b2316358a104fd1a93cbc388c1419b1db9043aff711d20510f012bd135a1309", + "0x88d613d910c664cee5d50fe1733340853900df4000225698ce32816f457c30b6", + "0xcd9d22a2cb07552bf921cddcb89d879e49ac840a5cbca91da3324427d7d2b80d", + "0xe7d213479605f340cf3714234eeebbcdb63805c5e9479dc56d4a4b2733997bfa", + "0xd899fb4bf3a918a9cfd46d23152fb1d5e54f97b86bf270ffe28e6e55e924e391", + "0x14a971dc6aed1e7dfd4dc3ba613548b8966495628182ce99c4fde9124ccd04af", + "0x89800cc5cfd0ecfb45bbd253dad288617123b3690098e41b38c0d51cfc10234c", + "0xedfe6f669b7b9dce540683400260000ee191c3481577aac6efc163afd7af6154", + "0x70b50725e51c7a5fd4818be7286bd1cc9b15ec2ed4ab6c1bf7e7203c4fa8f25e", + "0x22d02fe95c6f959f72ef4c96329dfb31be8ddce701e0c3ecfc8398119bedf656", + "0xd7877a10f7f883975c5498cfcb07f044400a09d906cb94c8cd29f7a4b93e4b5d", + "0x2e47d9590efa111e19419df7cec6b157f4e06dbea4e64108b7101017bd0cbec0", + "0xbbaf38881063dfcece265083468830bebdbdbb833a57bd7844044ea0c57d1e44", + "0x9269c959dfb4540e3d6c815aa0135b945acb7f50b38fff49f6e34425477ef553", + "0xab47e57f72ee8c8d8857247f84d3419edf43fdf6470c9ab070d8733cd8ad617a", + "0x2be450e3b77d2d3377218412be18390e984fefa2df07d02edc07ebb2d64a9312", + "0x6cc64bc8709eb51b5321b25453e77f871f364a8b277ffe51afde4b8c7a181338", + "0xda70fdeebaa9502e8d0af2350824ee0807e31cdd55ce4195f32a639f47f399cc", + "0x2dac4b30d219640aa01a2d7c69528c8d31636711c915827a64a9219524f2885d", + "0x50932f0dbacb5af5785065dae19245148270f1d0d3515b8d7e191c5702047b6a", + "0xd919cd9f3f6bf7ff66340bab7c562bf53eb969b3e00fc950d1d3b0d9d815e351", + "0x76a276f09fc452ac94cac15d5226ccf3110080d2bdbcb01e8ad86597a03f21bf", + "0x83bd36f26e7d087ca641848f5bda2313903ca64f8b61cdac127ec56efbfc6ccb", + "0x6a65903a006c6759aba3191ce06fd45b0702f127d822d9c889df12b2d52c7bdd", + "0x8e440f04254f81737b00d3857d1a95bf8709f1475bc0ed15d7347c94e57cc7df", + "0x20929894b05fe04fe12b11d336bbdf33ef983eaf6c501846d48813a97ee4b5f3", + "0xfc727f2888aa9f47d486f93b266c6d09b09b949821b63bf86aaea830c16388f4", + "0xb9035314e27d890b6362db7cbb0953e953b57163be0d80e5ed36759500f3160a", + "0x6d2ba56b3c06326a0fae498467f439b47bce1174862817b5c703019e8d448c4a", + "0x6b92e2415eb7349014bdc3e705a2170a5cc09796930d94e861868f77c45d5802", + "0x83a57de8623aa9742b33b3c8b3737bfb198f738111e437d9bab12baa0660cecb", + "0x979d381266e5105773f922d3172dd020a6010b9e435f3bad16ce6065b537f384", + "0x3fdaa18e7a2ab12c5705b17ae33e96d8df9ab3be631bb9c46d31052ad423a4be", + "0x439e461837340e67edf1c7b7fcf633d5c3d8636174335dd80023dfd61f66c67e", + "0x3ba40c7198d6c75a1ecd79218edb9608b7cecae9f779b37d26873d040d29b308", + "0x66ca7e3c8f892bea4be87afee3db3c9352641139ea4b8d459417180c2df8ac5f", + "0xd55c6d521f3a145379a1daeadfede8f837928315c9c2f1c2642ed0e1a7e87674", + "0xb848560abba9f0e19af44219c2c1a5011ca43eff4ff6471555b3c1c235c40119", + "0x1fa19a85d008e7af8585eb7cbbcc8d61ed6248708429d0f458f1b497ebb190a6", + "0x72a4e2f8b7fe422eeec318f1127b4b4e4fb03e40a028d45f5444c9b287a4a764", + "0xed88ca02a5918d6f621fa1e945bb1533e33ea5c1d41f7915672e3c4e4dce78de", + "0x60ef0df2f7f5c6de3dd7c02fb202c9b3a13f48102f317b54b25b2f0f1f49b6e1", + "0xc49153808e765883dd21e1b58b5725aa1d242f920ff0ffe0c6089a5e00719c82", + "0x0c8581a354376bbb53379f45c92e914e46676b68305e8fcf16eb069c65e87cd1", + "0xb562721b9433cb712b3969d193e132132786434bde1d45916bd7423194c84678", + "0x060cfe84bbb7842e0a49bcf9f8753635d9fcd694de3b8d5827239606269f0cd1", + "0x84306039a875a723780ec685c34474d35ac3431d6ac8d43b2b6d1bba8572eb9b", + "0xfeaec570403a0190c889e5d2ecf96a9a6c720b3944e4b703049c81a35b56d820", + "0xae002e7d8e1279513b037ad09695e93f80868c60d2d8b0ffe6efc8e0ca8a51fe", + "0x20e1f3248ebde32f2fca51a576abfd0db3fcfe359df399f1c3102ed2183b027c", + "0xdf77e0510d24818676727c9d56b58b2495ad63902cedb04e2f3729b58374c942", + "0xc33b4b53e7eac8725f5b3c27a9431dd6e4f966b1289e3b2a1e158474f4a47f4a", + "0x6466f3aecc922abbe6f995a3ede8ae650be7f1c08679c5f6355e32ae95a4412c", + "0x56322467df2291a50bea2baf66169caf34eddd525655cecf6d14fd2295b2a438", + "0xbd81e7bf5e30f4bc1b87c57a4eda09293cf6be979bd2bb02650ce5bcab8da996", + "0x3d611638ca06abfde10ce7f02152069aa30d97949dabe3dafe8980699d49ca0b", + "0x12723caf905e0c044344c83d085f3d89c2eaa695c9d70c0a831d487b050ed453", + "0x473f61c421d202e15d4a62d4513bd48313d253004feb09d9b6e0502c6ba276b1", + "0x9583746c372cd042a46ada64048ac44b30d3b055b6e22ca3cef5404e57a99f0d", + "0x8decffeda7b7de072da8268776c4b9969cbf3e7ae9433334aa7e1e7c93567f55", + "0x543f5b6b686035462d17ef969fa09e0af3e7cd24d13650c2d3597516e62f9909", + "0x5381b2412f6383d057bab3fefd23d08384f345960cc2fb80d7311a63be5080a0", + "0xd96b7933fd9308f7aac9fc42e8feb9f2f4b586400fdee23798cad69611320461", + "0x0982300c344d44c2f63e1c1fb5fffdb44c23749204a0e012733317cde6efaa83", + "0x6048706531d18c5f9a257448b2826fbcf7a72bd08d5d4feb2928acdaeee61768", + "0x2bb89086896edfbe79407ea2bc8535c6be143be6c64ddb1190e626e091c7e802", + "0xd1d6697db021746970393fc0151bef8aca67d202b0e54f4f2702a5f86c2fbe2c", + "0x5c1e1a43ba2578bf4a302e18f37bbc4f1a67441fe6a71ee856662739a5821db3", + "0x1ed663708c0709027c702ad5ce0eca6d3e0f22d6a01d4517adab0a3d25f5eb26", + "0x6ca247d5ec5ae33cbecf8fe88c1aa64745f7a8d299bfd356bacf764141d410be", + "0xfc020b5ae74507a1475ef8e2c0bb516b67bf79aaa2b61bdbc472ba2d75ef5db3", + "0x1ef0990b9051937ff1fa02880131aed9787e6d7d41a598ce7b5094eea1daea80", + "0x9e9e9a83fd6907dc5407c49ea34bd1745919d9ddced756433f374440fa8c704f", + "0xbb3687f8723712f39a8e9f8865543100e048acdcbe2045803ad5a40b61c4a36b", + "0xe60d8a60edc3d7e31ceb356e493a28fbc845f302ae2a8d1e7cb80f53112900b0", + "0x294039b994a3ff53cbba7718280dc827fd582ae789736a026eee1d39284b35e7", + "0xcf87c0d2ee79a0d2506a3d557880f3ee9a20ff51bb44c20caae0849a85055408", + "0x0d6bb688dcf3430e46de1512ebc9e411db3380590bc72dbaaabc52a5320216ad", + "0x9f2cd8a43695c78c7a8fb1352d581c82dd9dd0ff04e3485d5bbdd5e3942f9c4c", + "0xcb32930f407012e479eaa7b4844107167f519deea6c7fc0351cecb93c500d63e", + "0x17e759d815596e0b89a3dc4ba12b9d10ec59988fb0550e1518a8b1cc4f331190", + "0xfb3b36940c6675249451c4c857f6742bb0e1fd3eb126e370eb4deefe238d7d75", + "0x47d619d7d8a9510290dc0b8b2518af2862ff6f761ff09786dced91e39d8afeb7", + "0xe8f40bd7a7bb8f7dffbc63addf31a27e0a987a27c00525c833f6ea8f508537e5", + "0xca372409bc160e5eb7fa70e2bbfe8daac9763b374c7bdea0cadcc933450443e8", + "0x6e234961784273f80136dbdfe0f5618fce6c0d63c2fbbb5d7fd6823632c0ab6c", + "0x2a6cb327e669de9f9783300ef6b2cdba5585236e286ba94dca114de92728ebc7", + "0x0e91e6a11ea59f840d9bc47f251043e10159880276bf69beb075557e38715fbf", + "0xd452ed733b985db558b960ed14310215abce589d4149952a3ebfc7604082079b", + "0x7fc984fb9d191984b5141a9dc7ed1c9657742c63e7958c7652bd896bc6c9f985", + "0x2ce2f74343ae9e37153b5c071c4ba13adcf67676ed7789379c364107d76e32cf", + "0x0bb95a7856e5f61bbe47d56aae9d7f42b994fc4640b50ae80200ed8a678dfd51", + "0x2ab80f2546564ff01e812a39341ae227b69ccc1b38c7f28e61c31925cf622811", + "0x1b24ab582f306305400947e9e7e43a49de6cfd62819517a8ddd904972bd8eee7", + "0x852b65355f93035fdf4358ffc3566d57dd97c9d59a1e545706bc6a13690025a6", + "0x6a44f88a6097b5e3c822abcf1823c98362b26b0bf3753b6fafaafabe9591a07a", + "0x4e7c0a92561e904eed52f2a2b906293411b97795bb194d9c92e335cf9e4ab200", + "0x6ac01d96e58002f8881cea4e177ec7606c69e21d252d863787e5cca65a839792", + "0x4d95bfeb96b7a7978c890842544e8e780f531512c182cf22a73a71b55f1679db", + "0x84de4313a7d87fd748e9872db1164ad3ff9d48993ba429b74dad497dcda5a3b1", + "0xb5ba8e71bc844413cc3eee7325a949af1e0ea81405a3371512fddbef87e4e9f8", + "0x2378cad3d3f0558c0df47cd179791604af7df805f805f7d1ec67b52b2c330d6a", + "0x260d00d98b976fe3aaed233aa9e1b8fddec1092595c91336a5b884fc07e51a30", + "0x7e3e9859270e3a7bb7c5f6d7170e98a8a0a681216e21567c303fbc9e755a4739", + "0xf9aa5450b6036bc61ea2113fb163997ede1bb212f343ae5df0b55561ff32797b", + "0x465cbec75cc303fed26bed3e2701372f9bfefabfcd54096a9189d73994e7aa17", + "0xa86195c2696fa647cd5971d47587212d48957f3faf69721683c158a1372eccfb", + "0xdd104c0ccaebf94bc3c0a6abae1852a71f9b1eee974d5e622f5386ffe0949b7e", + "0x005f5108714efe19e512aa83608e9cac46976b0afcc7a010bfd682965af39d43", + "0x60289c653af2f12a58b10c0f81ed6072b3112eb270b350facd79d0363be2bc8f", + "0x8e22bcefff3aea2767ad9b118be1253d1aedf1e1da502a4855f6ae7eee54c335", + "0x3ec7f166314a0c594eb8138b75a050082884556f7664702333c096bc93b67820", + "0x605398473b453589bc31312579ef3b5ce0b74e3ccb95b680f8beb30d2fba34f6", + "0x51dfca1880e15660901b5f755530c3fa4d652050c134a769b6ab2e1645755cc5", + "0xb24e9463fccdeb2178e520fec46eaa8f2d1da5380d48815a2fe1816f71b79b8d", + "0x97bd624937de7bb8915d7e396c31cdb4afb739bfd4eb6d96f8773ddd0e4f4933", + "0xbe17101284e09bcaa9eb5cd150983b05248b620465244b603b598bbaf9bf312d", + "0xd3c2ce415ee6bc3908cdfada4fcc76b5e0e9fa4f1c6ab43a3710b2ce81f150b8", + "0x8d4918cfe78489e146c071c149a7271ea81dee2ab0615394ecc35827193e737d", + "0x6a7e51675ea6214d36acc7fb193911d2608e41a2df747e328afc6f5a465261c0", + "0xf012c5f418c7e265bce72f9f4e2900084216c9187900927d9aafc899616ea9e6", + "0x934c51d4f2051bb7aa555b3f44bef81ff782b690e29f7cc0a9411ad03ac74a3e", + "0x9ebbecb11efe195d2ef7681c8f1f8af3b501f7c65a0f9ea916f7ffc9a6bafd74", + "0xe28247949b99de84e721641d5e3b638dde927478df0ed0f53b8970b4febbfeaa", + "0x6491ca6bae8781055660837b72622f19daecc7407aa58d24088b45f5725691f2", + "0x3a56f6fdf34d6a4d742451c1f5b6e575685f9a6703541315df1cb8aafe531f7e", + "0xc204b9d22b7cbdcc9132539ea475792f4ea231cb246747c485632be8df4ff5c2", + "0x6188cd2938f72d2dd5e16525574f240b458316d42daafed892faee9189caeba7", + "0xa272f3ccaa93e016333dbc904183db6309e31d06720da1d18addb7560b9bb427", + "0xdce0b5f11909a90c1c6b8fd2bdb3113a035e7784103e05ffc972364530ac36ed", + "0x6bcf3461ce1447e80bd3da2d91dc4530bb649b98333304fe3e0045743c0b96ff", + "0x523496ab97b10356b5bfa8e17b4927b8f0f507368391e24250f218cc00be4bda", + "0x6dfa5889c65ed8413d6633bffc9c3e648621d38eb70e57ada781b3f4dd62374c", + "0xaf1a300f73429dec7f12d0ebe9706cd113e15e1dee6cab37ff11503a836cb3ff", + "0xbb8aa95b40671760e1d131cb269c2d156f29d89911604db04ee7f87511283b56", + "0x93ca5bec69be4ef613260e2dc850668d5a1c839e511322d95ec25203d74673ff", + "0xd7cd3a14db02b6c705bb6cdb03140b50b6b989ab82d733df84f990a9c4d6b292", + "0x9136b9484831f1417ecc2d5ec93fe31b25e79b35513cf5187e50e3b95f862269", + "0x1519b8a6581123491bd0df07cfa3a40b0d098e5cc6ea981368fd073f7c927ff5", + "0x08ad5c68577e9e09e5b00035c65835b404437b792ff327950d07ef227aed6a84", + "0x4e989dc2f09df3e9fef7e50e7b7a9da85c091c11796665602a0f8294dcfcb2d6", + "0xe4a311a951e3743c0d3d05db87cc5d62ab0ebbe6b2e85e035c6452b0803c4be5", + "0x4a64e0fd19dd4b2dd7be3810f870cfca0cb4303d44204ae329f3ef1cd0a78420", + "0xd13981c9f5bfc2efe70eba25bb4f3d3f7bf13d454527df015e951bd79c649c50", + "0x57af6009a040d74b628416de645cb13a58e16fbd63035c6a6d8c8a0bed102ccf", + "0xfbb76c69f42039da5d672776f9e67fe1fd3d7eb0d7f5353852fa64558a91cf88", + "0x07808058eb2b620907baae2b053ef2c5786deb73df750a1b715bb1e0dbc0e14c", + "0x24f1e75fb9fd88b2628285f3e49233ea6f59b474ca05f5823810a8b49ae4cde8", + "0x5cc1e13c706a5c18aa40d8e5db49bcc87c38a07655a814b2179a35b1a8ca79bd", + "0x8ce52067eb546774ae3796de7cbb58f33395438a7976eef1f191cca9c6f59f76", + "0x094311f783939ded904c263a92d5db558e60352a392d3ba77045ff82114978e0", + "0x399ecdbb06d1421fd3651cd625376cea22cce333c6dc200b9e572a001b794a3d", + "0x6a94f126de560108bdb47dcfa8eaa5e9895b3bb9bdf7e7e3078fb725a1ca18a3", + "0xc0c7a71a8e3547cb067a73a984cdf283f6480524578ff611902eb9ef947c4c80", + "0x8593b4417b4d497d0f1d68c21b5f27433be956b6e8f94d0e6efe983492647fa6", + "0x616dacbbf17052280e093ece29a151df4c78027d652ff2ec3887a48daa916d31", + "0xbf17d700c78628de624a49125b764c1240f3d59b85fe376a64cc02f44fd3f46b", + "0x89f0b2b0b4b0eff45499231c9c5fdb53e95f72c589e7ed04c734b4d07df32a69", + "0xd4399b262ddaeec84cb56417cb84d2065664d79a51750ee566217487f420d8d5", + "0x89874f2ef4e0b53e96afe703f4f9e5d5c7da81a621acf00df29f821098142898", + "0x84a9a966381053a4e933c1ebae4fec74d3452ae5feb2b1c90ed59c92fa0f5250", + "0x748adbe8f803c86ef6f20ef7f178123f46d6c45dcfa332827918f4cfa9417663", + "0x0c78bcfbe149b1b2de2253d443011aefb4e5ea0c7a48e2e13156cd5276437557", + "0xa8d86c719b15c328e5117fcc0f4b381df4b8bab346d522df49aae19820ee128a", + "0x3bce6f3055593daacc3ae11b67d5dcc20475e8eaa91eb3153f83bfca6f2e7c8c", + "0x8af84754ff63a68b7b8ba3948e255fc172c53610aa90fc2f5f633bd8ce1ef7c5", + "0xcacfe2b9181c60d0c3d7b48403b18ee184e7c7032f81eebded3f19078c01d7d7", + "0xde4bc2b17855522804fdd6352f36eec477baafd69823908506b949c017aaf4ee", + "0xcbc7689bc06c9f4f04414835a89650a845884a2d102b6900f3abd4d4c8f8dc3b", + "0xb9779ac13bc739d5bc40bdb927c3543310ff114a83bbe35192c250a5f772d441", + "0x1239fa2d0cbb2255d32b82177a976ed5c9f70f0661a5d5267c60f456b9a7f44c", + "0x3e81ff86adae141c75c8b1a91d47db7c6b196ab00cc883fb2fba7655fdd6dca3", + "0x551e92e6d774825a2a48555268c86ee52e1b613e63c8a6e14275ae877dfa80f9", + "0x27a7d2faa486508c7fa20b818d6aa130a914da688d5bc8c60a3547c241937aa0", + "0xd10995979320d9d9d64051e4f721644579b4984a4337de86901b03fc2c042e21", + "0x6f9308ec6c4eb211b8c2323b68c4670db6a8116ac4a370801ddab1da0066df58", + "0x17d3526dec54f66815d8e4358028b0aa91d3a134d843d2945a47dd5aa56ba788", + "0x3a673e5904cc61906f6806b634ae6375de45f4f0d63713555d13a1e274e1bbf8", + "0x39dc807657774ec32abcf299b9c7f03371bfb51a864d11800199ccc7eaafbb4b", + "0xe2bcb8da657b830794b6d9f1e7471663e31996c1bb08456f4d8802448deb8565", + "0x38c7998e73b21038659140e5ae8539cd8cf993686c90148b38d6308a3e3b92cf", + "0x4b6d2986964aac5d5101ded91aaa4ff78a319dc04ab18e550589ef09b638495c", + "0xd8c4da66b5525427cafd152c365f99a255ce2e78af3e3f3dc408de0dd16fee99", + "0x444dbcafda5c0c74092577141df9fc8fb1822ef3375ef0d43eb876fe29c262f3", + "0xc030bec71e90264bacb7c09f9de3a5e282684f9f1d45a2b177c8f19f9c7180d4", + "0xd529e4c2687c7b40d1bda81201770838320b1183da1e18c59c83cc4772296921", + "0xa1ca4f57cfc4ec4522a42cda37df9aa74406d8aa8dc4b56aa62fc78c70d02379", + "0xdd30dc03a60b0fc21dc4b75629124e8190daff2e3504222fd6fb772531bdda85", + "0x2d9d4a9b9b2a27cf863a292a7fd112c81b0deae05457073fa0d5bf7e0dd755d4", + "0x19815e0f25090a9494cf5bea69edb70e7a56e6bf56bd19ddb1856198f54399e0", + "0xa7fa776c8227838d27496a3c659f3da3f5acce22da70701dfd62953edfa2bb09", + "0xe55efa9386b2e0fbd38af545106f197868361f2dc44051cb4a1ad540396283a8", + "0xc6c313738c3c75d434da4083962f8e8355bb8832e17c7104d037b131682b28d3", + "0x756a6309e8c0a374b99b2b2534a851496bc74db36e5bf1c950c0549914f0d0a4", + "0x36f64ed32258a3d2dc849f4abe98db30d8b04df28420c56215e29190e8a447bd", + "0x5273c4accf93338826feb5bd75117a7a0ab5a01225972532ff4ac1d29b289d8c", + "0x6146cf6b830f0222a8bf9353ea26deb973a85c5c4a005136061ab0fb48fe56a8", + "0x97b07c22662079a3a448b373fcb73320fed4a0877125228b4e9a5b74c0bbf703", + "0x68d28adf72884756b688377fac36d371325a01c65f5b70fcd7ac16a2dcd21444", + "0x2c27150b4cd8aea85723c4d264b8799c2e92bd4430719da6bdd3a0290c024a21", + "0x6b553b884acac18804cd52c7139e4a245f2d263b6d014fb6c28e31d7ea08e63b", + "0x64bc2ff8936395f794702b110041a88c1acc9cba50e12c2c5c9730976e667ae9", + "0xc45b2a7e308777811b6c099ffa3287970e003001dfbfe448a2600edf995513b8", + "0xa89c093a0b77cf4ad1ad7ffee799872a66ee38c3989ad39fb90069ab70b1fb4c", + "0xe8d0823460eba540c0c86016014127c7b77b0afdd199fc7bf8145a556a7c523e", + "0xcb2ce7a29b4c67956c439195a84b53f5c54e273c20b6cada43aa68ca7b1b59d1", + "0xcee4cb506d3b0cd84b763f405cd68e2bdf9ec1741778a004eaac9910d17cb67f", + "0x357376e9a49b6c7dab7c5cc95d4a90cc27516f1b7f56c33c4c0125516153819e", + "0x77090e31db86c2f2b031cec1a6dbfa3c3b2f464db7e8444b5def6468c03f5308", + "0xf2b0dee21d7b016c0c9e1a02a970835f934f66c552d653c9d5fcfd20aaf397f6", + "0xfd662e1a27c14d5e8b1e9bf6fca699a3ed7c5bb883cc626d54f53a721c570557", + "0x86194d492a5adc474f114f9cb7b0f6f6795d7680614b29bdbf25e969513a3276", + "0x2bf3ae6993adb5d85fe62bce02a836beb598779ddd37cc2db1f44b1cbea616ab", + "0x4321e3a94d12161ebdbc1b5c0f9223a7f1dc9050792589ce95771c7951b2f176", + "0x79154a76904f2a3c59e7151fff7cd448a3f74c003b866b9faba330481c6895c5", + "0x9c9e7e1d3753804e3644da89248505116009585c6e6d42071cbc532de20749b9", + "0x4dc1441b23210778e4df8417be9f654619527b5b42247bd7a8490a4a5f50dc49", + "0x79fd11e85b307098e827168a157ef45b0af5f4bc073a2920f42c6ff332392a58", + "0x446e8650a156bbb1b96d22e0d09619f90b8baeed34f8b63ba7bf3da3b764e219", + "0xa86cdf11cf5586d8b0449085e7c153a0dd55aaaf930960f3f31f80d099011d70", + "0x4d30e55035eec495badfd3cb8a2174295b2d2cfbee4e669e61bc148d09ff2342", + "0x2f8f3bc3c59975caf160d4a5581cab3499b84a524cb7977e4977de10a74ab875", + "0xe08b4473276f706c7399f584797cf07d33a91c91272ad79e0a5004c00a0d3cbc", + "0x1e27eb957ea54f1806115824c61d78e265cb75807f68d508da5ace6c7dbcd9f2", + "0x8304bbb4592daf4cc754c67dd78a2e2008b1abd8d966521a2291d170c9551e9b", + "0x8298d1605af17c8f47afe0b34b84bba22441a064a3d5311a2ea7e45f76565c8f", + "0xdc8014aead4dcb61449918deef31c64ad8555939347bf04f543d6a1158eb1771", + "0xca91e9581535b11cef0ebcd2e68dc00c3a18844fb4d6f05acf26eb3cd15f1047", + "0x2b26282d94df586bc7d4bc0cfab8ffe1844800c7045621527b9f9f0d5004949c", + "0x9a92f43c5a697a097e39ad12fcd9279b8fb3c3076ea1d910ff871c5ab3342a47", + "0xe33707e3e852b3b6a5cd375d981810399de6a3f96015bff7a4e5065f9c8713db", + "0x132ddae1f0244abf072e6d8115470ad4afb24748169891be0a4b952271599333", + "0x2c1236a98f16a294a9de1c24ea59739fcd6b5932b3f2535c8d131bb2f92c1dd5", + "0x989b0a915bb07ef5e3673a99ee796639722b9e4cf5086433cf8072fa3264f4e0", + "0xbd871c039e619de1514cb6f9223299c44d0555b5eb88570f79fd0d593953c197", + "0x7fcb1ab57bca2410a274f6339927bc12ea6843c106816fe10fc9576b6c7f7cea", + "0x5692b49ef3c3ffab97ab9ab1bcc10017e6d0527e1fab5b257210633dc4d2658c", + "0xe105a92cb6817fe6fdd585068363e0ffd45686fb6dc3658504c70e2057b165c5", + "0x97e65f3bb842f242f51e9ce978320a90720858dc9c535c1d66bd1c269dda0286", + "0xe5ba47b574c389d060e0c5f99f69829d7b6dd8b3bf6e64c315c28521a329c392", + "0xe971dd283f7ed3ca0e28a73d614c490a959c36f44bc30dc7fd79bda064f23aa0", + "0x0c786961cb4df57adc1011891b90813943a13a06032dcb2b7f9ac38dc8b3458a", + "0x3736f1ec97fdfecd7c2e6139fc7ef236586bd9507f65a99913a23bafdd5f069d", + "0x5c6cefd0c6c9c825668f99d1d595f6fa55a45e6a43e23323e901900e02a32f40", + "0x00373765ace6950b4728871a0165aeff55ea61fa8ee07d51d7b8bb8114c20380", + "0x49abb5d78311bf743008c2401f074e4b190d9b29c59cf6328831decd83068172", + "0x0bc28d7480d5a56588b937a530d026a94becf9ced1fe71c6dd1ae0d2922bde50", + "0x45e4ffdd3b6d480ee76f0ee7f6acd7c039ef564d77e5a91546e8269d5468ff99", + "0x09600f167ac2e81cb9164e048908a5b410cef5b48f92eb9a801cf84104430172", + "0x00ddfefc3d36282e9aa8e163d54df86f10737416d9dcf33e786d1713ab54052f", + "0x5b9e3159e4394f03d05ed8b8127ceed638ebe147beda7b7097b6dfbd8342df53", + "0x85d2ae2bfa381b7f5c1b0305f8e252f703d295edbd7c05908e6ae564d05443fb", + "0x5d93339013a78b3344b994bb474fd714bf5495dbcee84346a30219b214f1ed27", + "0x509921ed07765eff19b5c5b7885c4eeb30a8329417d1d819f3428e278364a192", + "0xe004d5f07b3986916f8cca4ba84f9357d4550c26d408f79fb49dee47c5afc100", + "0xcd0f7446313d80026c33427aad00e4689ef0c9966dc5faff93dd1ad258a032be", + "0x0bf64f9c84ef26104cc0d0bc61594bdc0d22f9bf25b436170df1c47351fc8746", + "0xb2e605741fe4b42abeea0ad054727950485ac432754ac2f98db695988c515d1b", + "0x9b6ef4b72c4c5b8159c308fe0395c8f74119bfc495a64e0529209967a1efab7b", + "0xf682c4da2d193bdc8e23cbd2a35d2d2eefff9281bb053f86c84841a3c88e4517", + "0x19cda96cd533527a9a93fe8c38184778cc79ee8ce389c181e67d79971c82fa6e", + "0xddcf6596740ea21e3c5135e32166e5e7944ab1a37ca60c57d9d005f83015865d", + "0x4932d76141f9f33ea5193e58e1767f67b5017ffc277c41fb8b9cb020304b923e", + "0xcab96730ff161fdecb5c0118b34b2a8c6ca2e53cc38ef76b8702284fd64d862f", + "0xe042dd86029d97b89ed789847c9651d49b2790d68b475f194c63c89974704b95", + "0x548200b226d36c3092fb9d721b74b829564bae7f39a63c2be0a78ecac5c69694", + "0x26a162476b85f3f6e366b3b767eb39227ce358a4c78dcbe6c8e3710c6ae05c1d", + "0x6f388c498dcc8b1e986c17332c8df84af7e8af9fca5c5a59600dda14f74e125f", + "0xa342f25dc1194e225f4c8b4d89b8992bf59517cffee52a1f2c2a0cc4727f909e", + "0x5e0d21aaffd603c4f5d73e5eae97e14988b03e45beb15bc44776e2db9ce20fb4", + "0xebbbed03150c85b1a7c7e7e6a6a67fe0483fc7176bdfe4f94bdb094ffce5bb2b", + "0x40e530eaa7fc24685d8cd9cd94a3f4b01aff4cbea49aafd448cd1f7ab4b0c186", + "0xecb1cc861f12d2be9b1f39bf56363937e6bdd5eee6d7e5e90426e7d29bd75e65", + "0xc0bc404c877856648f5793792aba95c9fcf2768eac65028e0a930c57ff9d158d", + "0x3e50fea97445730cf5c3fe8f05c1d03c2298fcd52a7d9be911d1c989f29fe204", + "0xb512ff3c024347545bc2843bc84f6006c0b1a91f49a7549558ac5d8d331c1fce", + "0xc0fd2941f49fe9ec9ca375d0745803539dd3a9750f1bc46380cad3ce29c76264", + "0x7f37105755852886e86d113ada4b4f1f68ebf0aa36dfa36291584dfe28e773eb", + "0xf0942db3af7cd949ae31d1f690f832c6e4f8a3b9744ef9bbf8e7a90b04a0ebff", + "0x6a9cee1f0f3ae40d63dab9547ea6bf342efb99176fd30d0ed2d8de02f1be6c31", + "0x2c2092ec0adfe352c46ade57b3c115783b7d4a92fb63bd1effef32e162d4b34a", + "0x4aae695ff67508f2d03f8674282d58e4f1038cd0d4c2a6a841ce425433e305a5", + "0x543665bfaeb5c10c0dd4d180475c9aa18a9edc313e52405f1c5fdc151538744f", + "0x7473934014d90b821ca0076d132c716728c19927f5680482b69163e8ca5d79a1", + "0xf3f4efa6bc4e493b5e09f32cab59a9cfc28b5a180a59640270a79927058a4f43", + "0xbfea0aeb82cd88ffa0269c56eedfebe83759a4af9345ebcd2156ec234d99633a", + "0x827eef18a3c2e24021dacda3c00187b8cc87e071ed1e2e9246be0066135fc284", + "0xd567403ba1bcccad81978857599647c0a7008cd3ab1a3bbbffec1217da92b060", + "0x74c8805b9b589e9493ee02bc73131431256d18b79de4fc3820ae5220bb5498b3", + "0x32afddf7ebc9d7efe51e045446a61fef4b156a3379212517b0971a91252e1b2c", + "0x4d050a932e5f971f33353a23c5b3382d163319321f55368598bcc3cd8c67f91b", + "0x9c01431659ec8c4db0cffc566ed9da3d04d5db610c6d6fbae260ce3011fb68fd", + "0x0814da2cbf76f83196ccd5342638df799d881eab6a526eab325c06d75b7f8e01", + "0xe669b4a2569397b901dad843884668d52ce85919ac6703671963d55c0923df5f", + "0x44762f71591afce826580a50fb4af763d7ceddc75d6e74d4f40deb3ec4c6ad13", + "0xd3231536bc6b897a24e7925909da660e7bc2c5154e529be0dc590770b5573023", + "0x8934b9858529b0bfa879142e0242f1dbe68143ac2ab347517be826e2cd8ab087", + "0xe833f8513f4e71ec56adc114106d5a8ae19b1aaf95d91a5ce18398f316253102", + "0x0a5d3578d418e0eacc2be66f8eb365a7cff71e6b287459e25a921befc7c55e79", + "0xc11db91e90bca5f39221330704193e670815920a5319eb06676b5d74e1d7d776", + "0x04f1e0808c62821a8f088ca0172820f469d327dd336db66d9595932826fb73dc", + "0x1861241e353c68afcba164f24f650eb3892f219d984e376336f401902b4038fa", + "0x142c7d1eb631e40562c24d2a271f0fa21be1ae76d6c7d98491599dc0d0580d27", + "0x203231cb071fccadc815f222900beca55777075f7d42563529682e6449138a17", + "0x304bcbcc7b6dfee9437b8f6b255accfd789ed115461b41e933140730a46675e7", + "0xc9f2359de838acb06278d7967f2ffdfd3bda5f46300b21939a760914a7e00568", + "0x1b470dceebbda583263a9373a4ddde80e2523b3837ed3c20b111e6fb9aa99a60", + "0x765ebffc2d48b2fe92c3fb14b301cb2338984f7760d514373b01fb34de466b33", + "0xbe814242513e1ef6903600ffd517b8f678cf306e057e01f3971eac7514b72ba1", + "0xf313f2b3c05a1dac53de10ddcbc4cc38b38be85f89640aafa4502631c0e3511e", + "0xdfb72e306c68cf4b22f62e9bca906ef3ac627b2286d2a261489e2c922d700dae", + "0x0783bc2129066d953ef7aca86ecf53ec3ff2bfcf8920f6079ad0a4dd703fe331", + "0x71f1fbfc2a9a232e2674e3e36547ee874806ab37b22728d8c30ecdb7ed2ad539", + "0xbb098368fb1529222eb83277af668535a1173a78825c7e3ef86f4f45429cb838", + "0xc49eea0b1171263bd8df058e6279092d59d1e8a4f108d1b4004333733bc6e7a3", + "0x6f95c83060775d579005c4731e05eda62753bcd0f95295b395b1de22b21f3b0a", + "0x9869e93ab6e4ea9da4cd12c279580e211b4c870a7e7dca098058897795804e76", + "0x816a76e3c912b639ae1e4b5eecadbb8cc173c3aadd796815a9ccdbf9226d58ee", + "0x29f33d9d30c64af6b372e922414c85004655782d024916909834b95643fd6096", + "0x30a9763617e8337203196a11f3e4b81b82d9642f0cf26b2c654c8504d289a17d", + "0x21eb2108b1ad465397ed3aa8016c09a52000c60aaaf42e13d95c271cf394c074", + "0x59d8b8fe9dd951d5ec540bf46808f01c9ec2a5e9dd0247b34b2622c48bfa498d", + "0x71b8061902f451c6fbd95c29ff960353afaea2b0410ee11cb993ce0ccb8af446", + "0xe69938e7da23b9d7ca611326dacaff95009cb5898abf1858593060ccb5aff4f9", + "0x0aacb29673ba3a0dce850ac772455c2b092b1a0fe61ed34965e4cdf723d659d1", + "0x18bf2fb69dc62ea39c195a702b8e9514be4b9d5eba18af13974a63f74febccc6", + "0x560b7fa0d15ec6bc0add83b6125133b97672b39477092cddcd5e2936f49c51d6", + "0xc8b0d3b55acae88939bc9426181dcc7d965bb5f85cc506d26f966c60a66e4ac6", + "0xaa9c3dea2f0184de1774c47923fb7f6ead25bcdea96c70b30127ad61a6bf67ca", + "0xfa90b6e07511736519ec741ca85d23d2912b509ec608a5d319c2369aa358a82e", + "0x0ab8709a1c9ac4e9e516736b4836febf938a0055d5b4cde960ba651e986f2caf", + "0x03e28cb08abb6912d3a25cb45868d699b89bdbc180eba67590b2cf13718c967d", + "0x1617f5fb8c39fac172251ac4bb1a9b8e20f9c36cc6a47e7e0545ee38fa55a6f6", + "0xf8cbfbad5d5e66d95dbd5e83b2968d08b6eb41d28efed0f1d9205b2297168dbb", + "0x4adf7de19d0498164921d4aa39bb070c6183e8511c9f987bc91d89cb54d8affd", + "0x7b5b34085f3267297b40770c0f27095735fa286ade7521e81f500005ab63d253", + "0xc2943d2b12e44ff193ad957440620e43fd9e8da22d74bd7e4b18846eb93fe67e", + "0xa461d24d7d4cc4fdb8016476b3d5e44017bc27609b7fd09136c3a884915c9761", + "0xdcbd32d171d8cd8702ec3093dc2f149c31542a7a35a01fa63043facfbf7ddea4", + "0xe7c4e881bd4df86737497ae6e3fd65fe9d953b8e1c45ef1cbba2d291be860dec", + "0x1fc56bf433f10fe704662c0f9e69a878f243d8832fe723852215f4d2ce51f9d5", + "0x5d22da26a003567829f9e2fcf0c2be4d0f791d44400936ff1132a0dc367c316e", + "0x985c40c0bda98d02e3bbf9e33d13be1ab4b1b917c94e06255a0d60de8a547513", + "0x5aacaa6e4aa6ec649fa272c1ae2cd0376270a0252c39d1bfdd973f03cacecef0", + "0xf2992b858c902441bd44cfe0e2b3057615b7ef6a7d129bf8402e4270b711b126", + "0x690eccebda6832cdab7adc9a56b5d8ad7842aba0d7dfa0aa073347d835e72703", + "0x41f48f7975d1aff8070e4d787b3bc127613fe74cc0207e6355d80c930577348a", + "0x42286416ff16e06c1b8088e484e1687ccb93c134a880e06ebc621cfd1fecfbd4", + "0x241f3e48bbd35c8743856e8020a2def871ffef7ba897c72464286419a8e67e28", + "0x3ba5d479584f036f4b4f99942a5bc2f51cc9c4af24527dc9ced5c66178fbec00", + "0xecef4c63d3679889106352d9e56b56b7aff5e1f1408e3dbe86e35dfe6ea6c97b", + "0x2a55f99801b5437fa85f91046e933d5cb898ee3150c6a068f658e0091a303576", + "0x0103857974871ee986d9d5d430b5c3533c0b1187353300d25dbecc2aef14cfac", + "0xe2721431cf8bcc77d5652b519e879d0cde2524972d74b6ce3e6a78eb0bdc5c80", + "0xb577b9c2b3348feb5bd8e283940c524d940268a3f90c11e35dc9de3438ff038f", + "0x5bf29a628a6ae340206e02f33eab362240f99ce0e3cd8d440d002ed4495252f4", + "0x5b087ac28a0e6555830f6510fd275bf464ee4d50e6848b251dac4b823de6b995", + "0xd6ca4c3a14090c0204fe4b9ac487debafbf0f984c289cded1de950f2e655abd5", + "0x61e776419693248d8a6b8bb2ef9b9663882b57e60650ea7fa22f1251e201befd", + "0x84d0ee42adb4c9b0e127535cf76a00a0d8129396f861d5d41dea599dbbff3d0b", + "0x509683f63b390fdfcbb699a8a30340abfb5425b257e86015170d7b7296b33548", + "0xe18de77507e00ff5a9097ae81007e793ca9abf2c11f65172c1cb54a189032d3c", + "0x38a8a3c1c0c110f674a7e69039258593e15a9194b1e77ebe6176ef5caf09c6f4", + "0x7e55232c46a25bc79bf9390c2b105d0fb342015cb526cf0decdb9db23d1be43a", + "0xb745498c642fb70abdc71c707bb1e4baabd534c5bc503e35545a6395cdb48918", + "0xa4b968ff3f3760b1fa4b352ca6eb8cc883f4c902f8e7baa2644d5a7726694031", + "0xee106b785aa0d24e57532819d4cb34b5795ab0af3080b38c73168ad565103b2c", + "0x1535e68531fad8e1edcfc2621747620ab962ad38a033ba25d1d6f5947381d03d", + "0x98c83d74aa9e52a7eae636a0fb54475173fddddbb56ca42dc314998c5099c649", + "0xdae0dbf33fc395f96a4dc1a8da5af3285b8dbabe5b34639e47c70b0938a9f64d", + "0x91348b33bec70e0e68756023f1432346ca2aebbb6a43df28b7388f6f9f19bc7e", + "0x575859a6c8463bacb07ff4902b06fe1c31ceb9552bd781003d4ea2e15dc81e4c", + "0xef1a187b7033a67ff5dc0cdfe353f81d8286c533669ed4b0c0ed5168f018cb19", + "0xc671086723929e889340d42392545c10126be24c357d509ff1c6c1a5f9a57d4d", + "0xf4f1fdaf74870f153ea8375391b3c446bc3cb9b428a3426164320c720d755daf", + "0x32caf4a46065b4094869812b25138ebed9b9fe17e27bed2f1e1f18485e29a5e4", + "0xb62d0e1a873015ebd2696616378f4f3f39c5e9396ddeb750110b7ef04f189222", + "0x410c675d1f6583e8364939108dc46223cd9835623473ca18dc333a4b86e69390", + "0xffd66aabe2768327036556eee6fde0c9bcfda2b13280decc37d82798075a0b75", + "0x3acda6ba4917e64e977f4135e8c74e9091499c212e6345c58c399b4dd31d6fd3", + "0xacccfad59b3f59f16431348a3078c1dc0b662876754c1f373351d0725dc1df84", + "0x3a74d9e98aff2b6445b9776cdc21c0dafba808326d917f47d57250f150891bc2", + "0xdd4e0bb3b84db7b6e16783870f7c9bc563cb1576834eb9175721eb9cf75f748d", + "0x35e9a92581c9d402a83a7baa67bb72fcd0d9b3f3d7b1b7a143234fdadd2e67d6", + "0x64ead38ff01f1fb408829012a033eb847aa6ce3e9b99dc5e866338aa9c355b4f", + "0x78607406421e95ff55b3b952d2b4846c8b2224b2a6b46d231482ccec5de407e0", + "0x04fb332ad235e8ec13b07cf30b1c1cb6ba8aba4031f932868fc1da5d82c03dfe", + "0x4fcbf75d2beff58cf1645f74c2ea804c29e1abb6ed8d33eb6da0f2f7939b3cc7", + "0xf58b87be3dde47b6a9615315d2eeda6771fa3b31bdc369ea706f7769bd857af8", + "0x7aa5b0a30ab24a79a54080b1b56befc3c88719219ca5cb004cd45d4ca1334dc4", + "0xd2f1129f7a6a0743995aea48e9c3cfdc5efde47398e6a67a634c1c9865b15366", + "0xca65cece85c379cfdd49b9ffc5ed7e9b8a623e06f99bbec608fc3725e4a1429e", + "0x2e6942d93dc94555d948f3358d7ffef3774889455de4da3565ff883a96a590ea", + "0x063dc2dab7f0c558eda8bf9baf3901e1626416f517352760180557bd45014f06", + "0xc633fc9bad22bf62c85d4ce1c064f3ec161014456c4eff5ee9ee197230aea32e", + "0xabab885f2c04a640062289106e7bef857389db6db0a499468b45f5e8147c5f14", + "0x96eb606a5d165dc66e5c293fa139a9e8e28fb1ddc8515279705afe7a57e318e9", + "0xacb239d8e12502e378326dad3b338700d359095129411ace179e5b921c07e731", + "0x8cf7148ce70d71a754bc04049ae797e930a9b16bf4962dd3eea2f13ac6f75776", + "0xf39d2ae39131332c16508e09eb9d507f4c6bdaa284d1f4a9315af8f6122186d0", + "0xcce4df2d5f9484177965c2440bc54d1fbd0429060e82bb76c3b90f444b5246c6", + "0xbe77cc749e5f436a3b76360998ba7e6e263d39fcf792a6dcd7cc4ea18c836990", + "0xcde5a6e02589515ebcc307e20dcbf163ec85e5692ad9542bab23b43de55c487a", + "0xe7977eaf5cd7cb8c7f4e86a2c3813d52943a12baecc76f2b9d1eeda569c29d85", + "0x1011e0ba87c36df65ecf37d2360f98e0d7351f27ed9199fd7df166806332c139", + "0x9e481944f0e07b91eefc66693b69ea71c852552cf8cdafb1bc93336b971d6989", + "0x2b4d369db84d19be84a7af630b0c8a4ce0974418f407463cad8a8223b208a82b", + "0x7cf34185f5e8229b657c57c3c775987128434e909d72d06956515440678e6a25", + "0x5956c7ee723b161a0e7d74c69e57c96ad28261e9d7358bf25bbc16560a8292a5", + "0xd9a932e6f59d547de8699965c4e5964e0f663b9fd5bb9f6dedb4417d356f234c", + "0x59f2fae38f9ae4b74ba9abc5f06d4354fb9eef65983b1c8b1b025720d1b47d51", + "0x1c418c58dd888b1a546a1245021b52e83b1bd3fcbdcd0fe9bd643fe05fde502b", + "0x0db806610e23383046de4a35f8098597f1889e4dde4bf40a244e4995324b29d7", + "0xed51baa16beffad522b677c19935f07d7182b0a4bdb04330146bba3d8e8f80c4", + "0x2ecce838cf6ac5d0589fea00bab4dc9c7b107ed7c70886ea6519807785096f23", + "0x8df70aa241b84fd616047258f87b04249fe23219808a6e14f3d9fd0181c2f352", + "0xddb9d88567f42cea65b5913369c9791522b4dc4a23b0afab2003dcba337a5595", + "0x2e276865fbc34e7035cd50dab4b9b72c980abf8f7dec50988b86995ec57ae497", + "0xe82487c950c00a1e4a9ac6d2c3d0b80584b44dc27d28d6352dcef8786da3a7b4", + "0x724b23460aeb403ae7f9b3512a1e222a63fe721a2ffa4e2f4f3062da8bb5c224", + "0xe27ede30590638e194e91a392993fd9a9a1f168e32e3b9144d71d46e507d716c", + "0xd29403c683d5b1ff60839587e60eea5a6054588903e7c2c0b6f9bf030bd0d659", + "0x4e9464c5a51b3f2c6a829137b67e266ea6381c069e1701f0bce7ae7742e9e49a", + "0x0b107abcfda0ec094a6946c6057564f60eea9e6a55b2c762d4af5a7ab7899c65", + "0x5f908c956864addc2b57f01074c567155bee41412da6d63ba72971ff2eb8114e", + "0x9c00e148df00d9fb2d5847bef0726a48507871baf12be51373a7bed2a0c43f70", + "0x63a2fc58db6de3a2de3bac57255503791c4204941fcf15549a7839ca8ce26efb", + "0xefd321eb79658c3706f6f2a18663361b3adda792fe9064de3785acd101535223", + "0xa73176de8f5b3a5bfe87273711cc35a042c191aa998dc5a67498b0287e54be82", + "0xb8e2f03d134651957c31c47fff8cee2998738a603267a12f665f577a450746f1", + "0x3276e6d7618e898d6a8e1f014ccf9e06000f7cbb279dc9d078dee38f93231d3a", + "0xd23b5d1399be075454bc8f3613377113a7b65b29c1bc1a515f9bbfcc30b88174", + "0xa577feae921d39efcafe8102252452202fca0532681c2967c06eb63d00d83294", + "0xbb2231f4d795b6ea3894d802ad5f303c19edd2a25dde9c3a21ed1b578726b51b", + "0x81700c9bee6a014df24ac76eeaa2a378ce7febde11903e62a3d223ef1eec39fb", + "0xa1e05fe31cd3a58a3c11cbe47fed738e0add5039a8f97275572c7f66431f3d6f", + "0x8b5d0ea77b923d4faca65b07c9621467f2c891a925ef07009353b9e7ed854760", + "0x3566b43040f753d8a18edf7b3c89d44a2a3565aa0280ec673718ee81b82df24e", + "0xdf0672dd1e1bdaba83c0abd1d7c41d420ecdcab0019cb89b3dc310bab32bc8b6", + "0x2ef7e245c518654108cbea643f8b050257b9d3c4927493671a3a094b1dd0674e", + "0x993a3c5fe23e9636f525a4e5ee514949c5113f3b4db21ffc993a8b6bc3a55332", + "0xa023919b4e8c34cd2a1c7dd1768eb8e856ad2a1f5b101c8fed88257fdede3804", + "0x247fa5256cd95b9cc4431fe13466483f0db6707bd2453b6374934e1edd034b18", + "0xe63370f2acf5893c39f3728b66907ddc78d9dc9947db14ed6a7b5a6a876c69d6", + "0x397eb84160515d8b2beb3d37d7dfe167fb907f8a1a6cfd7457b646b95a18e9df", + "0xd236e18de82fddf7cb7f6df91a4d08fc98d9aba622e50cda7499261d01d9bb9a", + "0x76a526408c824b6c9e8afc5a0d5e5492a71f30cee5d70b4306c2298d348f0caa", + "0x00525d5481988d4c4836dadc936aff84036d99aa42722057b35ebd933c61ef3c", + "0x94e54fe2e05dd7d7e4026c0048d5e64e5314f235607e568cea8c26bd31dc3f51", + "0xab1e0c92b35d49b687188518a7af63584cfb13a74c3a9ad800fd8e1a4541faa7", + "0x5e65f148c1a914b300aea241f07de5c43709c38d279ed118bcb40ab9a3a09226", + "0x9fc8a8843a0eef62d8c16d49c70cbf2f3fe84cc155cb741d647f17e2a664e7d1", + "0x8257ba8acf906e46b7cd0de0d7463ee96c62ccb7dcdbe0fff5fbb6bc0da28d74", + "0x2a57b487f4281cc28a5b107a643944796ef2416d7989ce879d06bfd6d4caffa9", + "0x0bdf8efb30c449b26d5c574000646ac316aff27fa49d6e20420a08e441ed5f96", + "0x5d3b67c6a6324936305f405067ae70a35146759278f77793e3f7c4b90ac0c7fc", + "0x156f094425a09a09f394075d02f5b5d5aa6794bb5cf62d824ece1c57d58ea993", + "0xe31782172a116b92ac0ea9de1cadb81c1586e05d5b3993f10f8f695469ff9e81", + "0xd8f85113147a72b1950948000d75d6005ae183997c798fbbf2dadc5c439be9aa", + "0x9bed32bbf1f626012985392906016db1c993fd8ef351f8c72e2ae832a2efdd66", + "0x1c6f7b17c8bd64e03d21ca9b6dc2df278cf0b8c8f6f60c60741659fe5b34af81", + "0xe41e4494cdfc0e92f16fe6ec78e19b9d8cc3db73700a1bb02fc7670c92e4df2e", + "0xca1032438230b4faea930fc0689dd966604487a8d3abbaf21554b3e078547fe2", + "0x2bb999d1acc6cc7449dc0cb965c3bdff42e49b8ddb09cde885174c45730bc2b6", + "0x4601be8295359bb23f6f09d7f053c637ab2ce7942b762ac55b1da6d312a765c9", + "0x13fcff0af19f7f11af35b360a0199bfe610a09864dd1d42b0a6570bac17803d1", + "0x31b567fe7d9e6a9a3c15c449e9aa0ab8f83a453beb2784132f25b0919abfb428", + "0xbd4af1360219156ba336fba9cababad31ee78e1393061e3ff62f7ac785c41f19", + "0x2e15f44010ce7a966dfd3fea57c5124c120cb60d80a635910c0b2feec59fa977", + "0x68ed80af93e72f7fd9198d036d8b995e5baeb0f97c6f2734379116a5814b601f", + "0x6aeaf5d0decd1a5c8eef52435bdad2a60cf1cc5f79e23b90b7afc0110d830a3d", + "0x349b95da9a3c65e1d34533bd08f8c95c934c49b7c20e6c7e38ce4db60239c94b", + "0x2a0053d5a61602e26d932534d5e9a753f75642edf1410b3ffd61076d27d5ec97", + "0xca53c9d106169cd3a7a870efd2c2c7118ff953b8aea5c5b9896dc2ff9b2c5d59", + "0xd227181ff80d67f95f4fa11f86b1bb5dfcf37385262d82d6025bdeecc6bf00bd", + "0xefa99cf897198be702eda71b3fecf4cc12a27e7c90a258c4230aa847b03e16a6", + "0x0788c17ea693a049784eec30b17c49e66e7a71175893a064db7bc6e85a0b536e", + "0xcf2bdf91c2f44cae1148ae027688f70ae27ee65b8c1159cbca3e41ab7755e5c0", + "0x32882f2cf31033d40d5069e68c799f3e3297a9915287fb317bcf657e078fe6d3", + "0x3401436cb69ba8552d4731fb2f734a9a659cb10ac666f374318420d3e299b98a", + "0x988943c9b35e50f6ab03dc275de1dc770aa32574cf9a90dd0c13e7263b46c129", + "0xc282d894a7e4346a492fe495319c5cc9abf0c7f95e28bdf985710f692c770520", + "0xd7f8e14bbf8c6061a0927e107f53123f78448b878b9562cb8113b5d93d2d9142", + "0xe2c995419467eb379ee043399d89bb13a7d316b9a680f9667dc9defc7fcab80b", + "0x567357333aa3c5cf6b1ba20a3514ad0e21eef11f5a5c4ec999048abb78c5ab7f", + "0xb9f31c6c771e610048dcb0f4553629481b6d243980e1ca9ec3d1400a56ef452e", + "0x924533f9da72137f96ba97b39a95c2c369dba0bb09658aea3a387f3141b5a34d", + "0x2f17e624e0f3213c2d953107e72aca40b5f764f4b31278c8ee32a000119aa3ed", + "0x8d301cf22181c65bd6db20ca01df6e3bf13864f88958fc04861c295a31b9a86f", + "0x3bdb760c302d348d16e634c07f437f793b888bc15fcae52c371675b7eec2e241", + "0xaa20ff689413c62b1d9854ed1c59b1629e9fcd9f99512bee40933e722e4d143f", + "0xd9d0f8cb5b86492abc172c0460cbd819d13c05f055cc1306af6285459223373b", + "0xe0ec50a77f89631ac2a1c38448a3e5d8ee739f1cbcb542b23116005ff0726679", + "0x90238eec2af4ab1e1445ab94f422f90c862afbfa8cd6bec154d2f6f40721a615", + "0x5c2350ae9bd5f2e2355c97b0340e96621bccd43e9a7e4e867ba1523f5a5178dc", + "0x896a7844bc430b330fc094554ef21c162e2c5c890b4525720a612c9f16bd80ac", + "0xc2aac353dfdf9d7ce52240f6b84e8fec9e66d4acbd77402fe7218f55fb76e834", + "0x840ca0ec7af88f0e26d3b9e54473fdfd038d5395165b22a935e941187d529136", + "0x5e1274869d1d7f072dcf83d631844ea7e750f90a6183262622f2db72eefbebc9", + "0xc217f1324e0ba4e36cbc896c2dd4418ca5bfa880cc64bfa913d6212cbcfe8a95", + "0xbd7893a4798b0838629ecbf21a8cea963df8920a792f5282604b59c536ca91bc", + "0x85b22d6088f30f1b262369f869a72e1354036363f70c8778b1560658abf75902", + "0x829935ff52d7148a3c5548bcfc72b736b184e4f4661b251e660313895432d66d", + "0x4b0d3238882111cc0065b1e2c9a71eeccb34876b4ddbcba989a47faff0f505f0", + "0xa619fdf363c41d69d2cd4c8063e3abedb18066b8cb6ed4fcddd99686d684f450", + "0x2dad790e3f5f6be580f97dd37b22a1e80a6555f41726bff0639aef54f0bc47e8", + "0xfe2064175fd61af4c646ff0745a79ad689d9be2969bcca0939393603865ccaa5", + "0x8a18e5e22dd996798181fdf8ae77cbc7929e5bffa0145996b00d83c5e7829c6f", + "0xa7adb5fc7ccbb132a8e22a861cb5e3e1940a4ec7c5add1bc767ecc668d1a84fc", + "0x7ea8e25d742691f53294dbfdac087b07d688cc40a4a2de28fb398b2516de4bfd", + "0xc162edab705ae176b26b495f7ef7205552319a72d56c5ded30be9770860d6530", + "0x5406de06f5e2e819ec8a7efda23e19cde88bf8ea9969e3e3393f1235c4be67ee", + "0xe5a6b4f946655b32549531601ba3571fbcc45bf58a7b18ea24b5f4677fd58815", + "0x5bf157c76ea5a10ca8240c44a72450537678bc949f57cb9a748b445907180d8f", + "0x4f2f7c966d440ab36a1ebf61ecb1a9b1ea4ea6227c29e4fc1214a8c63cee7d05", + "0x81dc3a0dcd5ae99dc7bcda8b30cfe89aee00094258891d445425e8e304a71f08", + "0x915c3f6e8b37680ccfa5dfa941ad2147fce2f99842646a7835e2d45e50e4d991", + "0xe616568cf1a281f42a32686b65dd712e2fd003a84dccbaec32b890440dd206ba", + "0x70526aaeb8a25dbdf93b3a7cf9cc638292f2502b7bf78125e88df90335e594a8", + "0x6b3e974c6a004beea5b38dea401870dd2a68c2902ea8b3ad5a8358e10f04eaf9", + "0x99b17fa583f9f80f81edae98fc54bd5552ad44aeeb6123e99670696541cd0442", + "0xcb13a1b63fb6f0b511876a699ac017aade97d8dec84249680e7e36b3729d9744", + "0x2bc84717485fb9eedb00647c8da26e201fcf05a0b5c42e2e03072ca130d1e3c5", + "0x7bd8ffc908159c25a28a3dd97064ee7a76bfa40628ac54066f83e904596562e5", + "0xb9d16b733cdefe95eed9fb024d5737f90723bdc46260f0aebe2adf23712ebb05", + "0x0d6a943a7bbad9fdbd107c4a1df726f7aa61de4bcf1e1c50c8a32d56828e8c72", + "0x7a264f356294d00e55ef0dd56e8ba793550c4366347d60c7cd31176d79dc8486", + "0xf52baa383738251b1085fd6aebdd0da48414bb993fd3bc427b2a07a6ace8d39f", + "0xe2958f9d5bc0f1b23b5a3923d87567a58dfa31cbc0a63715b76c501bcd022f65", + "0xa760fb572f3a44ac43c0cfb75becf5bec1d7dab5e33222050b95a6cb8938b146", + "0x004437e7463a43de8edcd074a4c2f03ce72e4716f88f03567a50b6440b69ef2f", + "0xd7268e9610100bddb2188bdb0f80ffbc479b67bda2ecbc5aaf18f947667f3ecb", + "0x176ac5d88148cdfd9049d3eca742750edf975c32e649be8372b15e43ce162d77", + "0x118df9c7631bfd903fb46cfa867c8ef861d9e828e6f57de585f17ad351819e25", + "0xea084c972d69e9ffb61665a27fa4f2d0006f0e220007c0b2e4760a95d68c6c01", + "0xd6e2a8f3df290a204efcadd3a34bf57eea6a3980fbb68749029660e661282f2b", + "0xc538e4c7b704fa8c1c123f8baca05bca5fda28df7ad7fec099638a4a7dd4fd18", + "0x419823e612d6a0055fe460ec9593b4fc0298ea94e0ce838fb302ff1ae033bf40", + "0x304e214664a6703ad14fa493ed333cd12f6db8f4f6af1223bf00a348fa3223e0", + "0x4de744c5af198cf5a0048c4a3c9ba578ea3478deae31531b87eba2a0e65b6fe6", + "0x523694986a7277170342c7a53bb710b86a432b0a7a3d96e141fbbbc113ac2e88", + "0xb81dcd531f4ea6eca82860d7f45063ca7de742a2fb41d7b6c1d62202fc1af17c", + "0x205a95c1d7e7d2cd684bb666dbaebd2533f4af28837a6fd2f6a7d4aa68816dbc", + "0x7c48dd0273a7207ceb5a8a1e3b33352f6d438e2a7b45d4c082dd85135e21e5e3", + "0x0e3edf65e5a7502793a8f139a69f3946d567a959ec411088af96da979047675c", + "0xa0b8886550aad717f1b5d57519a4bd82bdfa30e3c8ba4ff81a64be341d828aee", + "0x399f2cd7012257b4991343f191aa688915b4375899ca9519630b5ec6c62a8b49", + "0x56068dc17a965fad007ec7f23dec7d396dff33b0a60c4e9b8d0f75fb26178f05", + "0xbb62f47822b394fa87d70cce239c9e57464157fe2012c2c37e8f6b69515d6112", + "0xd6a068fdc6d4cd90203209a07363ee1eba047703e50ce9b06dab471e0dd1a037", + "0xe5a62c74d81ad110ea0ec13847fe64e4c3e8e48b1eb053f1e381abc0caff7bad", + "0x8ca95a015ea27a649b0bee134eb170f01b5c03cc45a8bb2c40557c1598c3892a", + "0xb124e101738d541ac61b5666c0fa19375417d946a2344ca40baf308fe8449a98", + "0x1b9543937289ca48720675ffd354464fecacd8b251a3f267f42906b7188f184d", + "0x0b48dd3eec04741e0f78cf61937b2f263446d4ba269e8c7d4aff9c00a2fafced", + "0xf72ffe4699fea49e7e67f96fb5688247746c9bf25fb58e41f02b0dde4a8003f9", + "0x08328b322ac26a02e89401565b91a3dd9abee62fe991744e2ecb2458c6c26460", + "0xe9dc223fdf695c9b5480de56cc91fa640a4b73a8cfeff30ecf4db4d36727fe21", + "0xa83123655348b15b947d83c14a241d8e303242614b25c45044fd1a1ee28d928e", + "0x14ac46b1f556ab33fd4199e5a46e0584d00bbcb2592ebfd4d4f66efffe31bfa3", + "0x71ad4b7b5605aebe1059ee484b5ec791e9018b50f92ad2f8d4f3c1548a99411b", + "0xcdde5fea3fec154058e16f7ef877c70404b577cd74f98f7dc45600cb7b598b04", + "0x330f9d20ddac508dcf0e08a4c1eddb55cb5d7f645c13f50b3683a41bced9e244", + "0x76de024aee0b03e96765dc6d7c71acbf253e962b4f3892b94196487821381ade", + "0x1c37a50f5e3c774d9ea4438a629d497705c3bae728e8e89608ee68d7cd2b53b5", + "0xe16a37be64f82bfe54595c9c51625ce3b69413b70e0b119a04e79c5b8d593c22", + "0x525afdc902879df4c23b996f34a5387fac6e41300e1a7cc9e24c630a1a140653", + "0x845164906086e678bfdafbf4719cf8f80d988bca007aece4b031c3ca5df08db6", + "0xa4d4bca2c51e8118d16a4b8ed33d41a73c275bef73072a6674005b9ee7bbb793", + "0xd0759f637aab37f4981b927e688f3e51f17cf90660931ab8bdfa40363a6931df", + "0xf54986144fa83bc3953c4a1c91eebd6a4abb185ab7b188cf7492a7ca430b9130", + "0xa31de426ecf5f98c1381c844e2fb7c959ad8adac39484d71e3bd07d3b1094118", + "0xf64fb1f4de6f01317e242b1198802191a6cdd39e1580d356b9e5442adb69c8ab", + "0xb97a74c8e47d37b3ce7c12ba09b53811f23dcaf4a8d260dd370f45e9ccbacc3a", + "0xf118ce791474d987b9a8d3290be077e8316a6fa3bfcda3600e6c2698264db37b", + "0x547fe45b0ca517f898e6a5fd22929cf533911f505e15de083a5685c8eb1ccd0b", + "0xd74d307e3b5a166a64056f07eb85f60fda1d9c17368a96afc6f8141141f85c86", + "0xa315936672e2737800c6d51fc22b56d918126ec329fa7e1ba5e31af36ea4f87f", + "0xe928505d97d673588a68a08ba6e2a4bc25843592598988c1d168d5c938e230cd", + "0xa6bbd3b96bd66597eb68c4059203275421a529c61471a69cdc1d2d9211aee400", + "0xa46efc7ab47e7a0f57a54203a039a4339d992207b31bc707eac98ade8e8f6fab", + "0x46e903455140f009d1f7e9d224ede2e29d1fb3f72cebeb60dfa64ff059b7ff40", + "0x1eeba50e5530be85464456af3ea0ee38855276ba79bebfe305e49fdebd0dc97c", + "0x30e149bba2c3c0db9038c39871325392bcb41169106131469b6ea7994c5d8d03", + "0x9503edfe4cfb20c38ba2efef043ad824f2b17f39e2ace445fd9ce73caec93c75", + "0x608f294da5e0df707b97c4949b775f64ef76c055459c26b651010888cb888037", + "0x8eb5960dc8e49951c41505ce34160bbd588bceb74468a7dc0898c6744d75138a", + "0xb020dd8cccb6beff1e7d996a740b876609a55ce2041ec0e9f09f683bfb22466c", + "0x9e8333dc01746341ff7181ae95ddb75748cf3efbbed24f3b16885efd0aa19da3", + "0x2a97bcddd5f0a7245c520bbabd77e48432c39f3cb17a0241be9c62ab5d185a1a", + "0xa81cdce57af311f79ae16dfad6808b40e8ece16115978131dde0f3edb29aabfa", + "0x8f321249562fcb94c94a80679adf69aa701f0719515753932548a89a28cdc7da", + "0xda37eaec19bd44bb1892d12d842a77ab7dc5ea43ca0a1a92aaa3ffed0ba9d90a", + "0xab8c920add1f9e922890da5d92ff199b384a5f042f5eb4e3fbe565f5ca50ffa8", + "0x9f52ff4d39142c046effbe6e552500886200c9c3154dc68abe0f9e4bdfa9078d", + "0x1eebaf84ba1e6667e825716be63ddc71a963688f47227e0d17d78144c820e17d", + "0xd2c2c19eacb26695c89b51b75fd616de5c769d0c7169794057575e1dff3800f8", + "0xc5ad683c4beaeb409a68cbaf81532e4edce6f64b60853725e493ffdd93e69f7d", + "0x768303ceca362b8a3996a4823c4d64ea4a4ca5892e91ab0433f2917b96486806", + "0x88e25c3ba8ac976c0382344f4a8fa310bcfc7f51e09efab4faaf222cf6dc5d67", + "0xe05f9dc2db75ce9b0fb59cf1ce12581cd10910dc5b91d744791f564bbb87e176", + "0xd75fad017be9f908c431987b10f25526a9c9d346118901d7e0b84e74a44724ff", + "0x83cd50c6634e2edf21044fe789e82850667862be407faeaa90f9bc3b0c60f9ed", + "0xdf6b6b1134dbe14a48678610c630ba5927f3d75d45d01e56534204b87ed575e5", + "0x3e486fed8ba04ace837ba81d61086b3443ec22a803cffaca18e10e0e0f1cf679", + "0x6b7c8f5e560ce6b6eb94ff8e4f811b06f2ba91048ebc2440e25f2c44eff4e637", + "0xa7a92f9396380b5ce01e3666acf035dc80a297448e1b95530b9a8bd9eb19496b", + "0x7df4150c891991e89a5938c12bcb4e4ca1a3bb3ed17e1d14930e78a3b7287cd6", + "0x9cff0374f59c5c0a8b6b8db636387e0d032922e34049356ab00ffa3f2cac8f23", + "0x85a5ca8ea29b19babb6aa45861de2cd9e44e31ff13f7161ead44139e6b2de019", + "0xe418e0eba34f07d10ba270bf4316b78b15c49d2a920f3370b403dc584cf2bccf", + "0x8500b89c737ce038eb99a443d4ed6dd02e00ab06c836b8f03de3e713e485e99e", + "0x0f324429900c3bb11cf6a0c4099148af93d8953b748fa8974c7cc5d942f6f36d", + "0xaffe95fb50dab84128becf268413fbf2c8ccbc2fde2b6f6d8bdad23cc4ed9312", + "0xcb93bb3ee92074161da7d6345022f415accea11b20c412cbac48247c64d099ae", + "0xb5044dbe63680e5fb8479f899caf746b778524a6c6ef3f56614d3b9832cf0006", + "0x1d9eb2e2fd6d8c78a5a4125733cbe69ff25b95cba736f63627bfab166f736c18", + "0x4bcdb35310f9e23c6b952933f3adb4adcf6b43dd88dcbf80dc2d9ed4f8cea505", + "0xf934917c926b2c975bb0cf0ee0eec66727da942e06c65ecb1e168c015f957a65", + "0x7375ee9c763fddfbbf6fe47b1db34faded65f5123dd92ff469d03a41f1fc47d4", + "0x6b4e2a1c3ad70f07688662e228faa861496294b068e21f040edf90cf9d0230bf", + "0xa64458a7d295ff66658de59d0f166a55dec1f9e9e2be6fc2a8ecdcb77b72509f", + "0x4e50f8712edd21e913834cbf4f8d6baf9b371f0d4592a0c6a11f70a8e95ccd26", + "0xa132bb777e81aa07f8d5a6696e3ec6c800a1c0743a946618d04df4b0668f1c8f", + "0xa552543fb7ce61cdaba1d077338aa31a6b69cbc7e6af69cb5443e2d4e1393cf8", + "0x05c451fa47938025e4fb6835d09e9a92f2db33cc99e21b44b98a1f3b0c6071c5", + "0xac9628c769038d220a38801a43aa1449c24b2277df287b04ebbb4082d1763f7b", + "0x6d188b8c97ecb2e45ff51e573fedeb95083b40c8ae15042289753ae65caeb681", + "0x0de60d18d4f052a11a584be1c4595430ea8f5c943dea397da9af2d27518e2646", + "0x02c7e9849aeadc3011c2d36d4f645aa0d3f23a27d19a8b7eec61e2ee723dc675", + "0x2c974900dc848a8a0eea1e248aa0e2469037038bf9c0768e6e46d2781530ac4a", + "0xbb4b7b7d9ae81c7784f6a8e7c309f30a9794f0240562ab889d4113bb1e775697", + "0x463ece715ed0458cdd0f12cec6ab023fb3a3cbf6eda4b55f3b4115921d20df52", + "0xd535c260190be6f755d84d8812697c8ad8801533b939dc95e2072e2f39066564", + "0x7f3a0e061e646047bab6b8dfa88b092ab003c0e84240dd82f6e7d407bd5a3bd8", + "0xaf4803ac72aa8419999b383e5765544cd61b5ca0071f7dce952d7c24d89ff8af", + "0x1c53d5aa090bb88a8302fefb12080eba29c2f9f198b08b073587049159cf4245", + "0xf71ee084795fb52661d5cb7957c7e710e6171683aa691412d5c816a764f61f64", + "0x9eb207ab5d1bc7d1a44afcb2790f32d7c41f1c54a17b277dedcd8ba1e63eaac5", + "0x2ba6c0454e857b17903fbe79d6396a472216ddd825b81d70c696074291e71b1f", + "0x899f295af86c53f6c27e75e6cb98cf428a5da102be6dd8a8e2e59b446a086a18", + "0xcda6ada90684f614c967b6fa4c37e6159522e2dee2fc8663b6a8478be5238165", + "0xa59f5518f36b97d9fd077f736de67de7856d515f5146d5b1ab1b2a36112c6400", + "0xe7265df96658699ef8781fba631750ab18dc9d62c0b24820e0538809d046a2f9", + "0x4d9fe46ea3b33b6e73cddbadbf8bee4aa31aa830c4a1abbba4567f21f78a014f", + "0xf5d3147fbe7420f7c55f6b06e045ee7d2b2e0ac7f2040ebc8183ef24108ad70e", + "0xc8dfe6d026040fedb27da79dcf77aaf83fdb008792c6366256d5988e356eeb94", + "0xeca183cd9a46eddf04e02e0a82fa295b1f56322e5552a7c7f0aad090d209b9d5", + "0x8e26a0ad84d0c8b5e64b8a57eebf3bb86bdd02e24f24ac95c6222959638a3037", + "0x5b1cdf956d672b244ecc6bd5a828cec7b80867a4ea2a547cf7240e39793cb5c1", + "0x48c8d0fa40f9f6a49fc6378152972b85cb984ec221384484148231ef88cc3a97", + "0xccf14e2b03037c17bd6d47ba41460aa54c826e945c0132692d08140f156fd115", + "0x331791c82f8717e22f27aa77b7530acc83beaaf9536cc74ddb90533327c5072e", + "0x6c621acf6c972322182e5431049874a5e78bbaaf1a3f49219fae2c8425d6b5b1", + "0x5bd86b4984df838b2ced1dd0f3e37ae19d52ab1002a8bea859065f8cdaf6bc38", + "0x3143ad07e92a4b2a24b6482b5502ce98d50df46923ace4845ca35e0948090363", + "0x66e2d61040285db2e895e1aac42b69b41f556e6fa82116c1e84b49e67478abbe", + "0xe4f3a6c6761a3e17a5a978c69d0a6688439d4d6de3bbafd2b830b5066d809e0b", + "0x034280d368d7bcbe1f1cc63bd551c3ac2406f612f8f04801d24f98d89e75c444", + "0x2b9ed64e419ea19e5dea807dbfc08b8d21bc13903e8888aaa15741c6c0481440", + "0x72630a380871aa5ec67bd06bd672fb0128b95499582be5d34a4073645d15eb6f", + "0x9ee6618d35b3fffd4abeee984f1e9f3fbd200e5f60c562cb0ae3200b8963f522", + "0xbb40172754ef37505f4ce8077382eed0c45b0f96c882ac26b7d209b951d7cfd1", + "0x76e973e45252e97e2cb31bb8b79424e5391c3e76893cc7be0c1c1101bbafb57b", + "0xa4218614e301d35b94bc536160007b9b88acb5c9987a44a27c514f6456b28be6", + "0x0227fa09131444917185f2cc802ed389687a4f968f99bb221148ab7effd5fd5e", + "0x0a93fa4f9590996785fd599bf2669b290e8eca7f02ca06aee9582357293a8493", + "0xe1a277823bc99e602027fd18db67550f0d5e60045b94bd2655e49531bb152f0c", + "0xfe8ac01e4e478b4019dad76813449f8155de23b4ba2a6e2091f4c8ba82508bba", + "0xb194b4f530b832a2ecdc88c1bf40580474847b91c300751c810bc5cc408095fc", + "0xf1de598992e61dcc7bc9e1f1490d80d10024c6319954aadae6a4df4ac54ea564", + "0x38138e224065ad8ed4af813bcbb35535bea444f99613d686f0ef4ff00c5a3fe8", + "0x13e6a7016f28c856d777e1a7f54bce788a3e21b129cc1b57d8e5ec21e6522d3c", + "0x1c5d57d845f18557e61b1b3761d9452eb26aed8041a4a3073097259546e2045b", + "0x536848934654d65ec83f7cf9a0f69adec6ae974b8e5944127ca819a30a20b012", + "0x1653d5a4610454d67236e8049dcee0b1a531e25d5c7f0bbce913a6a524a60db6", + "0x7bb7bd63c5985b492c4897d59223335537ed0f8928c5c7383b5ca7a6fa3c3cb2", + "0xe4b8e08d3444b8e14e390e219684a6085fa335d11c1c77c530582e2c3c4c8e55", + "0x5fb6b09c1ac68c1ad0fd2041c27f1fad5a83906d4aea5af0f965cf36bc3cca3b", + "0x40034a02507258439d490a5a282956f9ae304b4ea4730ad6386005c767eab5cf", + "0xec6ae08d9c0033901514ef409a7cf68e1a682a202dc97c5c467259c7b6022e2b", + "0x9082855abacd99a2b634ad1f50d8517b0f1b091cf5c649ba377aa3ad2eccb65e", + "0xf76c0b9744305baeee70b1e274f7eaaf3670b2217fff6655bf69968b5acac517", + "0x917198a97cb8f704471f6500aef3e6f014b09e8da719ee03e87f45c95605f2ae", + "0xfe1a48d29d6ddaec284dc0bca96cc874ecefbbb91b74c8ea6030a9bf80470c73", + "0x9ba5c60cee1a7d901f9832e3024ceb9db24460c6636b98df81d008d1678073c7", + "0x7cba18b1ee4fb25f1536708ad3f4c95c43d60930f67dc2cfaaffaee2f91fe1d8", + "0xbd2b278edd0e75c6a39aa2f43b334d8cbb52900c152b2b8e3ccf7f27221c0643", + "0x65c3a4efdb5a189b46db8b8ab60968f6c16c1b56f9f2311b3380c275b7914383", + "0x45de07d3860d9be6f7b90dfa928cdf0da9592c2054b00b774ba7608f3d99324f", + "0x91a4389a9bd65f3dbaf092a5a49f0dc2333bc5ec7b59c3a48cffe97ba52213c0", + "0xff9342e526815c132251c3202d20acaf0012be44ac7c47f7640f27fb6f2d249a", + "0x48854fe3580cd19aee63f0eda576f1af518f3ebfa9f87d24da87a89ba227acad", + "0x8d292c2072d5ef4f3ab12cefaa60e9b54433a0eb7303ee253408c19394345a4f", + "0x48007c06be01f79cda41ea5791e3ef4bb4e946d7af262b52cc74eb3e20e98a1a", + "0x36a39e5a3035ed57c8227571b2d57317ace61cb9c66dddde57a566d34eb7d894", + "0xca4446f6cfc51f82ded4f4c798da29fde3a3bfa1f30de6cd721ab459e570dcb2", + "0x82812417102865e04fcad17c1682c7608cfcb855267b4ecb8c1e0666537e6a9f", + "0x81ef7d9794f8bec6b04ab899cdfbf3ff735eaad06610258ef7f90c77c83d5387", + "0x4810726311224ee42f1969465daac6f12516fcbbfb26e9febf221fd8d1cfb41d", + "0xb39a309cdf26f5f2011a83a0c1840b61cc5bebfda385a479a6a20d872bd082bc", + "0xe5002eba07d8b69ba9470514d286ab800d28b443531349d641d9df57c3cc1399", + "0x662dc062bcbcf4f45759c85e8a0ff833564beea1ff3894d7c5286133b3615a9a", + "0xb2cca2f7a62870673c70313efe23bfdb57ff9e6bfbb9e73948288fa15a8a2f49", + "0xd9e38758784261f67700452e23a59ab25cf22dcead205a50685d5cb03442c81b", + "0x039acba436cc8d99337c16969a076577a50d609cb2986f42702199e3c2dfd8e1", + "0x7141bec6010aa3d5ad1d543f91a8b10ba3bdab7625fec8a7d404238c09893e48", + "0xe0a2f776956dd92600ed94088b7da0aa416ee83cef35d37063d3df2d3442173c", + "0x7e099f882fa8909a3f67cd5950346a00a20bd0678e7ccfaa03395bbe1a7bdb6b", + "0xb52e8fb670f5386581c89d4b01b0bec691b9e828c9fd8916708287b6c1d49f26", + "0x16b599c31ea0a2c2c23e2845cea74c73fc892f16a2b34091ad9ffc5d03e7f609", + "0x4c04bcbce2e30cb9fa64e6c776c8be2a4cea04512c9d70e2a5d8a377aa77ba76", + "0xad1f20b7e161337e3d7aba00d9dc3585569cd8ca932329b3df13fe5f23574f70", + "0x2961a4a19bee2dee47d9eef2f875e03fb75bbfc30473604c902e76c76620507d", + "0x666c0d915622aba83912b23cf5e48ac57219a8e592f09f9e224af94ed35cac7a", + "0xfa6e99ccb3460635ebbb7ba53b332825f9d5185dd10bc1e2eff5fb6de4fba746", + "0xd3bc3b194941ea52e2b31ac5ea1c789233dea804e24c15000332d41f8bb4a8c6", + "0x07281b9f1ab9e962d46f05c76f29b4f4ff3db35baa777c37c5dac6cd33d49a90", + "0x5bf61ee56f75630605881d34c11fc029f7c2eb96dae86c7dde18af8e34aa6c77", + "0x972d651e4903b97eabbe5a58440bd248eb2ab16a536da686a707770b88612d00", + "0xc953d9cf8cd4a68d7a2d9dfdc3bdad8bd0d511f63cbb2144af7227ba49084a71", + "0x9a90ca2c4dad5386cd71110de906f6d96f80934661afba440ce194e44e5a6036", + "0x8dd2c27d9b327b1a6e2216f561c09c276c9db44c3a87e6f8fe381d7a906c9769", + "0x17362077544107f34233c1fad77f12c9140d0f0f0a5206dd887bb9cf627a20dd", + "0x52afd7ffe299cbfe5f418612ecf625ab1c6debcfebc6bad2569c3b83aa1f9f55", + "0x6597cfda3deb8371e447690b5f90df042b72095551d347eb77b2ee55868634bd", + "0x97a7278a76d38714f16a5b3bae0910b18d2851b2519ef5dff0a791f471cff90e", + "0x0f4124bc20c9553612a8e78b90c80c1341a3a290054c75326753be6a103dae22", + "0xa42039e0a42da736e91ffbea82e58beaef7fa7d88263764611b73ed4775e222f", + "0x13f6c5b099ba6a2ed4701a8b3edd76c2645b68d9c2cf9af924da39bbaa2c18c1", + "0x939ddea54fc48f8c8dcc1ca6c04ff2cd70fd8da9e93abd3ed062da56b75a1110", + "0x3e66eecafa70c79675f26d259fa6718c646ce3828e80652134b792f0366f0c68", + "0xcf507596184c9c4a14286412216f771f0495ea5780bc372d12ba6e8445c67d69", + "0xee64dc03e5fa815ea5e9e3e4d2c87126c8e4c0ff56f1152c349e3f9327fbd5f7", + "0x3b6ba90d23473ab15afa76d95b23b2a86309b0d6e2edd3492c374020e544c820", + "0x51ffa382078573a9bb41ad67b775074ae41f9968e2b38341ae9a64a9f1f74815", + "0x6c3a7ec03f93b7d4b73d8b194ab38a23b512a236731b5e54b8b5bcf44aa05608", + "0x0082c925bab49c6ab52f9b996986123039fec2cd6641dcae3e3ea7d60bd7a2e6", + "0x85185f7d346260f24bad3c767a04bfdfb3356f61138b9fbafd7af0f813e1ddc1", + "0xeb5a6ef56f2926a533d3858eee37cbfb5b37e8fb5bd181cf61448e36d8b48dce", + "0x700da1f1e9339d6d55c54c62cc5523c30901162216c2f182f5f2ea66dcaf9620", + "0x84161dc26196b99ceeea8d64f6ef3d127982b934f49678f6a512c07534e8ab54", + "0xca3f434ced785e9b5922b625e1d2457b156372e4917b9d6c8f4f6a995182a176", + "0xaf62ff81c29e9102077eae515015286765592d454c8e15b0a302adefe22e998b", + "0xafa0ed60bf7417e6f74fa7a9c10ab7c7b0b1e94b699569b0e3f70ab01b234ebe", + "0xd2cdc3211869e030c3e291f4fe2f163ef54b24d7ff0bb4489d73a5159ceb461c", + "0xd74c2a92d3c506bcbc11c1bec086cc419fec1d0bca34d50b74b28f89e86cf864", + "0xcc25ec627504ed9f00af661c72990a36a2f9ee4c4507e5fa4def89303456d7eb", + "0x8edd1c1dcd064b7c693c978152209761cd6c92e449e9444e9dee807fd9f9f420", + "0x660e691453e374d0a584b184a5fdb85894290e1ccc68964a8292db53ca096505", + "0x9cc340e9d997cc319fdf2e00c75d80b80953a90049af766b1a499846c5e08bc4", + "0x58e650852eda00e55bc2d9e024a49b3b7a5d6d5092d837407114120ff143b75f", + "0x5426eb6b6b8965e80dab787befc815c6c430e80231e91fee5511062bb21c3e4f", + "0x4bb9b4512664884f7b63bf27ecc75e0a69e32cf2b980a8b9135e410871ce45ae", + "0x22438f10926c874196f8c65e274d018960cedb55ca43787e18adcb54631df7ce", + "0x68aca6a2e6a51c8543939fd10be02784b1149923652da3f07f91999b75be995a", + "0x12a77edd8cc051f6f991cd3912f5f4afa1e797f5daf010ab17b3925220b12e88", + "0x0d3b929dc2733de2865dab86cf42684e8430c2ed47d19606637f932caf8d2d13", + "0x69f8d5c233a251c35851354b8546d89c7c54012736440c8965c256cc9db7dce7", + "0x6757e97aa449d7878cbbddeec490fd0636b2c51d5b00bb61eb4836685d005d2e", + "0xe1029b22f6ded11ab5ce46aa2594ca90006a04e8848f4152fc40c27735217ac3", + "0xadc4af259ba86cfc93384f3c0eea61a4b661f015209064254bc6ecbcfdb74f5e", + "0x02ff4bd0ca8008db90a121deab0c36e45bfc7acdaccaeae04acf3aaf51716607", + "0x9df6ebb38ba3e1d0a3a82f871bacaf81152bce32265c0eaebd9d9e6026665b43", + "0xc25503a6058ef394c48d1153ee2e70a3d8e86e0a46b29ddd0217906d694a71d8", + "0x83698b68d762e75476caa87411797ebc0050f9296ec35664bcfd3aeffd01d8c6", + "0xb185832a5b8fb209b9a6772673cebb3dcdf3d915886282d6adc47376a48fb578", + "0x32ec2d0710f9681d75819f1e2c28e135b3272dbf1da08e4d64ab2e6ae1064cbc", + "0x13c8aa9abf04b6ec2553b171b58356a1c256563406ced1ff3c84a3ffdfb5c1d9", + "0x80aaed5609e1b594b3c54403ce9977dc558ad292ec472ac73c8d7f39243e116b", + "0x8cbee772d46586087fbbc9b4fe2f54ce2405d2483572bda3c2314e79ca0d8deb", + "0xfbfe6a938e7bb9b05d889f8182e8963344df0ac7b9022302b451b036da261f9b", + "0x39131379b64eb550fa0a2574d504bf7de0219d50e6d55cc82998ac8d2684df84", + "0x5fefe2fe1d509eae61cab218f1bd03196b1e631f5c416e5f2c0e9e54a3d44d98", + "0x5839c1c6580a4c04aa09dfde45ce4616b6f30d1ee794dd12fc745b96b2d48c84", + "0xa75d2328c4e63acdda579000e6df9be72d9348c2001e1927264b1a8c303fd292", + "0x7331a0cbfdfdc200cbbd1723bcad1f1ca6e0591c1ee025bf1842d91e4625c8c8", + "0xe9153c020aedc51102bb9b22a2493db4616364fce9b61681287dabeee881130a", + "0x53b7aad781bea92a14b670dfbf5acd8a55d2721a6146f099b904bbc176771b91", + "0x0de55190007ddb76fcb57cebee9b1ec60d52d150ac83beb66b088a86a234f9d9", + "0xc703435d06a2e1c5e52789daa3587b920cc2aeed658907bb7d6442693c65902d", + "0x6d21f9a28fd36d865af468e2c06ef5f41167f3014251a53aa1d2ea55896ca1e5", + "0x6b24cd5b8a48fd9dbe7e8ea6c492b57f3146009daaa108ae5d1199261cfc3914", + "0x40e49643d669f497785df1e601cb1bedc24ca348f86354d4032b1d4a4c6776b1", + "0xc56f0ff0aa22fa1e19d8785aac33805f7a7a01b48e953ebb126a4728cf502518", + "0xdce90cab31ee9f5a345d03464c69cc5dba71ee601bc22ccc8aae1eb442f3b29d", + "0xa551b514490e45b6669024b539f7bb37e6883ec97ff79744cf1f1c2ba1d21ec7", + "0xbadc6d33cd58aaeabb8b62396e102cdcb6b1ce9dbbf7051f937a890a3f69c2c6", + "0xe544b08143014287bb8d917f66e8f22f2a6deaf6ad4a3996426e2186b8bb56e0", + "0x6ed9b64beac26a5fbbd15c09c7eff96652b710670c2ce52a6856cd998521a27c", + "0x48c14f31b1fcbe0deb7816771f962cacbb7c2c219518f3ce52661a89e9928228", + "0x425fc1308118e8ade59df07136948a210786f8b2b6b0e51ea01ab06653822693", + "0xee9b2ef0dc1dd873a3ccdd77046969a4ae938e5ff39695b891c85921883c3277", + "0x25066a1abffdd64dab20529436c3d9a44e6e837d70b19847e355f63b5140c5c1", + "0x7441baf6efba832751b31b93c9b000d8bf552d0328415937d0a3c78595961ee0", + "0xd9219e7f07c0808d2596cb57e26793c1162ea9efe58305e3a26da6fdd57091cf", + "0x1b42d745a54c5e3c48a4911a27c263bbe42c8f038c826975749c1619c2e21cc9", + "0xc5abf3dcbcee854b06836237de3a461d86a8b76e8081926ca3078531e25556f4", + "0x7eafa90a352f95c8eaa914cfba0aa90db5ab1275d966da5fa445d9dd6ac6e0e3", + "0x4230ac1a58e4d9903022416041d5119991f911b41702d43c1caf0723cccb1d05", + "0xd50f2cae10a5cb3084c9f5ed1f9acfce8fdf3d920d89ef41165aa2522b97582a", + "0x6eabcebb9040f7d6791a0a560b987288d8246db9140b5f188c34a6be7fa17552", + "0xbbcb3c36f228d2589cd7097111ecd708e419bbe034ee6d9aa691d483590750d3", + "0x72eded80c21baaefddc61ecb70ab76cfc68ec8509b4f8786fcf25d037d75385f", + "0x2a01f9310e3116bf3527cf90de19bdc78d9cc677ef5c9bba94f3ec321d700a7f", + "0xfa401d300fed7092c91232a2bd8b0173ddb62b12e8e96a5076172abcd44ef858", + "0x984001b77e32ee2ac8d5678f77e6c425e6ab9fb2ea3f4978b6594b4499f893aa", + "0xfce80ebf8039984ced85b45b5ee5c240df0a6aab809d6bc0974a5b1007c77d4f", + "0x0a964a69795de761278c68843100ee547edea07d790d2efe64d975b65d415159", + "0x5ab1dee36283fc991e00fb52079c232f2d9bfa97377addd05c50fb06a09c11ab", + "0x47676449956192bbed4235f3162d06ba3095aecb9f57d9c8a273052278582fc2", + "0x4e43d79f07711fd4d4a8dfc576f08d954b5d6829dbbb59ae4386b34221472966", + "0x8f5cce2a573190694302db226a2b22a89f4487a4f509ec1a759646d0d5face7b", + "0xe10a0419bb270359d2c190014afc1fe52f8df9454f7a8e0fe205309e5a3b33e7", + "0x4626c976a572110230c540dcedce33a5bbb97919867aaf0520128ceec2e9d8f3", + "0x057b497c49e4b2ba614280de64dd91118172ae4b4646c3031a93fce200c8a234", + "0x8350ba4e211602c38812276000b1caec40dc4376176afcac43eaa96d7af30d1f", + "0x9e93fd7b9b9ca98f26945dd5716ee2a6274f8586d14f05854a0f7f25c80541ce", + "0x9f11403407548c359164f3f93265f12ee390ff3b3631ec7b90b98922dfda2343", + "0x714cca7ddeaeaf302fc0ebf50fd072c89f063061ea329e67c809d62ea9f5fed2", + "0x9c088fa9b25f7a5ca635db39b3c95da6859a5941eb1ae3e4f4717013fe740cba", + "0x634542af50119e4adb4d72bec5d0e3b095df21e76865f683346e1bd544922f69", + "0x2a1fdccea29581063da7db3f2aeca7087ec646b11f1d47e6d48d1dea0122fdb6", + "0x156e283ab987a5da12710b459097b5fe3d79db296551fa289632c0d3f9b33ba8", + "0x3eaa070ffd835043d4b2b25d5e7280f030c615b2bbdcaf3ee12a2b2b4c620747", + "0x863d5bddbffaa9f0ef9f696ac5a7f91191b5cb52383e1d0c0e0d5a60332c8728", + "0x4e29095ca17d15099abb1c6c1eb43cdd6dfed160a7d11731f4d1115beaacc7b1", + "0xa46f6ce03354ca96ddfbfa9e1406dc7ab99b0b4ff1ca5e0346f3ce91338bafa7", + "0x9f19f494df488b250ba31e243c9098fbb7db5801a3f76b219d866bec32d009d5", + "0x763dfe2f87eb816d1bad1ba95448619041cdb3cfb1171063c043d1e02d9f6ca6", + "0xf8ed4dc0fc0c03b964eede54ede5e96a940cc85e1ef2191c11465f2f1e3f6f0d", + "0x04f0d8ff18d26b490f137f23144c1ca0e475e74a7f1599fd2f6a4972a3d1c215", + "0x012ead673926ef6b3d2cbc5332a7bbe5dac977ada6065313e90975360dfaff3e", + "0x773ccf0a297a22c43b29f1bad214ac9e3685a5d0bf1df7d49fd4b92065ee7b04", + "0x10b7f56b8cc84f4be7533ec00ae46c7ba852f8d093c889b7edd46d36c819abae", + "0xd70605a437bfc6a4cc3468f0eb6d59b293d4ebbcd7979eda36f02baa48e68d25", + "0x68a93b7685277a1ca51a341517d10ec1f03c3018dc4d99da00624d4eeb3db229", + "0xef8aef04d3b7771e8519952b4e067503abe6b2698411299edbe7dc22a79c39b7", + "0x8e72feb3f31eb9f13645a089efd4eaf6871bec26a9ee91452db0464a7e6bc5e6", + "0x3189fb0be615c0f2e2758400050e2657e3197546a15039e595b091cefc9e0d7b", + "0xfe444b821fdfb12248cbf371192783e4e0ea0a938f5ac7b205e15cac991b6c98", + "0x0329c441b6c6c56d76de552ad43596760d37262011d97bd91e595dd559e53de2", + "0xbecff3658ca19ed610e826a68621e7b5cf2ece293ff13fe3f0c57c3390954af8", + "0x695b87703e7299f3e862740bbf47ebf026e5330171509fa0927c361935ff612b", + "0xf90373fabdb83b403f67cc50d79aa37fc26d73ce8fda798e96c4a4b17440e2cc", + "0x536eee69a1cf54af816f4eb5d08ccaacfbbaaa165451d0a5e8b93b2e872c59ec", + "0x17b56635255ddc2278cbb7e7139cf7a8f6e2e55581c451cf53b5b53aa89f985b", + "0xb4a14da295a0cc51076c48032fc1cdbaefff2380a428eb03f6b068aee99a8fcf", + "0xd3cb3797197a398711299f816f34b7c98aafc8a845298287b4522cb0fd645b01", + "0x55aea7b1fd7bf0864b577e38a89c153ae8653da26c72f53a05d164b9da327a67", + "0xd4eb63ebc06549dd7419012d4bae13890716430efb843175a9270a6c517ea612", + "0x6958093bd81e477479a53443b0c95c11d8791b282d028bd9a6204af0c1f738f4", + "0x505f55a445b93a2ba8d5ac5531370e2bf760db44509f15d2f243175b12a7016c", + "0x4608a060b7bf832310eb73a157d285ad824b07d78bb471ea89ebf421d735d566", + "0x68c88d220d8ac23e19459d650594dde939aedcd75325ca2314b7a9419b938c37", + "0x891a1154ddc1e3239b1100840e1303e0627a53ad501996e56891839b54becc93", + "0x8b943abf7a572dd64da3c4e58c1f34f6f7a905fe7ce652a044ab8983ac45fced", + "0x06b07efee0be55002f485ec0526336fec4a7f825ff7eda3f954e8cc7068207f8", + "0xcafe52ca4b5198fb4e4e24f4c04ad12eb8c9f3ebf9a35ebc0014e25dd7bf5970", + "0xe0ed792746b780ba8e19ebedfd3922ca937fd5b8c28b03e0fb91789cedc0fafa", + "0xfd7ea98fb764223ca3c587820eda0a0d68301979313ea9cf0113508a05fba7d6", + "0xa874e6edabaf6da36996b6387bda14d12c3eafa026b1ca6ad5f1f4cae67855ac", + "0x29d7c85005517eaf1165be4921deea5afdae1f66b670d7de0981c4e502acbf1d", + "0x949318f8059937f207ea564672c86943c2c9bb86ca81a3b0a9523e7bee00a5b5", + "0x200dc199c37d16b25e207165c5576596266ce8b62aa8a9c6cd66d69d52c1a67d", + "0xd29108a106a8a5a87b5282467a0e8d37f74c2ae53e6dc11ad63005f3f3f878c4", + "0x44ebfaad5b4ce81fda3d4194c87b46e9e31fbdbf0ad28fe00cffa73f78d3957b", + "0x6843e2f6d3d56b55251ef7ceeb635226940dfdd698215f5d5a4c3e88ede5c0a4", + "0xb84d57422889adc19626aad033b38b6968aafbf4c6d0881a0ef5fb5932c6ab44", + "0x842626b82b93a54a3a1765ef6257a0c74e1ad2981d8da41fd8305adbac99bc76", + "0xeb347385fa0bb37b8d5d17ab60e6c2ed4bfd19210503d61beb88b71d8bf9adda", + "0x509a54bd689b7011504e835081bb9d3cbddd8592ad80da399689bc9172b48a27", + "0xafc5c51176c7222097b12310a3ee5513a7660491682ff1fcae5d168d2c19c3aa", + "0x406e9fa3f6687fa6519067e213377a5ff7875f6f0a3080880536ed395555ad30", + "0x2624c181d4ee1775bf687b522a36a7b9bb754ff6e40ef12363c7d675b60f3d04", + "0xd5c32eb980158772133a99d0af96e056726ed89be84289cb5fc1d083d48cc407", + "0x7b1c5cfee09aba12ae0742d9bc1cc2630bf8c1e141033b18724a524c2c1b7c2c", + "0x77b4b55b236cb7d27c77063a280eabbeba0d7171759fbf851f40b6ddbf7171df", + "0xa04791b79cad41718cd8a0bf604b0e956aa85230381070f842667d88760c0de7", + "0xb1558e574944d9e8910da9c34ed51d89caabbf6541f077a55ef2ae3c513a1e02", + "0x3ef8620edf05514c4e90c1eeb0a896ef30573f963a7507ee90eb76e4334412b3", + "0xfff99365402379af3e56fc9b999d316cea7a1f388623433cbcfef0ddcb6f9d4a", + "0x99fca466439472d08ea602bafc67d1d097e486b5e41b5a059818021f612e889e", + "0x094436d10026f1c57f04846690a0444646b762eef1fc0420c6e3f5cf5b845e14", + "0xc57923978a9dffe0812618f2f6420f30ee927658f9f1615ef7cad4519b90eda1", + "0x3a20d5e138cac29e3fa031847086bc62e5f90a5e363a70fd52e2602545faf9ec", + "0xf3b0bd1d597eb2b6ad98fbdcec7dec2639b92bc83c33db4fced5d23e6ddb64a2", + "0x0d5bbdf1dc7d52fddbb3e81e2d757b848f9e79b6847ee8d30352d4b01ba927f2", + "0xf8f51ff9cfdf6b2ad5609a68433c012c92cabeb3053335d784b1baac087516b8", + "0x5777236f251506c22a92f371e4ad3c78bedae22c4527ed5e796727512bc2b8e6", + "0x228bea6da7246c2dc862d9de97bbf824df6396cec583a4db71667306c5f6a02b", + "0x67ccfda86cfccbb139d77d8d2acf0d4bd980b507acd9bfdda6b5af6e10493df7", + "0xfd8f9ab200dd111c04803f62145fd82e6a79221776904be20a90c1c6328cfdaf", + "0xcd8ce973cbfa8a91a55ec09ac9acad4cfdd050b598349b996d252ecb3935d277", + "0xfe8067acaad74db589275d3122d84f04f717cfda870d444872824300ea10f969", + "0x4112ee457d4108c37121ef4ff0ceb1a4c7db3a9e3776d647225bf0838153356a", + "0xadb045193cb85002f2868c1ffd672bb93e60ed2841ad368bc8399e92c996229e", + "0x4243b3645b99ab1468bc421309220529d8ab204542c6901ce618ceb32b93becc", + "0x434e3c4da46b052402d465220e27d0e243bb5b116967d4baffc9325e326c9900", + "0xceeadbd91caca5832cace1624baa5f67b0d18f725627702cbd7e19ae3c691712", + "0xac54af2cdd95c862b3d9115c9550231f75ca8d6f6e607038850892daf1dd6643", + "0xc4ff21314ba2cac393c67982362a39b7ec96192fe37c316bdd4cbc692f729ffd", + "0xc84746b891e6dd8aac32b2ed0b373172df4ef375afe7e4ab826532b6b3fa9680", + "0x0b0e01ec97c12e488829d13dc1fd420c08475dc95d1fcd72c066d76220af055f", + "0xf0b54fcb4a3e075f391bfe937dd6b4f7481877182ddd4413e8b70efc63aa7f40", + "0x1a78c5cca33184c9e404a05f61cc56968b924d9d34b7ca6d573563eb250fc691", + "0x37ca206f795c02f45abc34380d67b15aa48122444fc444d4b307ab2f7f30a9e1", + "0xe03c444efd29f8d7c89b480ffbcb996a642ac6205ae43bdbb815ba1968051e36", + "0x2fcaf6ef7c22cebd36ccfdb037e66d9113d0965f3b5b89d597d91b490019471f", + "0x11a06d63b3395d09a048aee4d4291c0a6ab2d5f07a7667362890ce647153c2d2", + "0xc33a74c178ef5460b53a9a81aee02d3b42612acea7adb853ef74cd6b65f36efe", + "0xcce38b309fd919a930d38c7c7a7bc828e5039c22a7f3f858fd99c5d44b8cdb2d", + "0xc470e1078c305a5eaf7311d7ff652e24c9dbed83c3572a1c2ec7f6fce5788b0b", + "0xa29b6d0bf49a64182aebecc190a9a0b06931096d9984e7e6da9800ce17f7cea9", + "0xab0821217488504e1c255343939d109353c79298b04c69ff65152dd0e934022f", + "0x40c7bf4dd5a2d39c0dff9fb3bec5c8247093cc1bd55a8087d83f5fa7c8a35b31", + "0x3387ef8b199a2656c39407d503b9bd1571714e178d1dc7b1a74bc43cf88ca201", + "0xa5b2b8b2d708d97666281684641b611efc792f7c0cb27e053eb06752661b35f3", + "0xb604a4b7c3661098d4644239295cb9f6e456854651a5b289a2f4b65e33964232", + "0x4bf93500c257f054e6a6f993f344917215c9c943589644474f5cf98950b8fa46", + "0xa9ae0b7679a65498eeb2b460fe678c3452043bafc344eeb393ff1d930dd8751c", + "0xf21e50f55d7be256d14dba4f8909879cdaa3926b03da9ffa0c63ec3c9df34c48", + "0x88e1e824c968441ebf88b31f7a24fa5cd4e8985ec82fce5eeb13b3a30845e146", + "0x85d5206b3136bee840dbbf8d3d2302694dca2d5397aadcc34e1c1d6accac0354", + "0x00f68e845a2331a0704037d75361831d5a0079af3c6186ecaf256bf1da923c27", + "0x64c594c02b35bd5f69beb236ccc08140838c30b67a1576d2780123e29e073849", + "0x93f6540af637f1a630a8aaeaa86d046e09348320ca5103ebe2222f747a5acfc6", + "0xf9b4b9461b765b449191c7ee1acaad88d4dd7260e2b826c75d506a908fe71e6b", + "0x86aff1c986fbad8da2ca9de6315222459e9c47c58fd7f1a543e6719c566af5e3", + "0x68629388371ceb2a08bf7e335cde88a1bad7127990b44135058d62dfac258107", + "0x9b81d6745d5ab0a3459d26b97ab8f19fb38bd38c758a0ef106a025d091f6f9ba", + "0x2b42455bb30c387315cdf205a8a178ae4bd2d2e221fbfe4be55f5b364fe9a7bb", + "0x555e4dafa7d5d3f209d70a5c954da144ef231638f4a63715152bbfa4fbf82b4c", + "0x5d779a8f08d68794723fb5e95bafd7004685ec21d2cbae0e5ea728b36418dc36", + "0x7e5163ea9b1c0494aa997997422b02404a13b690257757f87f69bb42f81ba28e", + "0x3814efbbbfd4001641da7d5c93483f96467d55aa8b5b2aa6f980bb12a0dab6cc", + "0x431b7452a8157e3a6cf89a5a85d22127a1282877750519a8cf95e172c654c3cc", + "0x77ad2749e61c96fa868c7764ea626baef8a1bba56d3a3106e981869f9736ca76", + "0x7c069d14a86017ac36cb9007fc9bfe75ca92cd2522dcfd7bbf9d85c5133ed8c4", + "0x21dd48139667872fa67c98430f68e8d38c2948f19fff534ab2a5b8e0b92a4d51", + "0xcbc2dad5151367e6533963061712ee325f08e7df3cc7fa73eb5220cb32a2ec4b", + "0x398fa6f8d2b76d482a0c312bbf48ba8dbe9fb8ae06245da60ac68ce50f42638c", + "0x4ca92096314fe1d2d8e07aae3df39a6237e718c1396e88f3c0b73fb3124c89b6", + "0x3ae030ef952e2da7b29aacb08fc41776a44fa5a6c42e745d8b7991ff82566730", + "0xb4ef4b02dc130cea24a71a6053639238db2db30d4752dd3fcab1d98442fc3f94", + "0xa6256dc24acc6de428f47aab0b65a1f36855c7f0834a3e730d10a3c0c8d2bc49", + "0x9d8c8bfedbcf9552ba9eaa08a61846c52e240ceff531e7b19415ca148781ebcf", + "0xc6737357b53db7d2a14d7e7d4130fe6a516fce1dd0c7716be6137d93e21ceae3", + "0xafa9d3182fe6246f6c8d7b96852bc5dc200e8c3a97ce7d262a18c2fdaf5bf2b7", + "0x8064a1ee1eb4ddbf301fc983a03fa2983bc3743602bbb96d7fa6ef85780ba79b", + "0xc4616fb2fd5381efb37719cd9998c5051966b254abbdbe12228b2210c6f79116", + "0x05c30fff77a3d751853e3ae4c11678755c0afea16480a94bd99d61ac894300e6", + "0x47757d0104771c7e288f383bbbab1eeca2fc752d11989674305898e047a71bae", + "0xcc0f857a7617c16da7d35363cfc0af0ecccd9b1870ffdf1a2b2e2224ef81f876", + "0xab3a1b65f93df60eaff5df9e0bc1d91152d34d3428961c207f36ac3a94f61257", + "0xd0cd178507f1c3bdcfb7b528933f2d6227933bee2614636f3add19a66cc089e0", + "0x6379b65e140eed64020f496a95c36b3c27ea10387f78e0faccc5b4018f8f73fe", + "0x3b6977a571ac8d59bde2e851fec4384fea35a8d3905735fc8b8f2a8cfa6adcbe", + "0x2f193712529ecc908ee0a61172ec7839a9168cb424d8f108e7d7cc356bf20cf6", + "0xfa3e48832d13748aba9128bf6bfc76652cac371e49945fc33c941a9b294f7033", + "0x7086c7711a91271d7e38998715b4a142d7ec107accecf29f4518efe9f3333c4e", + "0x05c126586f4a2c1dc5814d07f158513d42282726918f71bcd1b4e0b67ee944b6", + "0xb7cc1efbf6880a60abe6b20f80bfe2ff3aa59de805ad964f8a7c5ed3bcefdcc9", + "0x64189964cba347ac35018ed9169ae64b78c3d0430145017cce83d78667b648d6", + "0xf6b1d09181b9fd18a0efa47c15631a6aa0eb01613a5fd1068834c4079e1a95e3", + "0xe760b5c16aaf587bee263f348f9adff4e04628b94ef27c828cc7155ebd3ac902", + "0x523a2c0fae8b2408ffe1c3b43e0aa7991b82336ed136e84c3f7d458d31143fe3", + "0xcc6d742b22b4fe3f41cf783a2f6f8dfc97a4b33866cd4bdfb27b05bc2ed39162", + "0x4d4ae86d282ec414a574370458c99e189062a3a48dc59a8e8e2a44790ce9b841", + "0x6fcba6a9469de1db92468f2b58b3b82c5080698aca4403ba8ecd1cfebd12b657", + "0xe7b584b0bcca0a5a119c8b2cddcc7a73c94f6f6a58503ddba7b0335815302f11", + "0xb1edda9625ea65b96a4485e10c798c707f6926e4ac2b51340a6f9d212a71a737", + "0xd8e2a94d4c0937a2033dc3b70b50934cb5b2ab54f57336cd6a8882af9f14b8cd", + "0x93ec08aaf09bd453c2b53cc7d9aff059681e0c23044f99569d0ea649cc7b885c", + "0x8ea82c1ca6be16616b62a8dbd88c75217470092063e0494419a6a926279230c1", + "0x175d030004e718f39b3986daa3beaf2e1a523583e529d6e90d117cbc844c647c", + "0x34cfcabda8b4f51cce74befb08f6a2e9ce884175f33fab59f26c60085ea73a92", + "0xd0570fbc17dc030bf6e7e3619d56ad2e866868939e4e5b23258adb191997b4f1", + "0x83245688ccb6e6f1b541930a3134d3141ef01a5f9b3f55f0321039b9d4a3cc1a", + "0xd782158768560d84ebc21d8e4f270f30055203b2d83c46ccf53ff8890e833fad", + "0xdaf31d5afb20a502b28329ecf1aadfdd16b4fd9118b10f9bebfe6f986a902dc1", + "0x0e24b26cdfc345d98a6d6dc3f4e3aa2629aab6fb2ca3820a78d58b10b09deb72", + "0x895f7a9b16ef1d1933c009b38a35a41632d00735a906b035f7fbdcaff1665295", + "0x70ee8681968778cb7da20dd794b75f08eda6b4b6e4aa653464436ff3685c6186", + "0x569f51cf2b92bde98085c2c167b773fbb9917a35844059696a1a97e378b5b577", + "0x4ee20277fbe5d2e616dc0b170e40d5b62cd8dd9f058c648e8e0d636316be7e00", + "0x1224d7eb3ae847458af472b19d3b0ddb90ce822f3389619487e68f3ce08cf6d7", + "0x57fb6d2ad5a75648449c99a46d92570b1dd74757dc1c0c11fe4923748eeb1711", + "0xa4ebbd26ed7dce135ce61bea0da82b8262d4a5319a7ab9c94527a7c670752b67", + "0x1533f0c29bd8a7b8d90c4c0755fc0b018439291566dc33bc816c8ca21269c63c", + "0x9cb5a5d41061a2168c0a8175d2712cd82d27cc777a015158c2fab0751e192d25", + "0x479f0a41aa04509beacb2eace213d9375393f583d384dd4e69b5b921c681c845", + "0x5791638640c821778349fc3064f6c5215f973f2b4f098ab38fc2138f6a8700b4", + "0xaeb1dc9ba82aa0c9ef266d1beaeeb5c756fb497607ee680c0a161b89cec21d26", + "0xb13f56956bc48a6b0760639488463cf403ed47f6d94c7b6e5a6de1d3d35800c8", + "0xfeccfb58d300594be16cbc9b5502ce851de36e15d62164317ef6e3dd9d72015f", + "0x3b218812b3219e243f99c6d23f24ba2b70e91b6a1e9bd27a5d3c83622c176b2e", + "0xfc8f86579345c5fba8e86d1263b3e9d01dafacd0c7347fff348c9a661925180d", + "0x50c6d100a8c0977d24c78bb58021df17c880a36f1ed118a0806d1aab347e3b42", + "0xd18166f82e90410a556744042badaebf3282c65d3c1fd81cf7e599695436b2d6", + "0x8f47f418fa13eee50b9a97781a02cc6a8b6818389f1b1f9b94aac17897ef1bb4", + "0xa4b3f32d84a547f66ca91ec35deacb2d5cb4da741059c01419b60b8d526d8a15", + "0x3187128246074cff2e8c0928dfc6b29294b0ad3f2ab839e7ba6d0b72f4f078ea", + "0x213988ced1828cfe0021da680b166b7d830b66a795613953589604d09b58bd5e", + "0x343c1581b9d75f1f72a787a29dba31a73384364672f0a06ec6d675bbc5b81beb", + "0x59a9da5a92994baba7e27688505df673c7131f4de43e6d174389124463eaa0b9", + "0x15c6b483253806002ed293f89d86d66314e55fdc32633f3e15dbd73dacdbde1b", + "0x01c22d029f765b941eb772991d3ef50458319d49ecd1e237ae0d61a05b7ff0cc", + "0x62f5ede9e4ac720b4fb34c239953b3289cb77e4e7bfb5268925727f5d21f0c75", + "0xe330297f6aceac790b3f4741efcaa4e58fbe1c61dd52c1d9bf99220803132553", + "0x47073de2812458f45fb789cb1a6d57f9ae772a38deb7dfd4c8c21c383cae3cb4", + "0x9e5dfc6bfe32b5f56c9799aad47fe1a01746fc9edc5d8583dbd1c0a1f7f81246", + "0x1d9a6fd76fc6a6f359fd917582f6a1af617b0b21984fe7038c323802660fe1fd", + "0x6f50b828af00200b81d65e14f07f8c34a5d485056b017146699fb8ac4ebc39ea", + "0xa8b15957d1dea63b64c56d3e40dffcbeacc5c9b8e35d27cd66f61f5c293def93", + "0x0ec32ee93cc52258a0de9eb53f48132b7101abd3de242b9319e791bc4205f57d", + "0x4405dae679f464fda0959884464e47f7d21e21d69288b66c35878560deefd6b6", + "0x1e490b1858da4d82632f376234e04ef4cae529c3307f3dcc5f5b893e38a418b6", + "0x4683e9dde5e2d66da4c288452eb653e2e6ee3a611f36cf2c80e5870c187c28e4", + "0xa657cd63ffa0cc282221e70ee3dc8a7f2e9eed9b8544f25467208b1954bc1f4b", + "0xd8ce555f85b979a26f207bc1e86d1463ab77f8c7e5f5b3c7db6d79785e388662", + "0xf604274a19dbc99c4c079ac4caed9fafd49c123226c3c223a53aff7f7b253b9c", + "0x4edf0d0aa873fedea6dbe3ad1dfa8a2b5e312e2c2b51c464c9af60a5a5c588c3", + "0x5ee990ce5c4e5eda4d80885409624af7b8075bf7349f386a40e03ae64b578707", + "0x3d34e4bb3284428153db9216319a83c3940ee95d0a47d963dd079a46d14ca105", + "0x7503687ea102d05d92bbcd2397eaa1edb42f757a0ceffd3abc871d2d895214db", + "0x7e7201b9fc6176b6ef993dea53732f335efb98abfa3d92462231bb6a5186bf16", + "0x1ab3a0afd0338ee34e047c60cb2c766521b3085658ae2e019c0688c2397bcfc8", + "0x68b5df43d045043400e3583c4ed125ef0df6f1617e30693525f68fede915349b", + "0x201fe9c6fe4cefb948972c644fb9d67634e30529589b4de597f9335bbd6dc8ba", + "0xdc09d73232f082162df780069a77f180bb30d8b736457b0c746c3e0a29d7dbf6", + "0x7c33f90910049812c0a87aa8321c97320ca8953f654f8ff7b6e3982b13e2cc32", + "0x5658b211c7a5a9d8d66be179b8d6039c6fcb5b5c9d232d4655e536e21fade31e", + "0xebfa63617d9055c50466157b9d8d0c16ae58f02df12f4e23f4bc09304701391e", + "0xb29f737d036e5d7164786e62b14d1f9c427792fc4faba265efc59360129aeba9", + "0xa1271a340258127b442c103959fd8d5f6369487c16575d90f9f1267fc3f78456", + "0x1d5e62fc56da958eaced4c2e6a58ad4acd3e978eeeb0f417e4a4078c6014a8de", + "0x4357d167c61da7d4d0b3f1646508a859d8270842cbf1f1f9f082d8f713da3904", + "0xd9556c35934ffc3ad2970a448d8caacc43e452b509f2cce4cf755b19d888b674", + "0x248efe4782d57127bdeb94420062b742031a4bd51c41d36375a9671b279b1e09", + "0x94d06fff869c9923ce5f524c3ccff9d9609b0b36562f47c65c7f8568d3f9207f", + "0xdea7e81ac2b15c4b145dfe132a1dd41300fae3a86eee16f936f46df16f33c686", + "0x733fb7f221502d0f10a13a5ab0473d50746afc5ed442dd69b4f9378abd304e87", + "0xc680bee47e540c3d706cf461399fcc1d7a6749b4b9f6808afa099c52d28cc6b1", + "0xadf685a187510063c7cf4b3ef6ae478705af7b4dd6c3c4080239ddcb6b069b3c", + "0x4ec68b78bfaa971ad03296b71dca45e36852f04f0cf6d0e8ea681c4d32ef6d64", + "0x407017242e04da4a1d4b16d59c59526a172e18d1d7abd4a343ac28ac883298b1", + "0xc92af4b5d045a6b02f2df7cf5a23173d969c447d7c006457a5be7f0251446488", + "0xfb8367fe9396d369332684b2fa3fad1603c7b572dbc00377bfcef0021192a52f", + "0x1d73c88199bc153c932ba313175344b436b28e5e0b39c3353d076c7e26fe843d", + "0x253fc1aca7544fb93d493684be03d3667628b5a0f3f516d7981e3a01e6656440", + "0xb8fb006c1de093ae15658b7be4b6625d5c6d14a5c4dd2623ac9a31e2479d32dc", + "0xb46abb8860cdd8ae411231d897af8269057060cb43880e52e63254f698af82e2", + "0xefb736142ceab502aeccd9df17018719d1004b554154edc5ac62ec45830a0d30", + "0xd9ce776c58f4e1eaf1ca20f61232d3063e98fee3ba0b078e5ba34736a16a7e35", + "0xb63a06ab391813bcf830a53febcf9553f292e097f127ab610745742f12ff7a02", + "0x225004609e0edef06ede2d08f490ef3616b1c5976027dd03f329605bfbf8a916", + "0x748f462a0fceb4743d8b03de6ecad430fbf35d957483b04e04609e9527fa37bf", + "0xf13227684614cb92591a4c0381ebb87b0e52bd21cfa265b501e231d8c3a0e504", + "0xdb56e9aa8ede4b7b042f32190ea90757dd9268457d43231d1a384bc6da5d6396", + "0xb4880cd0f5e5ef6e30e5c015fad427e418ae0efc70d084b7b6d342e1cb71ed2b", + "0x8a59bdfc0413acf03c39f473bd09b34223b109556c4e0fe976a30bdb1b944c52", + "0xfc2f062e32c3fce97a5f3922d3bb5c0842ea02a71775d6852e256ed0143ccb51", + "0xdc3ba03348f62599f9928101c65a8f13e2eabc09a377ed461636e48cc9e0a5a7", + "0xc5b2ac69eb80b3f2ee751ad4aa8e2eb2cc939e81586088986cf9d6e420330de4", + "0xd6d389727a18def7ce0bcaf65417e3d7543b1381b1b49c6f128f3e13f7d3eb74", + "0x02f48b5d43397b1f22bc7617ffd4d93254744b7fb872c051ef8a02698ebddc5e", + "0x90f674e478cf1dd60cccaa750363efe18cb4ed54415db0ea917a09d3d78a1778", + "0x98bc38a5b90450f89255564e3fb825c53d5fcb5eb9dfd9c07485ed6c42aa3f87", + "0x5b70c7cd74a8a92567686c5785657688f3f864b10d2ed8d9f21f004af2d0a3c5", + "0xb153280a3c86e119b7a03dfc4c8cedf79bdd41ee6128b3f5fda20cc83daa39a6", + "0xea4c28d38762dafc3c6716a760883e33666560cd05173d3844e7e280a6d8188a", + "0x8b498049e107092deee810a68bf8914e00d6759a7e62c8d6fda1c5b1531ff72d", + "0xcbcba70e0a5bb3ddb84e1b115432f025a71f2824061cceba494cb917c689f452", + "0x5906b23bc6b56c4e91706c5204d8873d17252c0291585fe4cad030ab6171e710", + "0xce634ca362c4acf53cf9fc68f0e7c8b199b7f3a1f5a2f9cc1c58a31f9650bea8", + "0x840f429289a783b9b4f8e0f575d1bbf0d2f4b00e09ca6dc83abd17d9718ad688", + "0xace326fc69d8ff3746bfede0d167206d3df6093315f3e3cfca8d41a857c20b52", + "0x905d81ceddb8f4301e62a871e29f1f08769336d7c0b94821b12668354af31fa9", + "0x8decc0ea30a4102baac7ccb3e50e15d50102f05f4a3102ee01a0a275d2c51ccd", + "0x56b67da5e38cfc995831754a64f0ce636f060d51c11b746aefac13638bafddb4", + "0x6672660064846341aa343879a40c5b29f10ebd8120c59bc76af66bd86b96cdf1", + "0x3600a734f1b1df6fe6dfd1cf49d8072bab86717bc5f2d276668c1a482e62acce", + "0x28e4ff2dbfe40b374a103ef1bb9e577c0f2cf1186ba3db324286ec490fd02fab", + "0xcc814edcf5ea3fa138fa7d5e387747334c3ad2095ff08465d7e533250430e25a", + "0x1aa1447a8db11875dc7ff7aa49d6927bc31f3b63cd88d2d937f53b1d85e448ac", + "0xa78c6871cc93ff6db876cff3755a59f8fac71e06c89ffc1200de6da08f56dfb5", + "0xf3c259454de9dd21788084bcbcf1cf0953bf7710bd797295fdfecfebd584d4bb", + "0xf86c0f1dbfb94dbce7368211fd3b19875fc831a422989340bce63102a2af3ac6", + "0xbd192dc3426a9b2fa33e2808a258e9bc27e1f14906b9ba9ec973ce604d9ea8ff", + "0xabd37b505d353f7042ef2ea28168f9d6be1a229bcd5ecdd4d69a96663a169446", + "0xf0f05dba6971b57e32e017285fecd48094e6044584889690dd6e0d70c62c3f67", + "0x15a8053e0694262c4954d8110c505ca101898fb5a5814ae8bcd35b8f24d6f90c", + "0x3f8c3d5b5a03f514d0b2f79fcdf7ea58eca2f85651932220362ec9ab50448aac", + "0xdadb41f6e17beff092dbb9a6dd57d3d0951a188fd041f60e455d63755134fc48", + "0x4017f006a6eec8c71840f7051e91dbcb6b18e52fa43529df1121980670f77350", + "0x358dee5f49761fbfe7e6694144a2de8e33614669da6b773fbfa2e330668f4e90", + "0x080216884b389a463ab63c12640f82f442fca56803b2bd7be45ed789db6c7371", + "0x5eb35f253d864713fbe058df986d8af27badce432ebfda59810f096b4e5126d2", + "0xa18c044fdebbe991e181140df95076de9cc5a70c2656ae99ef68e3c1532d7a14", + "0x69af193591c3eb53b00e9fadb149172df458a9e99f403352fcf866bf1456c6b7", + "0xf3a769187ea83cb9d2a96293ec8c9f2074e8231356d3cabe7669aba13f9509f9", + "0x5f26f2aab6b2a0b0f64312d243b7e3dc80621e134fe08f8189b135cfe7d9b2bc", + "0xd3edb5f8556c1a4983450a7d5ecc26a3dbdd332882dd63822e7c8cfb3712b828", + "0x6fd2e87efa3e7d4fb943852a358a515037af5c5eb9da73c3e3dbceb63106d2db", + "0xe574ee1110f966de904fb61d82995be95f3092511eee8195150099cf69fc7129", + "0x6d9c9b7b400d1f5c07aab8f4d23233d26e19feca2279f814729f122c01189c03", + "0xf0756f64317e10b276c71a678b5b62ca94e354c9b8d1ed7019a022be23fa6645", + "0x106402792c6b9f57f4b471736376a153d12ebab21e4bf034b6732324a1fa4561", + "0x33f10f38b702a617e0598cb20bd5df0067ac5ff155cd6b445f1abe46ee3d625f", + "0xffbfbf3aba272f7b978c9815e9e17972786c24fdee8f9167a47e85e9be60a613", + "0x9ed9567c8720d1450b2b0e45195c5a836484a18746e5d5a0bcbffe0b511ad075", + "0xa6ca434a876c017f522aa24937cd4dc1534da3fab47ec57e22ea7d2ad555fb60", + "0x2aec2650b00fa5886b61b1d7c4390dd4e5fd39097e9ed5b1714b741c7b0d4cff", + "0x0cab7259658221598aa39b98d9bd40e18c777ac3b11f6bc7799615c99858efd1", + "0xd76a13ba9212ef2ba4374b265d0405e41ef7016cd14197a2f7a9071e6d4e0a5c", + "0x2802a2d30f42fcb2c953ac6a83212c23711988998eb7f537f9807751b42652bd", + "0xb971ad9aee88adae769dad238a7044c996ee35596cc1b2a7f6e876eaeb4aa80c", + "0x524520c4c947c57827359ffc5a23c4926262c002e6c92d024ea7926a7e0a8fd6", + "0x0de58ec745307c9a36d5f3e97108f666ac58d86b85ce31e73b69579e913d300c", + "0xc0cd603660568434bfa04f6a06342e5fd78c6d916fb8dd77dbfe060cbaf02aef", + "0xde928fdfb8515d944a26630fdafeaf4b3a17dc40b08418097a465fc2009c2938", + "0x11dcbdd72f1b46be2a24dfa6a3cbd8024b6e05f8fe5cacb35618429d9918dec6", + "0xbac41ac48726fc1708a5fff1a06e674a64b8c3a906ec9beb7ff9a444903798c6", + "0x16142a81797daae5fa1914a473f0b89465b0078c5c042f6e1accab6d3ea77376", + "0x6535db5ab7dadf1187ab7c6f0e0a56fdb47a6e6c8f45627ab993b88eb09e7d1d", + "0xa476955c4d2810e17add2ac9604869e9067998fdce26685fd6cf422f861687dd", + "0x4b2ad0b366c96bdba812d3dad76f432dce8f0e8be1943ed92ee4478e9496d8a3", + "0x74bf0384fd4b8afa1bbc0fb0cb6543442a6bb041911a817b55bfa60fb9039733", + "0x5c3da2ac9d4284456d13270fe7d160178cdf61be8bbcbe8a8536da815ee70107", + "0x62da3f7efe7d1de45be7d134d290f9b3dd50e45e751290d870a4b232496ee71d", + "0xd130203c98355022ffd5389a6e84cdd8fa0c570ac887d80ccff892c168a49c4b", + "0xfe129ea286e85269736b508aca4471e643c4d84864809d031dffd660243e2f4d", + "0x69a60dbee253142008ed0cbde35b425e4a2d07545571d2646a5d2a03f36cbf51", + "0x1e2355fe638bd71688579e07145f147384ae18220c8324f95c54ba994b033cde", + "0x391020697dd4cf20f8afb4b76b25f2e08b5f77be696c2406ee45d0d8499adcfd", + "0xbac11283e3e355ef3466ca3dc7d604ca002e26a98b76caf134ea86efb1523eeb", + "0x328b03bf254908db475888105015b638e7b16a4743bb235b85b160e430feee28", + "0xe9450fb3b361bac3eefe1cbe97a096218c40ccf4530a669ff9e10207c69b26ff", + "0xa574c9dc2d563152d012a1931352ec3b9116f949197efad0868a53fe79a2afc9", + "0x629d3aa0c10926f4bf5d250b44fa6959e534444d9f0e8fcf5b206a78ab5974db", + "0xe1e7bfc1e38f36cc8a094038ffa44ad0ff7432c508516e7a8b3520d71714c608", + "0x13ac2b375558ac0582ec61c4edfbdaebb268efb3dd736b6483530db77b266c2a", + "0xa2ec61b999d453a53aa33105a90d310a5afd6f9df76966c53fe524100515da05", + "0xac58616f19436e53d5eed7b50162713711a3f9a76266ede35da4411008de1b4b", + "0xbe8d7a38169e1a92a1ffa712af5173d5cc18948a477a4db917a7f8cd7013d6de", + "0xfc6997785c292450bdc3dfcf9d0609efaa2eb780a6cb33fbc911efc18325c1bc", + "0xb0d71a0c1c3b2f1a746f8cb70fcb99695950ea488216f83854cb267f88c993bc", + "0xa41cb69cbb562b104aefb77c9f0b0b2a7b43b92c7e1bb40c6e781f3667e78c3a", + "0xc3dbaa1d46c2bfadf7b69d5930e00b3d2ee2f0e459310eb9414be6e7d8fdfbf2", + "0xabf64b834999a679f71fa66acc622afa69a45bdf0befe5c8e0224ee12cd3214d", + "0xf788f916838793b4efc5cc80d9f29f717b9a84e877773dd4791fd6a0c1cdfc56", + "0x289de39a57b30662c600ef8056dd354c67722e1fe198ec2bb749c2af77a27643", + "0x580829bdf1584a58d7da444d360dd552818dd1cfd5f7ff4323d21a0c13506b5f", + "0xba51c5ed86b5303e52a3b618f78614bc1640b1b145e87fe625b51ed80d31017a", + "0xeef60ce9f49954e62854e938873e556386b5045a57980bab45e6fbe6a6e9c657", + "0x655bfa2d02761722b8792ee69367dbf3103d16ed0d07f7f8ff6725dcb8f2d955", + "0xc7a54faf2898c69f76123fe1910bef9be9ecd77509ac74714218c9bb8b4204f0", + "0xf59ca122bb48dc6c0c577b04449bb64d7a1ff5661a016bf50e32005f3295b223", + "0xd96401f3f5031c1aceb13d9a3a0525b5bcb7afe47424a5b76e8381732e789a4d", + "0xc74fb4d8533d438c78710932c95500923716fdfa6625154320625465ee32f07d", + "0x63ba1efd6ee8de3b07dd2863eda5d46070f7eb02d35cf670f7b132e16a958bcb", + "0x61eea2352d91b206a674c4c2af59d8a2a0fa70479d77447e3ee9b7db85d353a8", + "0x04b60e8ed3b12a7fab29bb6a74ab7c9a33d403662c47e72227e7eab515f33618", + "0x9c229a533ba459b852dbce6d96bb72c03f9829b9a984119cc4e1c852992bd2f9", + "0x54695b023a34947fae5230256ba2b0905d3e28a28f02c2764f70495d71441a63", + "0x2c47d3759d9df5b9330e6836835939107269d70a7d465be651a3845e4a1903e1", + "0x5fb3708137f2cd39aefe87c67a6c4f9cb60a9945cfb769ea71d0dbb7f3ee8cba", + "0xacba51629f86d56e806aac1561bec11a697a05f6dd182ebdaa906ff77aee7abc", + "0x30ef858593f9a35889c8c036eda78d012e298cde4a3e7e603282b7f8130a4595", + "0x1c11971b18e9c870e513d099e5a49615e409a255725a61083001313a1d929658", + "0x9c6e3731ca9cee43af8c299c02eb49760141e74e1f781d1ba49b6815565f3ce4", + "0xb59c0d2e7c5ca751b9abf8b7740d8d5c8a6fb1799dd1d5a5e9f0ba75769fb2a0", + "0xafbe8a18d07a30f3ecdb907eb4cc05fdd8df2f9e4e91e61f88ab87dbcca25249", + "0x5233d2380755af7c385b5b50d79c5cd9b1255f0145a36245cc6dab7a86c0cbce", + "0x54520d2d08116f06e38d1a316e7e4080f3bd8c4e52b06f3ec20c3a5327f88adc", + "0xd36158eb493e04911fe79cdf4c48dd43a42aa3a23568c7a6b06afafd3ceb51fa", + "0x88a509ee3b2bcebe15ede2063f8fc9a04fe103a84551f279b6ce8d4d36d3b259", + "0xb1b80927c19a8cd540d126e07c52aec2206eaa37a13f2ab4726649d34357879e", + "0x83b1534ad48437dfc54412e49357b13528f0f80dcc32555a2b6f2391cedecbd9", + "0x13d00415b9888e8f64bd3110b04bd47125a96abfe52e0b6ec004c96e142eca1c", + "0x9e3b31cc2715b383eac51b52a3d912e22d3c1f23fa883028ace6a1e80b1c02c1", + "0xcbd325f1c10db1289d1c46feadabc59b24ffbeefbc4f242cecc3dc0dbe5c2e8d", + "0x7627582f663394f8284a6636bf024683547863409f38cb6ec4f67224eaeaa2b4", + "0xa4a44ba1e2badbb513cdd55fafbe2f5741caf2132dd46c602172711c110e41bd", + "0xc7612fd67e5d4bfcd14eb631181977f5b6737855721aa42bf4e9252dec190a53", + "0xbe3030a24be5db7244f04c43dbf419db3c7fde7e7a2f87951cc74df9b88a4071", + "0xab77045cc03cfb77d55f118f15b3416f8f118327e78ae4cc8a074b3c8550f992", + "0x0fccd266f83598b42b88c40c54670e3f2ab3a4c8bbcc0b4effec5ba92e0f26e1", + "0x5285dfd8a25356ebc198835359f53cb86608d1058a90b20980748eaf5efa2ac7", + "0x182bd336222d0cfa5fa9a0d8f4ca769e2d45829af50bc3a454193628e073b44c", + "0xf1a20eabf959a3c1135943378f31a69c049529785e0556a45450174237d8a2ff", + "0x69387452eb76800b6cb66231cf58dc180bae7aed04ab182dcc3845cb1abfee73", + "0x5136ee55850f0aacbc26fe7bcb58a74ea738ae6edc56bdced078297e8ae44087", + "0x37eb930540d64aaf250e003ad0c2274cd047eae6c28bb861bd880cb53aa972e1", + "0x82d64719d65ec1c1dcb0d269222b1acfe77326ee7d901c8bbc542b7696d98de0", + "0xfbbef382c42f25021b7b5787fe6ee0feb1e589310c615cf26642ae507f2e8e07", + "0xa2da021c8e8ac265fd7c181ca94b372375b3c297aab51811494c07a96536d4e1", + "0x7ca0d6023b41793f7a4dad7aa65428e43332f9fe40efb62c1e74253bf64a28f2", + "0xfbe923af0120629c5dc3c118350d1ae310844e0df4cb8ed48decd520fa7b38bc", + "0x3c7efb35e8c27c90cfc06a18160b34b772a5818cb79a1bf62b107ce93cdee33c", + "0xf59c8f80367b98738620c50a44cad556d73ce17a5cc1f403528d72a52fde5375", + "0x7173aafc1f35fc4eaaabb61d26f908a8d0d834252b951f5607a8cda0c97cd79d", + "0x7ccf293b0d2ab799ce9fc487187d61eef099801d8731fa21300bc1b166c11788", + "0x6ed0dde1a0e7bb58435bb525d897d1a9abaf03f235cceee32f3987e1863d94a5", + "0x5a5d21f5ae95355ccf41cbaad953150d3f1231de6df6650cc712cc57f77fb7d5", + "0x7731f59f98388e028b194d16478c9315050555889c30242a836e84e5f27aff60", + "0xfa682bb7f35f7a75c9490c074b1ef4c99afc50f1e32d829c057c765deb899638", + "0x10403d6937901a289c468f7eedfd69d38fea6c6b468f63bd7cb17cd8db4a22d6", + "0xc5ede1b02d3841558bd8ab6f51e14f5a4e6b00daa31f982874f0bad7132465a6", + "0xbf01b8033add1db5cd02633cf114492800816bf01ad4c7e060ae4c9ffe92c13c", + "0x72d22a8029386eb9c26dc3277e08676609385cc2f9addd4095fc1de0ca6bbb17", + "0xbb77dd7851cc4cc50551914a62c71f8b8e2ad7fcb700469a6b893810b7d71a69", + "0x6ffbe73f30d4dc914a859911afea236c9540920e5fc6ea35a5b15baced0c8d7b", + "0x2d06f3ac10ce2d780f52e9f8dcfeed80bed8c4fb628e8169290bf35b59fce156", + "0x1f6c2f6010356f6a37b0217433d7a1f5a2e0cf51c41b6ae6de4afb236fe4b5eb", + "0x011c13ffb7e71e32bbd4517b994856f6d21b7ecf43d117b8642cfaac37b9a8d7", + "0xe2613913bc4cd8dc69550d32163b251cb1e6ab37d65eb71b3aacd05713158157", + "0x54247c638b2b1fe4efaeb4eb101d5177c84c975c759ddb1ac20207341818c6f1", + "0x34fa5ed94aec05a24c812403ad050ccc96d7a052b0d9509cbbdf83503589e3f1", + "0xd4c86048683eecb1e595cf76988e76be819488421c56b96a6dd4641efddf4de3", + "0x541b476f9a0273fba6340f7185c2ce43333de04bdf3c1a7ed022edf4372b2d0d", + "0x65319f2394a1b531beb788f72246a6035539816c618867b0e1d0fa3baf318d38", + "0xcc6b6ebd1eb606210f5d03e191f303c1c4a438b9fd7b81f61c38da76a6bf9fe2", + "0x66c0dd3e062f95edbf9b26189a302e46ceb5cfedbbd50e43139bdbcfe9fa2b54", + "0x728f5ccd05bef6a64b639ff86642f71078719f442915496c430dcd17b437139e", + "0x85a856f40e911384e7a7a42fc5d9197e063bbb890a81382b4ca6ce2e78af2c77", + "0xc80aed20cda1826d775271f2160b6040682095e51d7deaad7405a2f1c801f980", + "0x95576e4497c07a1738d07bd468e65d251f9876c957d7efab7ab7ed0a6eb2c9b4", + "0xc30785c899138565d799884aa7bc486f1a803901b6b8b8b66eb6d97ca597d8bf", + "0x3990fd6682fee93631fa80ce6cfc68fa57e25850860d4d982d0945f72ad37f38", + "0xa136539e69b53ffb451c817c40776af735c95f3392d24d906b22c0e6c6114be5", + "0x8fdb4d50398d776ef876ce77547d4d9e1a4609be5432121ca1dba983ba07a28c", + "0xc7a547ac0db666820263a76b9f9adac876b972b22d6c8bac407ad6fa5c839987", + "0x87aa61ed60484044960beec4d9c45c9112e6e4a70cfec894d5a9f93f94060acb", + "0x50b05f8c5a72944787041204b8a8acb39faf179838116e04ee7bad4d6f21d4c6", + "0x8b90f04539dfb2aec48e0f7a47a1ec601af5414f3284074911eca3a3afc36e3b", + "0x3f9b8f28853028fbd3cb0bebf22a723907600bc2c616ac5251fff33b2df5e9b9", + "0xcd7153ad8c35638d23fb26282ab9361361fd23385ebb9693d8d628a75aec6c07", + "0x370788f25ab289cbd7f9a4b238bd35efb41917b771d8d59493a05aa7bcb3fa4d", + "0x942223044ff0bb9ae56f259006787e5ae6f21f46a3a2bf11c0e977fa60b50b7e", + "0x7dc0e910fa0a6d722dc78f17644842792e619d7e7c044ad47a5fa32583686e9a", + "0x669d80d664251cffc5c7289ae2195a0cbc6fcc732c2af1bf429a4aa98c889520", + "0xd6d24bd4d8a639ac36b14c6d8599ee8ef5d84ab71dd7e6ab829b730d930ce924", + "0xba692b11b9febad8099415d1c0761f2a339328e598d9e04533103afac8c04dbe", + "0x8e9f7d1c6c2674b3139ff88faffe8339e45d72212234b4531654accd66ee3d4e", + "0x2589b94b36fec67b5862871758f86c2773a963197b0d7ba9984427da3b4d6042", + "0xb7d1c1c35718c23dd4498571bb0f4727f3ebb0e1cd02d8094f4713fc0e858894", + "0xe222068e575041014f38e20a85ef1e989e9bb05279281c59569a627769b9d7f8", + "0xb0746c8dbf22e4fcf025fe5383fba7865fd02f79a4403d89753052bb9118e3ed", + "0xbccfcf626a8e36b6eecbadad1870358088b3e584ce79741bf5167380e97f5e9c", + "0x6215dd20373041734291e4dcac34b207235a5d19c3bd24359168d75778b6dd5d", + "0x025f64d258d97752e9b648e956d114c8defccb80c8810113a3522a77ef3f7d35", + "0xc00ffb03dc524d1ea1984eecfb8d26d860791cdde35c8b262faab927891e3fef", + "0x4ec39fa070e38fb24c41af52ae2ac640a859c61c96661d24e53c817228863abb", + "0x7d943dbec346b6bf55c226cae23ee23086185d9377fad511103bfdda3d677ddb", + "0xbfb16c7a87172cc804008bced344dd6c1105a7f0e925f3b7335b6b4d7c8def25", + "0x359acc4a540fb3b54fe22d81f1e3c1b969a99129e130e9e4e24481d024cc81fd", + "0x33091ed3e9f0e50c8c9aa100d9615e8523d594a99095e83863a58cf54332edc6", + "0x5eeb88207a02fe01699c8796b66ad3a0827432559690bf42e76ce1c7f23c0b30", + "0xf5a521239d0f969c8b5c372b84f739af314645de36efd1190f92973c0a2f9098", + "0x1a634f2d829a24589a25a01a22b139b8342c7aad990a14b5e30715d2a83074ce", + "0xc5f62552f5e25ce475af7eea51eba85991c59b73da75eaaccc3e5571b58a6372", + "0x9fb29bce2aff82c7d3eceb134cb1d5c6e6b309b8a9be5d239e6c6dbe231fca32", + "0xac3e3a2edae826437228f39859aea596a84253070a5e442e04adfd5504b9a108", + "0x717d4b6b147ee5eb42baed2a926241dbaed7e6426aae40972488c08430659d20", + "0xe18c4e7cec87f2e53f1e10683835563bb05e182596fd5252017efdf7d29411cd", + "0x6ddc0db9f04fe0b7f8417507afe16b59479303b5473563723b390149a5f09b2c", + "0xfbb88e97efd86e451817b13e55fe3d310edcb302607127808ffb350799631ccf", + "0x5f61ece4f330c3eb3647d2cf9ceb4f3cf238a324bfff628257ac4aa1de7f1663", + "0xa2a3bd77e36c3ede311ef3fe330e4a2b22dd41313ff4ff6347f629777a88377e", + "0xbed3c97e0d2dc6e56006bcbdeb007c8b63e060d80f46b691d38485b03c17c791", + "0xa4e4b8d8922741c5a767d9c4dd71f9d850231d298a5b5ae741397fd065600a52", + "0x0f49e95e5812f573c00dcab19683c391996beacf61442e52a9c240f08f8ab92c", + "0x3701c4ca890dba3cd43fa3b506cb3d9ce540e87c493c6cb9e80bfe05ec5cd255", + "0x785e2c2e4652a9dbc413c4b7bd54dc8c103f6c933eb9ec41ca44e609cf7e0bd5", + "0x7859e4bfa55b11274bb0e91f608c6d840b7de4385ce8158cc08b38449a61213f", + "0x64221410a8e57fa61ee9d1ea1b5ac161face63a493dc7b0da0f398c0d18b6174", + "0xabeeb213fab38140a8e66b41664626f3ffd831b91e83f3cb7d4f2f09a0b73e5a", + "0x8bc1b2eebc3481e54df34a5f0229a54264ac518dd36f994bbd162442fe1190c4", + "0xeb0753b5fe8706efe7224f354cd92381960212ce4d448d3ba554450a66bb5e7c", + "0x30f73d3082f6ce7f9ece8dc9d6c78610babeb05854415279d615eb24d0d10962", + "0x4bdbb7c38040b9f623b67409d8890070fd5d6f89f023556f2bbee1f40f55056c", + "0x18ff647cfbae0ee093bf85bbbe218802afecd7f45bde5dc29c0c76420311f5de", + "0xdf91143a55752eec775c6c02464a781e16c8e93a4270ebe1bf2127658adeb5a4", + "0x64ba37e403fe57a42440bd2fddc1e301297846f69df5990c2d664d3734f902c2", + "0x2f70192df5b8359e851856351ebe2b0888b1c51ce802766f16ea2cf8b723004d", + "0xa5ebf72bbf06ea040306715900f6bd06564887b52e4692333f880e38acc40b0e", + "0x3b86d989319b0c910e74a79b2177efa068d8601b9889b5e3d17d57c59c6a2238", + "0x1e416fb3c47d77206efcabafdfd3fbd0919e7e6d158ccfddf1d0a2a7cff6a37c", + "0x3db2b1eb730ce08d44e27585207b39d5f8dffe7425949fce9e6e1a4f296c6e75", + "0xf703aca3c59fb4e102018a6b156a83af6c93baaa96c54d9a44485a5b90ff6679", + "0xa103f504db51472ce4d6735684bbf46259e04224d42fbbb87548eeb01aabcaec", + "0x282e099b561c70a9a1a3ff6a4518970deac9a096563e15c01151c0c37f78f737", + "0x87bf6fc28f774c2f6bc83f32751e0d509a2e009e2e3dcbce44db2697dab33520", + "0x97d109285466d0d40ed47f6e1c8e11259e69b90b02731a4c25efff829e9c7e71", + "0x18232c1bca21707fe7b74896e3b1568f88094adcc51b4ad9a29a4c76ca33063f", + "0xc230723357dbd10e7e57ab187d1a1f72a27a53c45b650020cffe672fa8e156ca", + "0x6984c028091bbcf3e40bdb8da39d81d2c9f8a73801276ce3644fcf57cfd3e8d0", + "0x8b66e1d6d3d60f03098f29d9f9857a29ae48a5a34d43786a8fe64e6227ee2da6", + "0x353c9a58633a1fc28b5acf9a0f40e69fdd48252c689a9b8db7610c3d003d5441", + "0x1e020c7d1997e15baddb02742e8846228e4eecb6bb1beafc81a759b95783e238", + "0x50e9738978bafa44eff6b9ad9d344efdf40f7ace0dcb146e2c758cb7b3ca05e7", + "0xec6ca85b0c27f1735eb0822dfe5a0d4e642776e2945a9a22e104b9caed098f11", + "0x94f749840d03dfc1d1cc7f31070a1019cceb1eb36a09f520129457057885fb48", + "0xd29d8d19a1dceb08208369498527ccb0fd4aae41077d4c01c715e6989d5f828e", + "0x40b5cc4710284f1175ce67c1a0f134288428d8ea28f64f41fd061a3a4b139242", + "0x7ea68209ad947c37eb3ff8c779ba7f5f3efaad2d61edca2ae5efef666d7c1f5c", + "0x0af74db9e9195f27f1a04acc3150d6d6200a5f50be63a6dc2fa9acb953759517", + "0xd7a6b221519266e935b12a864c84c6d7daf4e4c8c812a93515ea8325e94f2644", + "0x041fd7dff3672a07a2922226bb0526daf0817fcc61cbde7fd3e1f8efa8dd6c76", + "0x79fe74fe4e56514072881413ba7157cc125051476d42fc9361a58021268ff0d0", + "0x01cfb41ca5887931cb98c347c25d6c03eb5e992fd661085307245dc77cfccc42", + "0xa1e93426afb5ef56a564ebfacfc52149e293c25dd36dcc2319d1ee50057eba41", + "0x6a8e8e62cd387ea56c621a5e085daaeb51003e86fc3c252d115ad417e2e79242", + "0x18e5d5dad6f00c36be4ea9c7898645611887a3c3310b97363699178136989527", + "0x6701bc914e70bced06487f22a16792fe3dff4f1fd15ab87ad42dc91de3cc951e", + "0x75161e0ea68a78e4377837bab6162f1b6d53cc5dd76c423acba9bde4f3ff356e", + "0x9d9ea2b7caf0b67dd97b62f0e25d172f78c984baf97ae3851e52e26c5af87770", + "0x4257fe5a910db425844b2edc8badb4977c819a3c40e356d260b93fd2f9170bc3", + "0xf2c878a894811bd844c30441bf38cfe79f3ede5b0574721f32a24755c40aeaaf", + "0xd45e12f2f3a025090fa81bd95e555c8787c26849410f96aa172d3dd153b40a67", + "0x6204243276bb752e5e2d77fc43cf7c5cc92078c283c4d489b7310ea2753ed71e", + "0x806a0a9e0f4e744b02b5091f72f57377a4d7bbbb27829789070967d35fbee325", + "0x13489b922a69fe05869130674253f90b4f883b199f01cd03c85df0a000e1717f", + "0x4fa87d7ead2b1789c72908523c5aa6ef83b7d9559f5c5edb506b4c2f681b617c", + "0x4bad3e31f50fd2dc570c31bd547d278b92e5c93a7d971c38035c09ec5a1dad84", + "0xa0f547806d376b76b33266d94e7d2ef86584a234b540e74f79756e0331405c61", + "0x4bab9342aed359dbce241e580b46043b160a01e44eb62bc29ee5ac413b8a7ad8", + "0xc7ff1b8f8557acccfaf4dd37d13a12e3f9d0e3612398c3d8b1d675467fca56de", + "0xb412685d085b0d52c72ca3d9987cc188f930f759022f060d5f2f368e77a7767e", + "0x0775a447ddac0050f5cb29e08fca1e7d016b42c882ee15bfbae3de5dd99b6705", + "0x1d33342e6115ca2919ad6d31fcea9f4a9fda5dfadfdb4e206e464ac44e59e178", + "0x26dd97156aa189d9f3c799e943f50ad13c2d0cc8018b054af65eb37f5caa76c1", + "0xc4daf50db81c04055bfeba3534a48af718695e2789aead7c3fea58b064bc86d7", + "0x87e2b037cdf4370ece9a2e4a54329d3e1be0b910af6da8c3850ac75d6ba34920", + "0x1b8fd79a76b40690a3bd1bde5cd3b68b36148eb951f45b798958777527a876d4", + "0x63ef67d88acd91fa005706dc9912991ecaa81cc7334ec367340a2c12147cbfad", + "0xe20cf7a6540722b3062b9f49dde601f210aa8cddb5b5ea65eb7bf44f53ce9d5c", + "0x05b5daade0670fddf401298414b70656294b8c5d3203ef7e21536ab2696195c0", + "0x678791e0898a0fd0dff39cdf16d298162200ab1d93beb96ecbf9e9a664362b9c", + "0x77698208c576cf9f2696280872c6f2938595ae522b37c2b8dc5b60b83ce7a9cc", + "0xe9453e5ae3e39110b65b03dca160f930f39e933ecca604f7b1d9db0f3d4e3915", + "0xf3d84caea9ee5dffd395c7da7131456174cba99f905eb734c0df1e070c16d359", + "0x3b56c6cb8308bfe1d9339e14c713eebd5830cd0c538b196d18743bfb729878d2", + "0xd0a1ed8e3bba6cd1ab36ae3e60952e6ae56cf2157039ef2f7136e09999393650", + "0x206a0bc96ac96836c5230d024aab5c7733e4c769b7cfa9fe4c52ec9ccc2c9ecc", + "0x322a0aae92f406bc6c08dfda0b60f625716af5dadfec8d014c6f863eb33c2edc", + "0x701f25bc99f297ac9e8a8e5d8c376f9a363ba277ec87d2eefe30833035657e23", + "0x98ee55ecb672b58e5d02ac83f716013b2e5ad57894383e792cf1bd82cb47b20f", + "0xd7c63ead8a31b5b188fbf0663e4bca087035291834ee1380da270bc26bd19186", + "0xce3824ed345e2101fe30f43287f428c2cdab4a9ee2b4a047d4c6ba1b46a05c98", + "0x853eb9e976bc0fb95caf99b60c978056b0423f2455e5433f3b9d6d28e8ddaec9", + "0x2fefc2d9f5d26e0e9893b98d6546f593dec46105109fbec9c0efb298dd18e534", + "0x255bfda7bb1a2df1a36e7ebc4414338928d59474d9b33f478dab6066275896bc", + "0x678516c205b1f93ddc8d3558e86ccc9ed5dc317387f4a7849ef158e7759234e5", + "0x58d0e9d13bb841286dc4c579c11cfd659b70e84aab4550a75d1d8f01d31c0b64", + "0xb132975005aac90edeba73c75a8533cb9099a5a7f6e9e31755a22b44289bd950", + "0x77ba37c64ec1db20a6dfad1462bc4cb5d49cae6e3c801a99e223e6062dda2598", + "0xe3a4d6edfccad2c55d2a729e6531cc9c20d668dd057c3a8bce78dc7789384d9f", + "0xf419bd76337344144a1e3f1e7a8d3f768fa97f4f1be87757e3f2e50c78c7ab14", + "0xac248be7b1b0f85f35415e09025f379bfbb02776e854d682bfc93caba3a0cbb3", + "0xd853df355a1b6f7b6921870bc5a00a615d5fbdbd9c5214e57e0461a00af92711", + "0x3696d847c84ecdbe2902eb3200013d332d364c0be47f67cc122bd7d4d644f08b", + "0x843a93026d2075704e731fec65fbef6a234eb6d2368f7da29e8e2d3cae45fc3a", + "0x923e0d97b13c9ff4e051cc43daa92960ec646236d1b02faf28902c5067cf83ef", + "0x4a700c31d34448662af972353f9cb471fd155b6c7b5c0afec7acc09e58ee85f6", + "0x2cf612c948d6d8a6ea9886270d5de1e131c2dfd4012f1811849c332716ca650a", + "0xd9acf143ada3cb5e1eb8c3d14b4c188bfce9efc13d317822dc406e08cb5ad9de", + "0x55b3ab14f3d1c8c7b8660a136c98cb4dbd90f8ee329c1fd08edd612a5b866428", + "0xd07432a9b77607da1fe30c98226a224c171cfabf96a1510849255a58f7040595", + "0xe12a4928faffabff9d4835598e103b6079f359061175ccd18159a6dfa7ece183", + "0xa223cb9afb71fbe269c1f721c22fcb13addb8ec06286f9d5b7e337a262c99104", + "0xc133b48eb3f4946ffec9fa143a85d2e009a3b8a99a68ed1d0121c7e9fa616fb9", + "0xcd63f76df5da2994fd87c43f743cd7d35d94cb8dc973cb7a120cb677db9cd5b0", + "0xde86817e4351951cf1b6402036bea2c75901b6aa7a6dff62b9862fe4783e801a", + "0x2872145a9ea250731bbfdbda0b66367300d88f2d9934c6b1d12960067d717bd3", + "0x86e0674ddc6c584cec7931847ec5283675445d337a89d19047817e46e9047d22", + "0x4aac4bdc309bbbcd210b87b0f50d55fe86f5db69b83e201f156bc9ad25347966", + "0x1c0e32260f903386af7e4cf14ef819fb1245d269d2713faa729f05b019445243", + "0x919711d6689630bb81d59ad2c75ace09b462625180ee8fb8fa2d3ac5aa15540b", + "0x231f8566ebd8ac13f2d6cd5a91566aba9074ffd235c762c26280e52feb5ee4c3", + "0xd5df310c108bbf4dcd5f876e0290c5d9c9c2cf20f4f979bc74d962d7da99a777", + "0x45e6ea115a13d30d8dec6f480a9d0b17cb9288f3d2590af02a40bf3dedf3f1ae", + "0xd9930c2a8d4dfd36b70207175e3ec5386fe91371e4b7fb484022e64b5aa8388b", + "0x529278e0e137a319d3a7516b41bcf4be1390e5646fd74fa8c6ece03b9e734deb", + "0x471c07b4e2c5760ad10759fc0889fafda85c2367f2a9147667ad61b687a52fe9", + "0x39332fd9e3c9c89f6b51e4a5fc43d8da10191d07e71c35383e5bafb997c651fe", + "0x72b4753dfe94ecc08b1ca90329dae352e677b64d3e28281b88765cb2e7e3e428", + "0x9a3d06d9134005224fd1f71f14bdda085f18824b9c86b3ec6254b213d8e349fe", + "0x9e8a68163e7e0d096cb822d73c420324ac7416731b27407d74059903c05f2862", + "0x292c607845fdbec84efa2321bdbda9864c3e7e543890fbedf1b85fa4b7ea6b7e", + "0x31be5706424ae91ed9695b2f8f7cb0a81b7623e02da8595f0affd2411170ea11", + "0x9331ce0a7339609a1a4ab7d82e41f432c430685dc6aae81c50ce18aa0592b465", + "0x37dfd9817be661b6f7310ae6c90b3b97fb5f63e0e622618ecedca0d609c39e35", + "0xa350f656a9cf101ba47b0fa109409f1113ae33405ed766d0308740d5497237cf", + "0x272d62080e7b1c27f7134c60ac9f0dd9c903528b1a32338ddc8fc199d9ff2bd6", + "0x8903ab21a203161e433cbfaf719a95b1fae95e029ee19f0c94fa7f1a68f3a1fc", + "0xd3ba92c896627745c0afbbbc9e3d8b5a1511057b24817d7070e08308812f7ce3", + "0x703ec0121dc8e020de0dce30459da694fb8b7ead68bf5b052320c97b0edff1dc", + "0x0491cb350e466467a1078436a1100a70ed6198122f299b4bcbcf8dbac4b1cbe3", + "0x826cc32fd3097689638c8701164358719b6c8645270b70abfc0b07e103d5403d", + "0x351679f35e52895312c8524262a6e420544b443ca3eee81cc11a11c4e40b195d", + "0x0fb18a66d08f29e90c1a71a648d1b36c2dd3fb84bd2e4b8ac24959233cb7a244", + "0xec7fad9848cdb994996bb9fb63cae6e913fe90c9727ba49ab8c9d293b692237b", + "0xd76f7d686c80c1ef3387ff50925bcb540084d3e8d750a862e76e9dce7a443d40", + "0xfa237f1a2b3dd6e4c646d7c77982558af1633cb8662e1d107d5ad5140ec86024", + "0xe7b5e487328a3398b8716043d3e6bcfb39a996405daa98be49493e46e9a46555", + "0x306c41368e9d1a13d4d20256602c4d4182e45b2b69549be7c7133e01dc930057", + "0x9551a36f384e66ad7c5a7d43f510480448f59fc2b3414cb2dafa8d71314ea4fb", + "0x72c3b4a7c21c0ead562b66abb8e6ac42ab96fc5d01c8a5f934df2393b03b738c", + "0x849f7030b271894fd605067a59e373d903a6a52e9fded2357c05340138d3de1b", + "0x5be66687e522cce14e119c9d4b3b3853fef6cadaff6f6c5c2eaef9b6769b1fef", + "0xe063a6dcd767abe2a9e37d3f18b67e2a2efd68ad4d96b4215eb75e4b23295afc", + "0xa8f6fbac9f159d5a5db1e8d614dbd3302bd5737eeae692ae44155d26637ceb4e", + "0xed37085b1ea6b01638a3a145297f390b63b307479e88c55908fcb46afa1e5960", + "0xd963204f34b83d30e97b458148d7e3cd0143495ff67d893b512d7beb7b225035", + "0xdcf4fdc30c4e90b82c2894b12cf27c2c9ca9e4e5ee88d6052d3526a96b93c55c", + "0x48ae98a481df3d2ec8a9c90d0a838125a5237d5716617d4be50d09b2f1f2f592", + "0xf85cea1c73ca422200a9b41a19fec626d13d70e0ae20dbf8c5db66977091e2f8", + "0xbaa3273782c55be478f5e44af8d6d32771bf837002231621eb82fd5b8c07b519", + "0x1dc0a7713568a6fcad865704e07a405a44c2b0096354115f07af09b760eb9a09", + "0xfa70563c38634999282cde0e088e97953e2d8a81180f5c9b2e99ad74493cebf8", + "0x58c7a37a105fe671a833f01f6c189c6f3204d462a0e119b494b6b0c8bd97501d", + "0x9ad437c83bbe3a45191b5c9fca239d1993960a8316e3c52978c266cbfb4d0ed8", + "0x0e8ce8c69bda4ff65d9bd614bb827def7d0f6bce5d550ed72bd5d91c8c1e33ce", + "0x74e04e71ea4c189be803be1116781a66cdfcc50a067387af6d1d468733185b14", + "0x9d1eeeaa2b39e1e0cc9717e921507d34f35faea1450727825d147ecefcf70464", + "0x6758482ad61721f92137d015d4d07bb238b0976bf14a3c548adbbdbba6b73f00", + "0x794c1b2f6ae68389c51761edde1c96b8bd44904769e85a8d7d0035e76be9f13d", + "0xaafd63d0587a40d5b73ba230c976ca80c46a09e3b7f7df136f8eb0b04b60f5de", + "0x67d184707f6e0b9af49aedbfca464946b4f54321c4eaf3263d4ce52de31f8767", + "0xd2af9a84d73ef353c42517a6c5c0667b1f811ce2bb327e3702b49a178fb94179", + "0x2832ef9283d9ffedb03743b454894472eb31740487ce89ef016a00819ff30c2a", + "0x82ea0cb0f3eb68ead50a1d8106278f464e0126c0d7589e6d4c16142d80989194", + "0xfbdc8b5fbb0109cfb3a3b03e01c90c37cb4ee7781563026c338f455ea708058f", + "0xcc34701c30d0ced752f863fbe56d47abfec0c9f8012d1fccacf3814e5bb824af", + "0xb0cdfcf55823aa634004387d1dbc34246921ca0459cf4b9f751377e3a78ee041", + "0x313e6f0cc985a8a0eb2fcb8d3901fcfecbb7d29e98ef8145996e4cea804420c1", + "0xa64f1d4794cd286788c281b14adaa6c0890f9782ec0d80448b8fef906ed7bbc9", + "0x619d70b2e48cc3b295add6bfbb8fc60f38a01e61f4dfb4872b58c1ce7046efb0", + "0xdb35cea33ddc36b0b91b0dcd84155e214a738cc81c8805127c47fb7312257299", + "0xe101f36ff5b89d028618d46138aed3d6b3269605cbf4f83d68c9bbf233f63d81", + "0xe5925c839b60da70be28b38b2081701e3bb0be98cf763539114609b309c5f97f", + "0xb594135c1794da9f7b7af1366d56b4527223c0471ee3780d65cc03cd70fe2391", + "0xd6a8a3b4c6d33bca9b02b8207aa680835266d9c9d4808e2d57f28f92936b7d01", + "0x640a50f666edfa0c4cc55b6c945a09108fdd53af5ca55ae92de4245d56d5e436", + "0x8dc9acbbf2b71953327924fc2cc711574fb1e82a6746a3606a71071369e77601", + "0xd764b84ee9d6a552e34252322f7a939ae546281136a217f5f7f34e41997e677f", + "0x3ec87053d8ec66bf2449a17989721644050b2341adf9036df6843a414a9a1de0", + "0xdca7784726ae438b274f4a3c5892da0bc69ea694791c1ffb5398683952bdea75", + "0x29114fc2dc70ec997d34e3937c2e54136fd1de4ba7fce8353e19af65aef490b1", + "0xf1407df809e1bb932c725821347954eecc9e5e226cd37b6058b45ef9f4fbd377", + "0x873826f03bea4b73698a17d2b0044f1c689daa17925302edb0f815dbf50c7fec", + "0x3e98eaefd07ff2f1f4d6c67aa7ee3cabffd701aa0150f572521a17772bfd8d01", + "0xf44be55471f0b66b065a2465a04f6f47efb35a9ede93a9d8b22aa26d3c6637e0", + "0xb114c762f1f60a913fa570cdb207c279d20abdfd789d7fa62de06e38c44d650e", + "0x6f300baf19fff0f5af714e63ec81314d7de839d4f5900979cc9761e0ac325956", + "0x94d99e9025cec968ce5a80d82965bf72db62250c49131b14c0329b0aaa462b79", + "0xf1ad3dc366363b5a7c2a238e693600ced352984673cc4d0a07ba0ddc2b25c815", + "0xa48dc388a5dcbbd81e38b3e77178a4248232ffeb23acd7869375323f1aba0529", + "0xe995c7008184fe2d5b39eb0b1229caceccc8e86ef5caaa720f15e133e79a2efa", + "0x8bc6d112254905a89fdc319bc231f4d2c52a22d60baea4a499da91119a6872d4", + "0x16cceba4d6c7ccffe424c9331a78bc3748aa7b629f0fefe88c43dad9324a1fc4", + "0x564aceef2d2c0d4b8d6f73c10c234dd82570a9caeb572dfdf023024b61365f4c", + "0x5630bfb3fbd9625f2204846fc81b98774e95191dc8f7995ef33df915f77ce2d5", + "0x23d02e3cb1729ee715fe84775b969989d11c4ccd470910921b75c63c4e9e24b1", + "0x5984c5d4ed0af67154b12c73e38909b45e46e161d85d66e286d33b5ced150a75", + "0xddfc15bdbbd16b80d442f9a0587da4e304d3d7951ada0dc3d041f5a1df85a9ae", + "0x924c83566150cfdd60410c400078830bb4742b7286a6f8badd3e848a5afd0220", + "0x82847029234edd5c2f1538a71ff2eccf1de43e94f651557ba73caab59ef9faf3", + "0x15949ae538f10280406ebf73fd79fe0e77e937f82cd9d0c623e700ff04fa0a7e", + "0xd93edfcb2fb0c16e18b5c42acb751ff197ebee6ef13e01690b08f8e38e777e08", + "0xcb33ce0679bc3b417095cdecd66cbdd4cf5bfd288037d57e93cb6a542613c06b", + "0xa678db01074492af055c36dcee385b37166ad08a4481309945d227640ece520b", + "0x30b123bd31dab5f0dc65766e2b6067e5caee8a53af647b0c7d35d16ab85b2ee3", + "0xfc3faacebfc2c0ed22820eb332bb2f3d9634abc98d26fd42438276541f2beb86", + "0xa0d90324e7577ab7ab5f9667f9d7a0731d223f8edae77dcc9e38225b0206ba29", + "0x75e3bd20d6378133c8a4f9d0ad1121c485130d65340b0596258466fbc733d61b", + "0xbaef6a6c8b335cd317631b907f692cccdd730c82213755988ff7fb78d08fa754", + "0x03c32b933280b801ee17ade93600bed888caf283e0a058bfc0c73f47072f2459", + "0xabc98360fccd9567e9d555924bd815557cd5612836de1b38b63828db742ac297", + "0xdc6770ceead9f41fe0fabf046cfaf0be83f6c27bf28616a97d58c43e3f591ea3", + "0x4f9a91b13c9af1523071f1d4741ead5b6c7a9e72bc2881ede8309040b8ab686c", + "0x175c7e494c7f0347ffed5ce74eafcede61403cd0829d71a9df99e914774ff33d", + "0xe408f526449bec877c0d5ed25e677e8623ea68b797818b93e443179c9ed4d334", + "0x8f3346b57ad4a5de31df1b0b5fb5cac40ef0152fb5360d50ddc84752beae5965", + "0x4b2398450d192781d3ad48ed398fe7cf9e5e8a417b29661894c6dd43e83e2248", + "0xe94177ce0fc04293688209ff52cf53c548ac5b7022e7e60ee739f5c1711099a0", + "0xee6e5c8a30380746df8d9d3f3de53439fe0d864dab6ab5c349012d384284fac5", + "0x9fc9e919898303f537988a6695329143a77e965802be3566396f7a581962c3de", + "0x5277cff2542cb90c1698c7e673b7ceafd16cf4d0750272ebb51e3aa3fb02f3f4", + "0xea07718095d00493c662b21d0dff8bf747783c93897f6f2421571e2c7e3e8955", + "0xa8bfbfcb73a903d2937025226b38aefcfccbb3f9d3fcb0563ede2d9f1cd8ed84", + "0x795af85d146f9e00cfc5d12c97efa5073f19977afeae31c636cb3a6c9771ba14", + "0x60d169884296b60a45cc87beb366a513a6bb7ac34e6acf6066d9abbb1bb3844e", + "0xd256c59553a03c8069aa3dab431c2868c6dee246fcdaa9683b0284d462ad3fb0", + "0x1a399a1ffe8e7f5eb5fa69e70a620e1b15087988934a754a468ff47a7c2f8add", + "0x25cfa588df60eb1127c4057ba949004ef8f7f2681e435fba925f4bf8ce0eb54a", + "0x282d5589c98668c7a9baf871dbd48a3a8c263ea55452086ebdb3b4db440fb9fc", + "0xdd3cfdffe34633d189d9bea7513b890b6d54c2c0d12067d8f45ae72c258c77b4", + "0xc81f96420ae777252b04116d14bb80762c5169b73abad2e1fb23e8bb9334c2bf", + "0x88bf1fb814490289ecdd3d411134d42155a483b7225a496f24ef29d84df164ea", + "0xc6f0b78237824d0b240b8dcf1e31e75e93b4608a495fb7d47ed47ac70caa5aa3", + "0x10f4272adf03ae39311b049b460dce8579b424d3c169101a80aff74efc018846", + "0x52a6ed4acdf0766fc0a63b221d113e3dc7f9e22435d734972e3facdfb3447a8e", + "0xeb75f393b00cbceeace53bff0725e0fa3382e367450fc1c7f0005bb859467d62", + "0xd58b7c94861e7822f924356cf808c0b6ba19c100e49cd8a1fe2ca8a537bb20b5", + "0xd355030bcb4e35157543fafe7f204040ef0e0ecbd60bfbdb897add425112be2f", + "0xbe3ca964fb22fdb9c6c74f07381dabca0e932310cb88676144cd78cb374416c6", + "0x6417c82c4fa9ec681e767a8b3a26640d72c61ea72b1857bd61930187a54f08c5", + "0x0501ac461bf7f2e813ff8b58fb9ba936abe7eb0dc6ef0072f98c52f83458765b", + "0x6ed677008e96476990029e1ac8a86e4d9af83f812dc73d9b876c772c2beb5a77", + "0x9c35dd84c1d73d78dd3277d96ce4c76beac8c6bab498a8a5853970a03026b2c6", + "0xbb0b70d3be3239ac17b3689d67571c12318b51bc6811dea5e8908393d9a567e8", + "0xbfcc8fb9be4c41f8b26214e8462320e79c2fc126abd6e129f701b27b9ac96711", + "0x18bbf70cfc61152ffc64fa6bd21011e446f9d8d1798076e8841cecdbb2e25ccd", + "0x6ec57e3b3b13f8e3fc9298760ea47907c9e08b89bb7599c5cc50c83157a5b12d", + "0x1e681fa5a5d2d63ac23f45cc30720c5b33a3417ef0adccb10b9d9299f5dfdd15", + "0x63397c3ea42e3ea7dabaec5f3aa3cf7e15a4ff94ec745228c0b099928c2a5f1f", + "0xc8d14199fa6b134b84c48a44b9ef1962a9d08b34dbe78713f84ebc0d307c38fe", + "0x4dc0102f265b0e29cb403b258cfee5c73afb843b0805c9218bea86cc12a08503", + "0x4acb64d573cef699cb2d9036488a28bdb3d68a0d294d04c92cd198d42bb48098", + "0x872df3af6d40c5beadf565ea8f6cc502edcde941c43cd3024c812b2cbc33eaf0", + "0xaa24ebf00a407b1ee7e126cb5f396a1b4489577f160a7ec735e0e47fbf077abf", + "0x15e6c3ebacccecb59426bcab8f5845a60a584a18d5f6875431181a816d5dc0e1", + "0x3ae0bd8b42433be46a280335444e8e2d35c1afec926cd2c1d5ea537992c506f1", + "0x1e423a88a245221c826586cc67ea45dfea247c3e9a36c81ae9f0c0b5d5d3e5d8", + "0x5401f93723132c737589b457216dbf231a753c4c4619444af4eae9bc6153ee40", + "0x70d9a2787990c3dd8166357ab21985abc81a55eb0d50af7e19ec20454b314d4d", + "0x4ab7adbe2f74ac269840ae607a17824e8ec74054fae9d9b3998dfb162962e1a0", + "0x91fabfea828408eb161ac781a0896155ccf7d9cbefc3483cde52b35ec67883e9", + "0xaff4547e50acac2e3851620e541e96d7645682f225400793ebc0b959c6a09a01", + "0x0937506d4c9e37d57560bac5851795d6559e51df255ea2c64f2e119b88cc7511", + "0x88d66c613582fcf6df46773a1456304c4c0eddc212612b2dddab065b6051c8cf", + "0x2d6315542c9b30c8984ca951ab488906c78e6c84aec2090397d4a61ef26375b9", + "0x8ca8d613a382711420966787bf7bd541f517733d21ac4f893c282dd930f69b5e" + ] + }, "nodes": [ "enode://e809c4a2fec7daed400e5e28564e23693b23b2cc5a019b612505631bbe7b9ccf709c1796d2a3d29ef2b045f210caf51e3c4f5b6d3587d43ad5d6397526fa6179@174.112.32.157:30303", "enode://6e538e7c1280f0a31ff08b382db5302480f775480b8e68f8febca0ceff81e4b19153c6f8bf60313b93bef2cc34d34e1df41317de0ce613a201d1660a788a03e2@52.206.67.235:30303", @@ -57,7 +3076,10 @@ "enode://814920f1ec9510aa9ea1c8f79d8b6e6a462045f09caa2ae4055b0f34f7416fca6facd3dd45f1cf1673c0209e0503f02776b8ff94020e98b6679a0dc561b4eba0@104.154.136.117:30303", "enode://72e445f4e89c0f476d404bc40478b0df83a5b500d2d2e850e08eb1af0cd464ab86db6160d0fde64bd77d5f0d33507ae19035671b3c74fec126d6e28787669740@104.198.71.200:30303", "enode://39abab9d2a41f53298c0c9dc6bbca57b0840c3ba9dccf42aa27316addc1b7e56ade32a0a9f7f52d6c5db4fe74d8824bcedfeaecf1a4e533cacb71cf8100a9442@144.76.238.49:30303", - "enode://f50e675a34f471af2438b921914b5f06499c7438f3146f6b8936f1faeb50b8a91d0d0c24fb05a66f05865cd58c24da3e664d0def806172ddd0d4c5bdbf37747e@144.76.238.49:30306" + "enode://f50e675a34f471af2438b921914b5f06499c7438f3146f6b8936f1faeb50b8a91d0d0c24fb05a66f05865cd58c24da3e664d0def806172ddd0d4c5bdbf37747e@144.76.238.49:30306", + "enode://83b33409349ffa25e150555f7b4f8deebc68f3d34d782129dc3c8ba07b880c209310a4191e1725f2f6bef59bce9452d821111eaa786deab08a7e6551fca41f4f@159.89.223.6:30303", + "enode://5cd218959f8263bc3721d7789070806b0adff1a0ed3f95ec886fb469f9362c7507e3b32b256550b9a7964a23a938e8d42d45a0c34b332bfebc54b29081e83b93@35.187.57.94:30303", + "enode://6dd3ac8147fa82e46837ec8c3223d69ac24bcdbab04b036a3705c14f3a02e968f7f1adfcdb002aacec2db46e625c04bf8b5a1f85bb2d40a479b3cc9d45a444af@104.237.131.102:30303" ], "accounts": { "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, diff --git a/ethcore/res/ethereum/ellaism.json b/ethcore/res/ethereum/ellaism.json index c3107bbe4690ecf03fe0ffaa7e392bd7077cfa42..41f08e755727ff659662274dd6f999aa06e68184 100644 --- a/ethcore/res/ethereum/ellaism.json +++ b/ethcore/res/ethereum/ellaism.json @@ -59,7 +59,8 @@ "enode://5dd35866da95aea15211fb1f98684f6e8c4e355e6aa3cc17585680ed53fa164477b8c52cb6ca4b24ec4d80f3d48ff9212b53feb131d825c7945a3abaaf02d24d@178.79.189.58:60606", "enode://6c585c18024eb902ca093278af73b04863ac904caabc39ac2920c23532307c572ad92afd828a990c980d272b1f26307f2409cc97aec3ff9fe866732cae49a8c2@144.217.163.224:31337", "enode://edd90c4cc64528802ad52fd127d80b641ff80fd43fa5292fb111c8bd2914482dffee288fd1b0d26440c6b2c669b10a53cbcd37c895ba0d6194110e100a965b2d@188.166.179.159:30303", - "enode://9d960373335c1cc38ca696dea8f2893e2a071c8f21524f21e8aae22be032acc3b67797b1d21e866f9d832943ae7d9555b8466c6ab34f473d21e547114952df37@213.32.53.183:30303" + "enode://9d960373335c1cc38ca696dea8f2893e2a071c8f21524f21e8aae22be032acc3b67797b1d21e866f9d832943ae7d9555b8466c6ab34f473d21e547114952df37@213.32.53.183:30303", + "enode://5120308ebf25261c8423866a3a082e8d0f31106343d8b3b6c4dfe9d41bd900f5e03c64356ba51b6d343a951846a3f5ede5c5dd05925eaea4e4b9c35b1be9237c@95.53.247.188:30303" ], "accounts": { "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, diff --git a/ethcore/res/ethereum/expanse.json b/ethcore/res/ethereum/expanse.json index 2061231c60de6385374c906828fb809474f3d23c..99a3ab5d7802a2f0e468358be65a418b3754af95 100644 --- a/ethcore/res/ethereum/expanse.json +++ b/ethcore/res/ethereum/expanse.json @@ -65,6 +65,7 @@ "enode://96d3919b903e7f5ad59ac2f73c43be9172d9d27e2771355db03fd194732b795829a31fe2ea6de109d0804786c39a807e155f065b4b94c6fce167becd0ac02383@45.55.22.34:42786", "enode://5f6c625bf287e3c08aad568de42d868781e961cbda805c8397cfb7be97e229419bef9a5a25a75f97632787106bba8a7caf9060fab3887ad2cfbeb182ab0f433f@46.101.182.53:42786", "enode://d33a8d4c2c38a08971ed975b750f21d54c927c0bf7415931e214465a8d01651ecffe4401e1db913f398383381413c78105656d665d83f385244ab302d6138414@128.199.183.48:42786", + "enode://df872f81e25f72356152b44cab662caf1f2e57c3a156ecd20e9ac9246272af68a2031b4239a0bc831f2c6ab34733a041464d46b3ea36dce88d6c11714446e06b@178.62.208.109:42786", "enode://f6f0d6b9b7d02ec9e8e4a16e38675f3621ea5e69860c739a65c1597ca28aefb3cec7a6d84e471ac927d42a1b64c1cbdefad75e7ce8872d57548ddcece20afdd1@159.203.64.95:42786" ], "accounts": { diff --git a/ethcore/res/ethereum/foundation.json b/ethcore/res/ethereum/foundation.json index b725c9f7c02f61f2786e9289ab8435a54074ff32..48e174eedd9dbfa59810a5c34bb641e98cd49178 100644 --- a/ethcore/res/ethereum/foundation.json +++ b/ethcore/res/ethereum/foundation.json @@ -173,9 +173,9 @@ "gasLimit": "0x1388", "stateRoot": "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544" }, - "hardcodedSync": { - "header": "f90216a03b798fd7d7c51f61fdbe7a08d6d2257eea4501c12dfc5442146b85837c0da51fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794ea674fdde714fd979de3edf0f56aa9716b898ec8a0a2df7c321f2a532f63cdaf4e234227dd067f3782787db2ac892e875a8cb6842fa0c3a3f2c96c938633c7a99531a3876d544dbb8d5fac06879bea8e3cc5b6ece09da0221863f4a4fa6ca8dc7b6eed0eaefea36a5069f06ba9a61e78b87b634b5e4409b9010000a02080204012000000004100800000c0a08040041160000000740200200148000000000104011040800081808000102001180000000a80000011401020002c14008402000000100014400e20082080400000aa004100000000d10e8a0026180020882008200400a548000000201010088080000c0020800000001004046200600000052004020001800400800400420001800084002c1200040088028840004604020820400000264000005808500400410451c0808020140380c02014000440000002010422080800000240000000048a80072140000400409020020220810010020018008021800280a05008020000400000000044178000008000044410870b075e7ebe9d268353f001837a11f88379cd17845adfefa59565746865726d696e652d6177732d61736961312d32a0c92755fe5da24ea52d89783e387d88e1c2e24ac202641dd9906fc704a88979d28818d4dcc0009d0541", - "totalDifficulty": "3828700463149109414955", + "hardcodedSync": { + "header": "f9020ba0bb120488b73cb04a3c423dfa6760eb631165fa3d6d8e0b1be360d3e2a00add78a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479452e44f279f4203dcf680395379e5f9990a69f13ca02d2cbb3c43370257122898259f1e06da38fd23031f74b40d6bd022b037ecd3daa0107b3a01662ca77aa1c72cde45bd66c062d781310d7a364e5b6442bd791431cea011e451bfe7b89addb96020182e0e7eb448d0a66303924a2835a149247bea4188b90100000000200004820000130000020000322004002000140000801000081208000880800200100000000a080000000800400000000000080240800000020028a100000400410000001088008008400080000100000000200000000220804028000000302000000180200c004644000000000101800000040040020200100020100220200a00000000280002011040000000000080a00000002002048000100001000206000000c000002010000004800030000000000300884008121000208020080000020280000000010104002000004000002084000c08402820000004000001841109008410040410080080004121044080800800000000004858040000c000870c64944ccfd130835aa801837a212d8320dc6b845b452c758a7777772e62772e636f6da02078861f3b30aaea6fad290d86919dd7542433a56edc1af557426cbd2eacd60d88a68a26940894b23f", + "totalDifficulty": "5282739680501645457616", "CHTs": [ "0x0eb474b7721727204978e92e27d31cddff56471911e424a4c8271c35f9c982cc", "0xe10e94515fb5ffb7ffa9bf50db4a959b3f50c2ff75e0b8bd5f5e038749e52a11", @@ -2862,17 +2862,232 @@ "0x4a3295525bfdda29bb9a552d8dc5c992649699f5694f96ff5bb0647910386db2", "0x337389b3e800bae87fdbe5271f2167f169ffeb4710ecdcea30f08b2cefba57b1", "0x2978e1e3c2b5dfe0b41ceb5c9c4029f42d346a2123a199c52ba6efdbf1d5fb68", - "0x8abbdb4f1f88fe8900afdfe15f3d03244435d4fb871606a689c11f6420145b45" + "0x8abbdb4f1f88fe8900afdfe15f3d03244435d4fb871606a689c11f6420145b45", + "0x986dd2ca80e46f37a604b7186ce5683d3e5e114384ed6ccc39102228fbdd0eaa", + "0x27fed9eeaab228907e106872d14473d621559176063f3c19c98393215ec87e02", + "0xb743e115e42ff9ea8240082a5fcc9f5878221ab742d0db8f1b0edc6317484f30", + "0xf6d2172dff821efc35df518767fbbf59eac9fcbbf6d89246bf845b588f5277ab", + "0x1c608dc9a9114a38c14d81a75c038efb591259dbecdf00a41f0bf402f4dbbd92", + "0x0ec49c3e2e0617fa336c1f9e36bcdf6ed25e548281abf1ae0286c5d92571752a", + "0xcdd7dd5d936b3b685352a9797b52419c6f9aeadf33e5dc6dd8b0ff35a85d2a35", + "0x9bc44252049c89b94967579c0ab737e14dfbdc95eb23d14579a73f3e68a81def", + "0xe67fffbb7a6dec1a39c46e838d72f6bf7c48023a2759f2c3e4340bcbdba057fe", + "0x55008d64590ccbf16e1288121b2a885d4852dda11cdf4bc21c578f85fc7eca70", + "0x0ab47947ffc76c87f5a4d8c5eed162bf0b56b0cac11e425b44f270868f22fd8b", + "0x7f5810f6e39bca9e268e1d0f2fe8b3b172f60a84e51e61f2b9056854c2dfbfd1", + "0xea68e4e38860b5fbb0f509266afd110d50b6d34c7bc083f772878716469f7202", + "0x203cddd6d6a1ed1174ad13faf518d08a11bca1ed4809bfd9d2e8947ff21664b7", + "0x00e1378e25cf45e210f0757da309b30328b3ba3a1d270a065bf797acfd696eaa", + "0x4327597fcde5e099327889cb075d1db345f5fc996888b058d3d17a0e49708e51", + "0x6ca6195a4887f9dd5112621a13fa67463bf945d7aea39578feb1a1107c88eb79", + "0x5ea64f4ead2b127c29cb51c79b3c28b81e345e2eecd237ef57fde7adb8702972", + "0xb2c8f6e30f4b70a2983b508502cb50e6150fdac3b6d60c8458f9bc3e9b0c1fdb", + "0xdcb684901513685c0bb7582aed9ee01b98297e05e9b054f3ad6917515e7a8620", + "0xab7ac631c98ebba065ca7d6d81b58e8cee0d1304b6828ed4699f07ff2d7b0f18", + "0x21f12ed6ecd4fcb2455ce8472f01ef78081fe3f3d4eee5a7edc7b546bec5e01d", + "0x0735e851626195dd9baacc806903c5a623eb3d3902ac2514db9b088292f6ce31", + "0xf8008dd2e9b354b284425bca8b378fd2081449c30cd6bdec3a8859b0021953c2", + "0x809f2803965be44e3dc219d279acd5b3bee6c25780cd498d15dae3325d8d568e", + "0x5fe269bcbeb9d2d2b253cdf4f0f2bf669c93be6cf428996b2137b68911ea0724", + "0x41e04646fcf4a232b331a15619978ecfb13e9095ef266edd812aa1793e1a8a54", + "0x0553fdd5e662e92852697a7f41679b1a82940b5d2acdea812b0925b7ea3892b9", + "0x6e77324bca3ecd57316541eeb110f007a06359dab94131d98c245c0a137015ce", + "0x217b4e8911ca232af5cf1673679137cd720e530dd704d11987eb8fbd612a8b16", + "0x42bb0c8c8d5a2c49dce7bc4ed6f97869fe1335d3ac3f8df89d4701ebe8a609e9", + "0x2cefcc4dfddaa49857629290b1b97af2ed03ef3b8e3fc67271315c6961038972", + "0x6db8fc507494b4b5b6d7c95e056fe15571cee06adf6e7d21dbe4c5d1787b9bd3", + "0xaf5c85ac940764c2e50ec0cf57c37febdbf1e4539dbccea24e7e0dc499e4b38a", + "0x063f930786584fec4dc4aca21922770de0547b455e437a7b0b245edb9d161005", + "0x94dcc780bc2c40ede15992b2ef6667965dd346bcf00cba42e718d8f83c68f325", + "0xbf5f4beb305c3cbe0ef9142f3f588804f0437c9696fd2190c35face26db36c6e", + "0xe8ab9b3503167c91116debe3ce48d0d76e23ed1c1cd12da09876e4ee518a39f2", + "0x1fae4431c7874fa5d2787a520b27b8a0826f095398d7ca1e94b234650c04ea98", + "0x7f5d261d5c29232b5ed9c55a26a59fedda566fd3f6bfbaff11d63c4ff161f5fd", + "0x763d7abaa36d8262b659783a6a310e965a10b362e9bb7d907bef107a70f14e50", + "0x0dc66388e318c83fa3cfdd1136b621323e9d80cc2b97a84029bffd53eba93cf1", + "0xb422530c15aa6e8b4fa35535040e4b7b64de68a41937a439592be5d9afd4f699", + "0x3fe4f704e67fd2d9ac629ce20c622f1634deae9fbe0a42b02da21c4f119250b8", + "0xdd6ce24b6084576c646a2d8e42aeee919ecd2b2842964812c31c6c18adbe8676", + "0xad0b9133894fbeef5ca4562aff4caae74218922542f6b20f73f99a4e5f30096c", + "0x751d56d8e50e1f6b1473ceeed9ddf34030f0b203c9e705a8703a4988d1b0a3aa", + "0x777800d29fb6fd9f7fbab607b4d9852f50f2aa3bd52b7383f7cdc287771181bb", + "0xa34077e2a2e59e10649fe850757e3db69cf1fe0be2cd34fd4ac1a2793668f0d5", + "0xea7d03f2cbf31f66327d8dcc7eab05c9f7fe98517f3d88cedc1c590742829106", + "0x9c834993c9a684c8c726866c0a0013c3a92c275002137fa0288368268f513c8b", + "0x30134d868fdd3c9d3e17c19c2813605dd3d5fdc9867baac66312b3089f1931d6", + "0x35c44b2ab3def27f323b69a679c1536d8c4ca8e8c5dd33fb4db1c28214db48ea", + "0x4da76c0233f32f66d1117d436aab4e73a7c7d3675aa2fa0abbef5498973fbbca", + "0x02aa3319e1c7710604fc26a1622651dc319b5119a68ee4e887aba1b66f85e4a3", + "0x642722b31dd1cf026be151a590ae81c8886812d858159c1ea9c40fb93b88e73d", + "0x84942ffdfe4af44680244f7810239ce734981f2c9b6a42a951261a3955bd31fe", + "0x4bccaf057f4fc0914ff58b56f4ffefd096ee71c508d4e94f70d30f59a3c8ef07", + "0xfbb306bf85220f2a93533747e5d081281d323419adc3458327be9f50ce700dfe", + "0xd3ebe4dca06c2005fd62be1448f92d0bc8cbddec22564e3adadd11e4001432ee", + "0x4537177c35266327008bf899944a740739fce625930df5b89fec5cd43401c665", + "0x3346cfb4b3b5f6a2c34b478f823d5a5cea08bcd026d1dc1f8cf885064d6a696a", + "0x6d7d217e6f196549a651bb51500e693299a5838e23651902e54a36aa26d3cecb", + "0x03fc17e1d0df60cb54874c848627ea0a86fdd8eba989faf64fe5ec3ece8293d1", + "0x3a671486102a9dc591f67b937106a1dcee58680062a328f2fadf8fecd8fffd7d", + "0xdfa484a44d55c86e2c3b05429144bbb3e6758e31e12283226eee25d58fce1e04", + "0xe01ef4307108875450a351b5df82c5fea4a3d34a662cc87f7071cdabc7e5e4b6", + "0xd04e6b7fca513c797b05b49ca345a2102243b6e893407f45247b0b406fa7cc6b", + "0xc54725a8216701640e068f8a8ef8e77db86c7e30cf4add44f1fd125a6ac4dc11", + "0x10851f13c23fed1edd5434deeb6a07d466d922f1516a282c23ce7834faeaaf62", + "0xb4c3613b7c51412a171f1a2b36ffc01801abe4594b05ecc5eba6026139892f0f", + "0xccfa7a95e0a7eabc97d234da53c80e94b811f270bebb6f6ac8759657e3750e3a", + "0x3adf3ad22a66a6205a76c91d488b8f315c12df4955c52605724082d1f3b93da1", + "0x9cd530ef2e1e14f8003b8d8651802bd1b0a4dceba53dcedb93a115ce4ee127a5", + "0x803bf4629682228ddb883c5a81bce39a234768de6c299f65a07a3ee5895087e9", + "0x8b6af66caee2b87a3fd2643c72e8d84ec9c0c75fa271456c48cbde2774b2b134", + "0xc361af073d0a9044e2e28cace7fa6dbbcf7c05e41cc372ae13c2c5e3b1d42ea8", + "0xaf73a3936f76a401a3a137bb6479978acbcaff7b8b0f6758a72a0c772fc2ca1c", + "0x53259e3f0ed789a4397fb6897f768d526de648c4cfe50e4b88a95ea93232e404", + "0x2145a286266f525fcaefe549221f470a5b8472db76d35e820c62e9dd09f41ef3", + "0x9834dc8c6a845e685219a66157f77809c2dc52dbebdbf36a7a768aa4d2a89edb", + "0x300e7319a340f894b96281edb2697fe70c650d5e1a112760f22f10deb32ce547", + "0x0465a059e6b40cc6ac10a2bc78b6d064d6765c0adb0c20a45290e65560bd1e1b", + "0xe935237f4f93f5de4d7b768627ce849aae62d8a5d807e0398f142677165fc3ba", + "0x943f9abefc54fe4f118401b9682c44c9d7d97d6cf03ddf38d32cb694f9af1c32", + "0xf658af875a69361211c9894ff4a77e595026d4e815b3c18e9cb83774790a5cca", + "0xb5ace322f7b347062e8b728b312ebcddf6bb95dc24842c6ab783430cbd5e52a8", + "0x8ac46515d61b24567ee93b19a3bb407a14016ee4b3b99b954c74923504e5baf9", + "0xb7c2a9de470c3a43b7618fa31d4cc0b9ac879a2168ef6ed1348fc66c486340cd", + "0x9eb593e57bc9784336500e4a593200274abd0e9da1c8a16b39acdee94a0be676", + "0x361e998b3e24f213348db959f4cb65a04ffd1de7a705047fc10733034fbe1c66", + "0x47b2b5d68a3080d6f11ada3bf0af1d90759f8f08421151f6a2ed5af64974f262", + "0x002fe24eae8abd356bf631051897ac8ae1a754f7c5bdbd5fc521bcd364fdfd96", + "0xff53d1ae5e5902c1a1b66bc36f88f3264bb01f14dd84def0ea0f94c7c7eadec3", + "0x93813bf1b6a660f87410f862123d1ee694eedf4e7464a1a9e4556e3e3e2f9a18", + "0x077cf660cd2cc0f4c4cda9cec68d8dda36d7c95d04cdace3b70c8d010441a68e", + "0x367029ca5dc7cf420efed09c07561e9981b0dbd8dd1b1126ebb829cec9b5bafc", + "0xa111113ef2ef722bd548b5adf4d75ddea2a7530d4d843b022c2a54ec25ba8c41", + "0xfb2337d6125ede563770a84191a6f158ff45a00ad5006153765bbb72f51f6e83", + "0x1ede4c16ea063d9ab7e7962957b4c067b0fe25c2403deffa5b38af79c563aae9", + "0x067bc5f7409eac44326e4adced1eb688e3d9834310de73f141e90c4c63342dc9", + "0x909d8a9ea7bd84097eb6129b8609773b90296d9d01729f592b4bc50981d9f1f1", + "0x11f09438cd48f7895d90a6bb2dc9fdc342b8f11074d988b272f2c95b76f99fbf", + "0x7ed2111c775c418ac81e55886fdf8fefab1f639e243f47f2c5526ac85b3309fc", + "0x376919526e0fff65b9655bc34020d9df4c91300c0747b225ba9ac5e9adbf97c8", + "0xf6ae43cfd33c14899af2575283288239210f3c00de11364175c3a1556637830d", + "0x544063d4d8cc6b471b354b0e57773d841052ecc0110870b37f6e8657d4256381", + "0xc1f6d5b592da819a2ebaea65a0a6448f63ce09fdfcf1c15f93fa20fb8b67e074", + "0xc337d4acdae3bbbe7275c21b07b04b2ccf72a87b5666ee002ed54b7f56c6a276", + "0x8956d8aed9c2ae1b76b1aeec8210cd24cd900ad5fb14cf0e86e86ba35f5b04f6", + "0x06219a3301edd50166ff67184586c2caf2b3553b73e863cddd7a3c35b7f88022", + "0x52b99f92dd3ffa353c0b54466fea2bd1876b3af2b64953c12cbbabc266197e04", + "0x5c69f7312b8786144aa2161b3c965cbef42cfd41c8b586d117336ae8717b65f5", + "0xe57747520a141a1be0140ce4b45e2973479ee8f4a50a85162dcdcf5090380528", + "0x1f73420c464ceb6bd25e2eadff6a248ba092dbbeb5b3046ee809567dff1f34cc", + "0x1df7ccc998af1e233e61adeef0f757caa4a80270eb6d5be5e920d6b085a4cfc7", + "0x514024457e175885e55034f5c28c666611ce6bc1b8be8c3f253028f24091672e", + "0x7574d79098c1aa62802b6ae31f43b47fc5e17ff1cb3b79b7065ec42dc1ee402f", + "0x11329c45c6c4691bcd77cd97b9ecd27fc9108d909877abbc5ce894f081e0a4cc", + "0x098a826b2a276c2cbf3c67b88caaedbb62316e37a570f5bdac257f9b901d355b", + "0x56b14ea493e2280d63db496606a64f44646e2565e52ef36590bfa40e9a5dba63", + "0x16b83703c9ffd53c3deaffab57d5d3c7252cebeec4a0b1ae957c17e56613a19b", + "0xfc004311f603989357c1bffde7a42a59227d0ae6ce052ef010f8c9f4c31926d3", + "0x1da81ae9ecb576ef9d74b05d15364e904cb252a54403fb2427eef5b49c8655fd", + "0x2260c1c27d3bac445984b282a3432361d68f4b2f61165cb330854d3b8507c4ce", + "0x0225d0c83107075de447a805d0892a8affec5e24b8229d79f327021a0848397c", + "0xf1fb6333242f439dc53aff6bc68cd267f21f77fbe805b824710412b2f45b5468", + "0x9fd2c82902d6890fad571d4125c02a1308dcc05ec53ace2b3a0c7d3cc46d16c1", + "0x7b9248e0a83b6cc1e47e4828ad33af3b37cbb586295727d9b19fdf2ef62ec4ba", + "0x352a0c2a06c5036b590a640c7d080a248dc1ddc1dbae67a5cf6698108b75955b", + "0x6737bb1c9b05f740e28f1813f57a8f9d18ebfd042f260edef963fafc553994ca", + "0x40d02212c95bfac0971766e71a339890ce86cfa96e2bd0ef0b270976062c5344", + "0xa493f9c86347f4b0c5d0d29232afdd5681e7b0582575ca88574a2e04d3dfd061", + "0xb748487ec35f299c2527260495fc2155ee354c488040f8b8de7aab0c232f6a5b", + "0x76ba5a1f7c4d314bc773e241dcd15e0237de6d5d1a7f990d1d750da9e4bfe2ea", + "0xcd8a379b7dff8c0732bfd151fb4c77b631e7d018b513cd34a2c7e1be3ed5b10f", + "0x29d471c421d1624ffe4093894d79aa57e818dcf4042cf58a10fe244f1d2b43b3", + "0x50a0d79e38620fb0f28dced7689486bc9790389041fc6b2731be8908c8f0027b", + "0x1587ad177b7eef5a475045374b69ab13a38101a92fa9bf3c2d7b686b5058b0f9", + "0xd79d13f96b5a91cde57290a87678630ce212aa11974f4244e2468f2a245796d6", + "0x8f86548742ea82892829ced29ecf75947b42743e25c4c0b485f66160e0a2c1fc", + "0x09650fb97435d4c7ae472f2b6cb3b9efcfde8f2c67e6c007c6c7b6f89529af16", + "0x60221758839c34e2841c76a443675df9934027e1d365c91136d9d7089fc8c373", + "0x4a524bd23dce7b76d06158ae7c8c8b973be2d8edafab5b6921fa1c2cba3cc4d9", + "0xd6e51f25afb4eb839766ffde785a598185dd1e34870538a4a8b4eb9115a045fd", + "0x84d6430ed5924bbc86da700f650536f3474f093bc9f61e52ee4f7f74a207464b", + "0x9d2cb8b8ba17dfb9fb7562f902a43219c977ffd38697b990bb11b3708ff3718a", + "0x89909eb848d74ee94b1b73ea6b1af8058ff771491ad131d3e13e2d95c2115903", + "0x118b3ae7ad25ab96fe8a63973312c758d4ce9ecd39cc24913c26a65b4b5534de", + "0x19cd088af8dbe2d3e6ca7987d9ee1564ea2256f482840b1d2f0da85060de9a86", + "0x98bc07422cf8b0c4d1428afb759300d9a7637de2518528d34f7d237be7e863be", + "0x0c64526b393066911c7da3f17f9e652cfa38112ae324e3c84416e811d3fe7cad", + "0xa30cbfaf518996ba776b426a7068faad4ee49775db45565ebd327f9c679a45b4", + "0xd3e1a807f5940ee1a321b20b7931bef90515132ea9959df94e55529e05802cab", + "0x338aef579d9ec8acc1a0411c1674bcf213d03aa7d4bbc56707e081829ce30004", + "0x68c7a603089a220273f019001a39bfa9194590a6fa6d8ba960ddf4888b105a6b", + "0xd6a9d2c354e1dd77322800d24774eb03b589dd94bcdb3cc2b70437ed70411e6a", + "0x39c017c42ad571564792bf5741b3ae786ff0c24ebcb5ee46882ce0545b8a2262", + "0xf5caea6b23f4085c9f94c880d89b1c23eb69c03dc098b426143ae4b28969a2d8", + "0x959eebc05ff0dfae8c7e6699f069b38b5f2e5bc8c155bc35fc7f578d2d112993", + "0x199e90557d4d9e13c3e7a4b5b4ef6fe52cd2c724c36eaa44b7fa151efebbbeee", + "0x0bfe35d253227696e76f92ff13e4c545c57fca51186a16f687e76d2e6707d34f", + "0xadf8b7678f98b0e5009130d9d5d77add6e460b67b0529abc5315c44dadea0cb4", + "0x86582f3a98b218939aefd7eea438ee278d1faaf41920e8c72922c46fd56f1c32", + "0x001b728a4737fdd53cde20341fa0adec9aa8ab7c7c1db244fbd509a6c4f3f364", + "0x9207900bfdd6c87e2ba8498c0372706799604a207930eeb331580459d17f89cb", + "0xd2192fcf74cad70e6f7986a0b088de8658a14638a4c03d7ae616a88ceea00ba2", + "0xbf6f6b91742eebe70204eb7a70196ef636fc2db4d4c4f89cd5826fbf990a945d", + "0x5c1210951949402fe3b012577f1af0d3e285a0b39c3fe19c84f7930e003c06de", + "0xa16d57f777f94f032f7f2f75b2e25ebd11559effee98b39a5a1e7cc804cfbf06", + "0x1b9561fb8035ec6955454d6710f053d7ad3d8e0753aaac568ac3bc98f874465e", + "0x1a622da786425e0b65b9083a451a419c75e16908fa04d89ddc2c11d94ffe65a0", + "0xbfcb9b1d847eb40b6808e45bf3d2fb8f6588d6f103167be65f246d0733afd1f7", + "0x2317640589ab9d52e7f5e8dda95ff3b1beceacc5832341e9053b71209bfad07f", + "0xa10611b829dbb533e565ad01632b26b1fd642a4393e7fdd9b8f235f11bb606c8", + "0xe4ea4173982f342e396356b0bb0eb47e6748461ecce0f34dbe8fc084cf6a9fbc", + "0xd58399c0d0ae878338d2915eaf2d65f2d1e29eb8d551d254e68bce7a8235adcb", + "0xc0c8b73ffc675a207f73903c49d81131e6831e4c8e071b988ed9f2a5d2277024", + "0xe1ca77bafa66bb055c671978b3d1bd5df32f8e269330507f071afd627012b6af", + "0x67a1093cbddf41264009d1dbbc33fbc25a337339be0727e70c512b585897749c", + "0x0fd615782db5cf4c0a3686721cbc6245696c1bc9b403a9eaffae00968d2c8ece", + "0xc3c2dcaee8954ca86d9b3e4e98c4bb4f6b6bc183f9eb062016c5a25b2280717b", + "0x70265915f5ed94d589afafa3d0d0eab6310195cc690aa82bd65e4a488b398c58", + "0xde3fead8ce29c04a86dcb081da2cabda5366d28de5ebfe2f8064780413f71edf", + "0x0ae43394fcf6ebdabdcc1ede314fe779eb61a12eab807a9d3437d9167e2247e3", + "0x3241127e2c7fbb3db9fe0c602b0c94e22c684b7910ffcf09c1c443e567f95e4d", + "0xcb94ba286eeaa1129b490bb5891e603fd35e85c97c2132c1216d1774f9017f35", + "0xbf396cd23c29ef21fb535880ef621457fb71981f856f2a09c494cd005d38f981", + "0x3df0c90ed7aba260e820ca1d28ce1778149e163524e306309aa346bbadedcf2b", + "0x66a2724f7481aa3ab83a8f1bae2caef8a7bc607c7ffd5bbb1cf3766741db804f", + "0x7a0c3492f4022322e10d81bc10a5db9aceec81d1ab70cdffd31418b79d750fd2", + "0x96a826cb667924ed75ec708bf07cf4c7c05f84a0132e154b71eaf6e193590e87", + "0xcc7030fe617c318a31984d04e3d7f2ff2196894bc429f3f64bfd69b969dc9b56", + "0x3fa94aae223f5aeb593246f1a93d6d694b48946c09d879e791f1188a9dedc4c0", + "0xd49e51fc324fe58159575c0c24171f4eb1aaf58ed8e1311c3849538c8cec3ce1", + "0xc474123906eae5cd48a10e0d93fcbbd653f0c6d25275f827d4fac51e696c3d91", + "0xacd7b790a19026fa3f3b0a354878d4fcd79dc600f7ba5cedd2eefffe1ceda76c", + "0x41b311a188cd7ce1444d258dc379994b81a895226276c7bfe5e6cb29a5f92142", + "0xda0ae01db7f73f07fce46b94c24d6e400598378a6baf01123dd710c5425fb8c9", + "0xe62e08175a02b575e28b9e029a838c365e3ce4278f60c2d3b5d529768a4b47c4", + "0x99b804c8d0feda7f9df961527d634fb8b2d477a362e1d8158856885a13425fa9", + "0xe73597be8ef7d78f862c7a94a8ccff17f559816eba2f830821c6f6436898f9fb", + "0x36de9ee4c80853c865b16904cd8f6c0e9a99ff9e7bf05100bfbc76789cedd4d1", + "0xf480b762872373102393461ff3a21323a1df799c315fd167780a45d7bfaae84e", + "0x303b66babd21e72449cad413e04bdb0bc3ebcbb84a79dd30ed7c972c5341b82b", + "0xbf111684fbe44a973594f31cdee2c94e807bff9cf7584c22dcd609d8234f6e62", + "0x79b26cc3bbf49b6f25afbff7e97e4e45f2dcb359095fdbeb7fb7addee692afc3", + "0x2839d620cc140ba838ecba6e7e52db8cf7b5cd4cf4857f72f3bfbc9b1cf0fbd9", + "0x93074136f4eec367adcf27955d38efc0dc6da514693bfc97935c7871793e35ea", + "0x21f5af18a4cf0096b6e6a3d4c98f4043cfee5c4ee085ce106f86b713160144b8", + "0x90d16b403e2deca6cd5c80e52eba0b84b2875e1dfd75fffb1a2f82bc91eb6942", + "0x8a5cb6854c19a865f51e3ee9eaf8e843a97b272f6467634ba40e547a435ef624", + "0x9afe42a0dffca8ec063c83908fd6237d6130c9dfeab57078bdd02b6ac6d0ea07", + "0xa05cc6108b475d3e68e280e98f514cfb6df4f004e1b7708fcfd4528d346bea6b", + "0x71f10879b875caefab46669e8525b9c0487bbe3247e43a6cdb1dedbfb4d4ba33" ] }, "nodes": [ + "enode://81863f47e9bd652585d3f78b4b2ee07b93dad603fd9bc3c293e1244250725998adc88da0cef48f1de89b15ab92b15db8f43dc2b6fb8fbd86a6f217a1dd886701@193.70.55.37:30303", + "enode://4afb3a9137a88267c02651052cf6fb217931b8c78ee058bb86643542a4e2e0a8d24d47d871654e1b78a276c363f3c1bc89254a973b00adc359c9e9a48f140686@144.217.139.5:30303", + "enode://c16d390b32e6eb1c312849fe12601412313165df1a705757d671296f1ac8783c5cff09eab0118ac1f981d7148c85072f0f26407e5c68598f3ad49209fade404d@139.99.51.203:30303", + "enode://4faf867a2e5e740f9b874e7c7355afee58a2d1ace79f7b692f1d553a1134eddbeb5f9210dd14dc1b774a46fd5f063a8bc1fa90579e13d9d18d1f59bac4a4b16b@139.99.160.213:30303", "enode://6a868ced2dec399c53f730261173638a93a40214cf299ccf4d42a76e3fa54701db410669e8006347a4b3a74fa090bb35af0320e4bc8d04cf5b7f582b1db285f5@163.172.131.191:30303", "enode://66a483383882a518fcc59db6c017f9cd13c71261f13c8d7e67ed43adbbc82a932d88d2291f59be577e9425181fc08828dc916fdd053af935a9491edf9d6006ba@212.47.247.103:30303", "enode://cd6611461840543d5b9c56fbf088736154c699c43973b3a1a32390cf27106f87e58a818a606ccb05f3866de95a4fe860786fea71bf891ea95f234480d3022aa3@163.172.157.114:30303", - "enode://78b094cb27ceeecbe311bc278f4fde8b9a265db42d268c88484c94d7a2d19b82a1bd22dfd6c2bd4d90f9b05e6d42255e6eb85de15f73848ff82ed0be9cdf5202@52.233.198.218:30303", - "enode://00526537cb7e1aa6cf49714f0635fd0f608904d8d0693b949eea2dcdfdb0abbe4c794003a5fe57aa662d0a9215e8dfa4d2deb6ef0101c5e185e2617721813d43@40.65.122.44:30303", - "enode://4a456b4b6e6ee1f51389763e51b80fe04782c762445d96c32a96ebd34bd9178c1894924d5101123eacfd4f0fc4da25b5e1ee7f18832ac0bf4c6d6ac81442d698@40.71.6.49:3030", - "enode://68f85e7403976aa92318eff804cbe9bc988e0f5230d9d07ae4def030cbae16603262638e272d19875b7e5c54e296ba88ab6ec6e98face9e2537346c4dce78882@52.243.47.211:30303", "enode://1d1f7bcb159d308eb2f3d5e32dc5f8786d714ec696bb2f7e3d982f9bcd04c938c139432f13aadcaf5128304a8005e8606aebf5eebd9ec192a1471c13b5e31d49@138.201.223.35:30303", "enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303", "enode://3f1d12044546b76342d59d4a05532c14b85aa669704bfe1f864fe079415aa2c02d743e03218e57a33fb94523adb54032871a6c51b2cc5514cb7c7e35b3ed0a99@13.93.211.84:30303", @@ -2884,7 +3099,6 @@ "enode://1c7a64d76c0334b0418c004af2f67c50e36a3be60b5e4790bdac0439d21603469a85fad36f2473c9a80eb043ae60936df905fa28f1ff614c3e5dc34f15dcd2dc@40.118.3.223:30308", "enode://85c85d7143ae8bb96924f2b54f1b3e70d8c4d367af305325d30a61385a432f247d2c75c45c6b4a60335060d072d7f5b35dd1d4c45f76941f62a4f83b6e75daaf@40.118.3.223:30309", "enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303", - "enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303", "enode://4cd540b2c3292e17cff39922e864094bf8b0741fcc8c5dcea14957e389d7944c70278d872902e3d0345927f621547efa659013c400865485ab4bfa0c6596936f@138.201.144.135:30303", "enode://01f76fa0561eca2b9a7e224378dd854278735f1449793c46ad0c4e79e8775d080c21dcc455be391e90a98153c3b05dcc8935c8440de7b56fe6d67251e33f4e3c@51.15.42.252:30303", "enode://2c9059f05c352b29d559192fe6bca272d965c9f2290632a2cfda7f83da7d2634f3ec45ae3a72c54dd4204926fb8082dcf9686e0d7504257541c86fc8569bcf4b@163.172.171.38:30303", diff --git a/ethcore/res/ethereum/kovan.json b/ethcore/res/ethereum/kovan.json index 02d22bb4196a67e04dac04ad89dded105de9db77..1268de55f26b6b0c7f264cb4350e60aa8b4f706d 100644 --- a/ethcore/res/ethereum/kovan.json +++ b/ethcore/res/ethereum/kovan.json @@ -56,8 +56,8 @@ "gasLimit": "0x5B8D80" }, "hardcodedSync": { - "header": "f9023ea032ac0e3f2dcc2042b6b47cbe502d5c7dc39d27d147e3273e17fbdf7966518a69a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479400e4a10650e5a6d6001c38ff8e64f97016a1645ca0c97490dcc8dc3a85050fb7df999bd772c3ab40cababcf5df4ea7141a9a183353a002bc045bf48b7208ffc5764f48c35162f488bd1213c5e96b3b06c0dd3a32f24ea07041b8f6d8db9964497fcb512b3de8e71cb87d89ab7ef592caff47b444f30637b901000008000000004000000000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000200000000000020080000004000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000080000040020800000000000000000000800000000000000000000000000000000000000000000000000000008000002000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000200000001000400000000000000000000000000000010000000000000000000000010090fffffffffffffffffffffffffffffffe836ac001837a1200830a4245845ae02fd896d583010a008650617269747986312e32342e31826c698416b80bf6b841cfbb3c579ee8e631a9b2916de71778e0c4f477d1424ed65cc9ca7958899c4cab09721b8eada42b49c146c870291efe475bb8d88652810819dc03ebda2659f3f100", - "totalDifficulty": "2330161772435517944412054200548742154048251186", + "header": "f9023ea070413bfe3ceb9160c7dee87bf060a0cc5e324f7c539cfce4e78802ff805063b6a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479400e4a10650e5a6d6001c38ff8e64f97016a1645ca0f8ac12c30b4fd0d27a1a50c090659014574b554ba6e9cdb76f57efbcfbd390a9a0b474ac6cc4673c17c5f511a8b43cc44dbb01bb028735830163667d7a3a2582b9a0bcd44b7c04fa24760df7d733ca8ecd99e8da89de0716e6017fffa434bfd7519ab901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090fffffffffffffffffffffffffffffffd83755801837a11f88301d8de845b27471c96d583010b038650617269747986312e32362e31826c698416c9d1c7b8418bc805f23fb01fdd498b37df5519f49691d65160fe6a6794b8106e2ecc4782407f0dae3a512546b7d93e89bbb2a761c750553deeea1f9401231f56ae0ccb059201", + "totalDifficulty": "2654916374389120143910668097894183918476475680", "CHTs": [ "0xdb9557458495268ddd69409fc1f66631ed5ff9bf6c479be6eabe5d83a460acac", "0xd413800c22172be6e0b7a36348c90098955991f119ddad32c5b928e8db4deb02", @@ -3474,7 +3474,473 @@ "0xce0b41fa28c47f7a420ea5efe6ec77e413f22b6f67e9fd8f6728ddd73e5c6baa", "0x9e7b2c49c92a224a444f4f91221ac2173993decf40b21118ff5962dea3969fd1", "0x6a611eaca85f609f1f79bfce34df97fb975f450e87e1f24d9a93b59ee0b0083f", - "0x70ec7e2b800c43d093f7b1dec60e6743244b4516394ff861e8fa9f265efdd28d" + "0x70ec7e2b800c43d093f7b1dec60e6743244b4516394ff861e8fa9f265efdd28d", + "0x7e80326c6eaf085eb48567fe017f21354bf202072b1a2d7a94e9d76d0dde38aa", + "0xea7baad3d12481364a0cd85ca78d71e3d86738938c4073a90d9e5b71162dba6f", + "0x4e3b7094fdeead9a0275de1aaa590fa5d45fc57d164709ca56f209f1285c3707", + "0x12e56845b0e6206f75fbc6fe75fb28167fcbebd2571fbfa2373707af352aff2a", + "0xc7dc260bf1335f5002e7351b0ecd446379c71520e9d0f086dae2eeb37301b644", + "0x50f25018c84c40c0b854dc197a82e15fd95ff58bcae5226aff17ddf9f44f1e2d", + "0x0c71edfd14a52a3c18f56c0e8e94bb8a6b78a1e50736293983d8539bf02b0914", + "0x9f914ff32cd2535bf2f0e430a6d4f85a144480049d29717c0a28d0c8ed02858c", + "0x97c1ebee13b480651350851b8438fe7d709ca397985c6fb392c6e56102ac926f", + "0xd75ee7dddc445d9f6361f2eb079a20a0d0a0ee9e7356c219647081f3d778ea60", + "0xbbc2f0f7dcb1bdcc0390c75d85e37e1b393b8cf7529ce79fdca968ad2b330691", + "0x0eea82ff391f47f7df4e04e0307621e1d8b6aa976995f6eba3cc95253c9aca29", + "0xeabe8946289ac1a562ef5ee5c553129356a4fce4e3c108dd723678bda915e4a5", + "0x4e3d7341bf8f7269481cafacff7dc5146f33d27e5df25a0504a42caa1f94c3f5", + "0x4681710108d0aa64c8d0ea1405431334ff66977169c12c3e6f7cf76479dd5c56", + "0x62cfebf32a022ba6667365f686352407e6129c107cb845105780910c9c405421", + "0x9894915fe24dd0aa6b4b639b17bfc60d9ca0848738f143c6287d33d0cdfd2a1e", + "0x00d0d949ed8c01b85b8b9da7d833668eafe52760d4725c4266347948073b6827", + "0x5ecdc5570106bf27ade344bef187f64bc8591a8d9905e56ae52ae697566c5575", + "0x754ea4f76f4b3ad9c7afdd856dff50eb161214673504b232d4a63a0a42883145", + "0x8641f93482761679fa7397dab41d8a9495a95b9d693c6be903ad2e5517b6278c", + "0x78ae59068cb5011d88567d919a3ed02f05beee15bfeab463f38fc39d7b25aa47", + "0x8f8024181efe6a6709a9957d4895734d4552d63e399d806f31305e50d94c6c16", + "0x40f098cc8a06180c95ac29f82a86d78951bfa1a14cc25e4cd8da929a0871e979", + "0x1c76272e776ef34c5e202b476577ec3ea7613a332dad195afa1340b874648ea3", + "0xc5492ca8fb2784ce1c3ad733137fd1b9d946fc349e06f899530d37fd6628e9f6", + "0x0b7034da8e247df9b12dc65b577f3b75c4cf6ecc557ed3fce1a40f4455da5066", + "0x2d5b70732a72057a6bc6d5d74e2e2fb4854dcc17159faffdbda00611173e50a8", + "0xd92b2ed7c324bd17569cbb18b317aea888e361f9b998b58ec8af5a838f7988a5", + "0x709d9dd243ad51600cebd449527debbeb8230afec92e6061b6c0e6010ff765d2", + "0x277d7db1198e452cc42f7c814c8796e448a8321aa730e6351979f56f64f2aa08", + "0xd1ebf26edc0e6dab23c7a6b9a26a6ac6b5a5eb8c17c355c7b5b6306c35d25634", + "0x7c8d98fef8ae97c2d84b0ba15534656340c776e0e2f303ee6c0b5d72c1be048c", + "0x98d4de7e589c593df79125171b2e02ea165d548fce644563a3ca1f455daca5c7", + "0x4a69319a826ab82fdd111defb028c67f582063335325a680597e4ca972881210", + "0x57f90e73b19a459899a25eac9958508fbb015edbcffa33a8a09ee66ec3ebee3a", + "0x9772aa0cae90e3b96a5a907b6bf975e05e664b6f6bbc98681fc71ad5a3e0b42b", + "0x81272c15403b6bc823541a12502b89a5511c198fa2f2a316a81975c77678f938", + "0x68ab134f9289300446f3dec929a2385d6ebe5e087aecb806181377a911602e70", + "0x135c03ac38c2830f5e43b09541e0f69899e79a83d9ca2d5a97a37fd44f4c1901", + "0x3f579b811867a044bb1837f3591cb92b3cdb806651d87a7a887456338c644f74", + "0x17d3e74034424ee46c93a106f8322ff9fc3f3cd499ee347f0b2e388dad853028", + "0xe6fdee346df741d742eee7112aa685b5addfd907ad08401c9c1b27475f71021c", + "0x1c0ce4a7d444672e9118044e3ac1e141d85c9030f14f62c0bba3f2b409b93ae0", + "0x76548fbb7c106bb0ff13db5c7153710d3bcd4439aed48cee4b68a8e4cc978054", + "0x1723acc5b7d8a7456471c598abc14feba6f3702aa732ffa009036cd9773d7733", + "0xb01c82d4eaa7c5e1cb4ff0b0dda7ad1558418c3576705cbce343b340b03ade5c", + "0x1d0326e10f506633798707287553cd7025246773fe7975c8a19f4ae3e59cb9bd", + "0xed9eb55217788e468d7e5a586429a80822e89fda2d24151882f1716a6491602e", + "0x0b4fc5e070deeec3d5d33ac8c5a9da85e594f03e2550a0d84a7e40571dba6f4f", + "0xa56a7fd51a720aa2c05c3b1d73bdaa9cf8e417381731f25a4d534db59ef5e83e", + "0x44522186801bc1e053bb5dceb8450117b6e16de04a789bba4aaba25580fa9d98", + "0x3b74841d03b2a2cf79b7c4592ac9ae180cab171462b55507f2126a3dd7884851", + "0x8bc3afdea84e0a559bf844f964fff3af35d2b2578c3b666b749d8f7583b0192d", + "0xfb9ab198c8aeee666cd69fe20598722cd187cf349bb5b1db396fab23187d2335", + "0xb56912ae6bbe67f55b1803e2a93728ff2615b65f54f3d88424de4454f6b0a92f", + "0xfc3ec0c31f6999bca315e3f122dcbd1bba7f31dd45b5e936f79231b1e61b4d2e", + "0xca247a4196143fa609f4ef7b5160528b89a14732d33f84748911aeda600e053a", + "0xa48b8477fd330f3432a928b3fbb6c2b16b37dc065703f892b20c86c16459d4fd", + "0xa793b8d41d239f047e1a2b446323f557e89307dca9a48de78f147f62ea078c33", + "0x1f4543fc48bd23e0b043719ac1bb39afea92ddc5774f34e06e0a14a58036534e", + "0x3ed6a22fcbb2344725c7228f2ac4543fb9d3fc835d4ba9d94fb807481557b7d4", + "0x121d1e123ca87801e5336b9de23dfb3c5bd42452adb0c52197136b210ab38520", + "0x4ad96b36710da80dab7128cbcd36bf946824b45322ff10f21ec4037d09104e93", + "0xa30733e12726b6855ff857358cf26191734c811ff91979ce68f3f4bd0e3740a1", + "0xaff3716f450ad70cf575313f3c311edc425140deb4121d744d1a9e366772618d", + "0x9771fd12411da7ec1bdbb3bdd5d9293e1e691f2c9a4a7b705710cda9e6204458", + "0xbd88569eea71d0833810135d6e2898db7acfd85d00c586ff755332e44d2039ad", + "0x214e1662b559cb1efb7a49a97b01778e606789d641025e1e255e7474265963f4", + "0x1b92313a0f069097213fe62b51680d050f6292e5ef9b2f2a4d5217b03d1ea3e7", + "0x88b0faf7930fd989537d1c3e8b1f2f7a6e9cb3b1117eeb5829030f9250277dce", + "0x22c4f4dac7ca24b2d6d524bc3293eef5fd73286e2928bc3554652b75c12111c3", + "0x45af9039d3783f75bec64d71dcbe829bedefe2de5cadb592dd2e9af0585b125c", + "0x60fbced492f778db766f3171c1e346e5a0498086b657da5d17817e05ab194496", + "0x14d6adbb6fda237b95e8f220844759f8f32e976147138c674c3c060466bb9d8d", + "0x1b27c87183f787d614d4e187ce3f1c19b794f933b33a1cf8b8c7f66443968d7a", + "0x08471ad5316cfe0bb68cee4d624d76c3725f7fea983a42c49473a06ccd072175", + "0x45673d37daa58c1a84bf6676386b008b2c80287a648490629d2fbd6fd6095b36", + "0x19e4615dae6265f6bd96aea8614d2212a5d0b1895f2d6fca5e3a61b96a9b4fc6", + "0x9b01ab59ae3b7da27f73c8578036d3295a76f529e7c3460f3e05f8d04f3c204b", + "0x5fe63007389fd90552fc916ccb5bd547c23e15dbc7293d930148874d59400776", + "0xa862a5eed290236b6e87f643cf80890b2d021d68952812765c97fabcb37d4a0a", + "0x38c18afb3ab2908625feb753e4c5f9b0738aa6f92641a6d74cedd742085389ab", + "0x7045a71a34952d008c7a45f774ad095115b2b39c66ac399666875c091f66a080", + "0x4e5df6d0367eb18a6b3a6274d54a85529156ef43e089d01ea270217bd91bc099", + "0x12f5b3943a86799e2601fc3a4a1fb165b113e8b6e30af6631cc96c8b02691338", + "0x75816b7bc3777bc579337dcc1623acc080eaa28a0d269ba12998f8ac28672fd0", + "0x93da08b8deb0256046bc0fcc1f7f320f374d778fa822d9266936ee14b7b605cf", + "0xa7a8837e083b1126b978a647ffc8ac454fb341feb0187b1bb740a311e27d794b", + "0x947942f80495b860e402648969c13b1d67644a610a8655e6331d917ce9d9ae66", + "0x8e59cbbb6225ab2e0a905f26cef3885727fe29435e83edabcc119cdcf01edfa6", + "0x27382765727cbc0df44ae8b56c973e8da67d4fde2e04455d00f299f9731b94a5", + "0x6333067c15a31397bcf1e16dcaad3e9eee2ff3a4ec6fa203575110fbcc9a404b", + "0xb624f0fb2bce352a20bda177528fd445efbca0fac5575dbec526df4b6ba1f967", + "0xe211244c1887ec9267c7455bf64cdc473845df8500a090bc1886d4ef15d94bae", + "0x459b10cb3605a7bbb537b237d7877e5ec16fedfe417ac434214f1e48d6cb9db7", + "0x00c6cb05293954996edad819dadb9dee132c47e0bff4f40883b553bd46465861", + "0x75fdcbbae564cc730b8b29811efe8550d3b2d889f33788c4c9c65ec8420be2b5", + "0x48a6349cdd9065fe2312b7434e5b382864b71a3a30f6bef527fb767641033024", + "0x2d524c91dc1e4c0bc7af72af23a23dea03023f4ac88d5360d39fde979d8c7c12", + "0xdc785ecde7cb892d935cddc32f3d2e803c36a1349e7c7303a063813ef1a29e6e", + "0xc918b72e98f95d38f7dcdd74c222582bb8647d54ac05e607ec71a5230007b046", + "0x201c1d511a764472724c906c15d754584dee39b682104876e916b83662409039", + "0x8524adc2f89a500dcbb273fdc8338800e4a12df36880dbf004e85d6dee27d0ed", + "0x19ff16cb234e3f3a251b57a572e05025c5f469d40580f73adeb7997774678e5a", + "0xad697abefff1cf702f041a4ff551ec2dea735e8614143553dabe82232eb1fe23", + "0x2f82cb8f448965874012ebe4291b98c9c2069237f35dcc86fd44bf3665ce8582", + "0x5204cdefbf66a6ca03f3095785754349ac03d148cb260040c30dcd245358e69a", + "0xd9678cf8987d88e40c7dc0fd369c10aa0149d78d8795f2180c0b6261847f6d68", + "0xb83cdf2e9cb8ad90c17d04d9a7645c6a3d63892c500354c95266d6e727d33748", + "0x3c448dbe297ec1e8bab5481f381d0e81700970e64ee3148b80f255e7d3c4431f", + "0xa535dae65ec4ef42aa05c7a110db91d419ef56cb78a528b6e06825488a539bcf", + "0x60660ad6d027f00f2e84df6f8ac7514b834553a3933ec17e7af6be3f4137098e", + "0x558c04aa7d8d828d40d55e1d27cb7371c89b83b5482909f6a490e1f8f12c0e78", + "0xcebd138a8d5eaabc37145801c95f5fb3073f98bf08a4670419561e2d0f798b8c", + "0xe185cfd8b4dfede3bf2eb898cc51436cc506705b8c8df97a0c62312428b9eaa8", + "0x8329c45d28e8384be558cbfe2c9af7d0338d098935081429a2a5323d065a4f6f", + "0x3846ef3ec37b442c2b94abea75141bda5b08fe6a4381c777dc7c15499399aa11", + "0xbfe141ecac9cc63cf17a5e5fc95745fa7808133e1bf8898ec9c06810a29bb84b", + "0x3d81adb143559eed09d410aea093d162cb5e378ac688665cedff53e37362c7cc", + "0x48bbdc92d5236ccd98a8f1803d512495ba412021d02f723fb8f7209a11198cde", + "0x588929461728d5f15fefe68a26218cedaebe9890282cc6a2be9f8170812b3f46", + "0x54b514ccc3cbdb1cd902ae0ed7b5ae0f91ae4118f54ac831b76f8ca8dd009323", + "0x6387311a39c020e1fbd3aa4de7a92b36da549f088043343629ed912a47207ba5", + "0x20c6399f2509cfde9093485d84aae197351bf688ef700f6b75ec43acabd635f5", + "0x6b7db93566738b7a09f004490f02794085c8a49b8b669984fd6492477696df70", + "0x70e080cb818578443f092d2426e76b898b077bd09a83449b1d615e241097944e", + "0xb2af0965e3a22fdc87b46cd70bf9fb69a8111974cf0133f63ff2fd6bc6e41367", + "0xaad34d97ead1e29ebb1bde538691b50690f6860e4ed8d9bb423c395ff0a37456", + "0xe55ad2c514b12c91354b18ae577a229b338c37c620a7cad86f7b4bdccb56da1d", + "0x4f0b9cd3797887659aed4dcef6ecd2f022fbb77b83779abf068c12ceae6f15bf", + "0xe4087d8f1bdef1a7b3a5144cdb5f5d2d553115a4cfe6b72beda5a929eaeec57a", + "0xc3c1aff8ca588e7fa86d2517718d76ee301e7a4fe6f1c2341b02a12d1534fe12", + "0xbf4d3ea7101078738cdd2fbd691b6b60ab7b3dba56b7595f7b6f706178981da0", + "0xd24b2320e7c3401797aebaf1efd0212596788a23507eba9e92b51551e1b2fbb0", + "0x6b14253803767b19ca3cb24a95086c8d7d3eabdc2bc2196be00139f89afd6d80", + "0x3e3781d97b5d8285ea66c68512157a70ed198c3c9fac4e4c797d3b0e878fd19a", + "0x6c1665c4b9b68d0eecda5be2530b142af404e6e6d6dca6802877fbc64d52a16c", + "0xc9a1e9ef2dc8d230c7ffcf46cee9b7b93e4bffcacf3ff9a5baf5103156ee1621", + "0x2c9d18bdcd673d8c3cfbee0b109255a83a83e0a70172676739b55d71519cd91a", + "0xba052c6ec43b5226718ae924a2b2065d52dd42c53bcde249a4fca0ea9e2bf32d", + "0x2183368bf77cf039f4e22ff970ab84f6eef3d69a2a081d2d0b0fdc023346277d", + "0x25347d86261fecbf1aa99b6a1e245bfb7a4d3ca3a1caf87a70328ea86d528c6b", + "0x4506c19fdeff0b1763516120996b864174bdf33cd6ed8f3642cf522d7453897c", + "0xfa0dbce75686d24e02884c7c44ffda3ad81c99d2c2c820533cf0983e6cafa258", + "0xea20b4d719c85b5f0f9bc3581cf0b9db484e5ebae5b9275678710d9a4bf82937", + "0x3871c8de36feba00ac1e0a5fde6770dd4259b934c49db43232372d4bb9ed8c30", + "0x0630cb6a0da32bdf5aed6adf8f75eede08dd8ad4ffc6f662d63c7d4f8700a838", + "0x09f0b8b297163a9689dde20f383dcbf3accf9b9fa266b74240fb4e26e737a13d", + "0xfed679cdce753b97c3d19778ebeb7616f1f308d6cf57143637c23150dbbe1114", + "0x0559b097b7974cc3bcf176f5d4826b4fe47487c9bc461b1fcd89182a5fd739c3", + "0x799d0651b0e9a12c74dce11ec9af3ed15b762a1f8ae35d7516ad73833691e17e", + "0xda8e0a23e9ef595ebe087eb6ddffe63a933a54783ff0238cd232c6345bfe24b3", + "0x454b1c9f7130ed4bc573eff46cec616ddedef3c14a3e06ab0e03b48dd98709eb", + "0x73b0f4158f7b98180f282768776cb1b37d2f70b7a4c923324e20933f289f7c14", + "0x2f8266751554c995018c4497b150a0f76e8a70715c3e33f5745136227a830164", + "0x0a1a9d2252e93028c9bb69cf1fa9ae1090699d960baa15b68f6aef9678788820", + "0x8b13ec3689127f51d5e82862b380a04162880aa1e1950a82fb9115f83bfea27b", + "0xd0c56341ecd38ad5ecc8c24867d64a75747596757afdcbcec26174d92e42ce59", + "0xb75d2027372551198eab90a3c88beb48a61224aa50b3f30a9deae317a02e3dba", + "0x4941ee21957780ceae3e609baa52a94afb7dcd9fd7ff8446fa044d0bd3ca5095", + "0xe99f45bff96e3015cc698a19dd2b7f25611e642fbc4cf814bd391278a3a5fc63", + "0xeb7847c727c6fed9604c19d1cf156d9c1d382eb338d62b600da4fe5a9cb32f9c", + "0x8718e416eeb9975a729671c15e0812de63dd45875ffc1dd2f07d3353e00b78e5", + "0x3c249822618a0f5861a90866d95f758d1af741951acd38575e7e80ffe4fa3d61", + "0xcf53052c009a76eaf5f629c471e71ed0f850a201c216f140646b804f5143c8e3", + "0x68d4ce1820fe96d02aeb10a178ebd16aa6cf5dafb36e6190be20642bdf5156b8", + "0xf45f0d504dcb1d37fdf73a0cbc0a3c1c0def4c47f5f3fb1290db85e86eff05cc", + "0x9786adb9c499160b9c57af19c40d3cd1c8f49544084527f1145db275320109a9", + "0x2de8bf50d3f2bdfc7a69d9d84d8ca0e41cbb9bf193364633eb984dc5777391c1", + "0x7f39b95ce80f4b91541d81741d59357c4f1feadf6beb85968a5baf4eececa375", + "0xda4faa35feca143f1f5dd4503c456a448e2e8fbe0033ef501146698f72ae07a2", + "0x69d03b07980a0256ed44d16c0084c7b72b07ad433b8b77b9c175858a80113f3a", + "0xc4f0286c31e1f69ec8611efbd82798add4247162ca01674dfdab4e89c807403c", + "0xb3d4788c109ced056b7837b1c6a9ebc7d296bbee42df618c2d32b2ba7342c2e4", + "0xff111f1b94658b12baf7e655cb92f713f4166580981207f13a55e55b13fc375e", + "0xcccac759f059e428771fb21ddd4fde11fc4342d6d9554912887c975dee85203e", + "0x88c0f0974ff6b07f53b464123924e2066cfbc07e9b8782bda5e116e175268de4", + "0x7b1a526fd2af68abf236f9ea30e4802eb49c3ed2b9ed983916fe8cc11a3ef08f", + "0x1032304f9e041de697abf23a0b50858008efd95c4e2e6cf24c524b234af758c2", + "0xdfb69e60d16a021b267f15659c72dd566da9bae1775ee003c207b3fbfc3daef1", + "0x4de8251aa14a1058c827391b62e70b1b2a09b4d169982656029ef39f734a73c0", + "0xd04aa0f4fb73f96b1948d9099be3a3ef9f4bb1755007d692f995fd49c344a005", + "0xe8bf94d4615e95aafbde3669413e40670184088cfb023f9fdc128fd482c78d63", + "0x3ba788d9abf5242973b1cb7f8f6e2d5d08093b8a736897e4414e524826643fe7", + "0x16ceff7c5463b0080c62547529b4b96a08dd01d49d3b2527c61ed151097e614a", + "0x0d7d9a889d28c14047b740fe86b68918bcb7f3cd1c29e410ce9ee2cfbdd95764", + "0x2d31827b3af0bc45349bfe388d503215bc882d90bcbf2d35bc100ae95f1cdead", + "0x84b77d4f0b6076c88d985125e73118e892a3d9c41e4ebebdfe16bcb435253fc6", + "0x2a47008833dea7abd3858a580d87106b57355712df26e0cd2ca4436fb6deca34", + "0x44a5f14487bfc776bdaeccf1672040548afe787b1237945aaa4ecaa73ff5a41c", + "0x3ee99634e1f6fef4520538f32fdbf31dbb77e45a88e9ca56e67c45aa9c3461d1", + "0xfc26a8fc353fdfd173571954755d8a9a68157754f1162f4b31f6d8f2b9c86577", + "0xe360df35dfb599811c35572a67e21c6e9fb53ab13c833155e6f320b23ce5984b", + "0xfb9da18c11f56c2c43d8f38d4efaceb681ccac318cce0bbb0823b4f954fafc9a", + "0x0b9b7b663ff8d9d42050aabf2c9d8a1cbc39aae18ec7e1d1e17cd213e89d8998", + "0x3e991008da81b6f383e6e5b7499b5af8ef6f5182e5af863d1d0087c6015d75f5", + "0x74b1a66ef34f589deb51f8f2fd9e1e422c8703ea027c21387cd45e522f4146a3", + "0x4285fcc0deceeaa9bd076fbe956950eb4f3678f2917357fbcb642befd3c5c2a8", + "0x52792742145a34104b19b72655cdeab1b5425476fcd68c9596c265cb7becd9c2", + "0x1a8b6fa728cc7ead440ec82a9ce3aa0e9211d8a9b210eff5009ced5e6fa9d9a7", + "0xc8e72083635887f82299e02d331ac39c61b2749f916a91c1db66943fad9efb75", + "0x587bc54ae5c8944ed2d0dcb8beabc55988dc32c4c69ce67f0c4b187badc3807d", + "0x19629653ee703764df75ccb9e03c4bf73cbaa0a441c95ea1ecf0cad9f63ee997", + "0x9f0d38b7b39838df6ddc474aca1ab5a485bc95dff8cd7ffc9e1001dbf58eff5a", + "0x3973c16d0d93ae934cf37c626545e2d938a28fccf359aba3b6676f7be02331fe", + "0xa61692812f3ee1abf7c3bc4ed63d94cac20b6c29214ba3489e8259a292a986c7", + "0x7ae72f35e70c9b7da0103d34ec208a87b07242eb7f2e62f5c1e3def6dea24f9a", + "0x5b026f1a5cac5375a40db884e19f508b175417e7a2994864e321f12494367f40", + "0xbc1fb39c00f9c4fd425b4322122174e5eafd71457e8391b551712b3237d0534e", + "0x7d7bddabff7dd77f2a4814dc6e78bf75024ad2a399939fcf81a937dc2f2badce", + "0x4c978814039087ac7b5f4c9f648d3f1fcb6c8384763626c0897ff5ef32919057", + "0x13ebc79e9f13a2592fcc8f9133463f504087c1b948ce044e05c62a8804f1b07d", + "0x80bd912a6162263b0d37344089605fa4a947c04f6e7eda2639ae95452296b167", + "0xe882df4079584defee65af2156ea7e2591bdea9fb74f0b088c4d0ee10a05f400", + "0x4db1886f3f468f3ff17599334c8c74d89d454ca9ce8961f91d55d6d582edc522", + "0x086f713234cdade930fccf4d61df5002bd1991b9ba8c5fdc117ab43bde3af22c", + "0x1c90c79b72d152595023e861c5a5c7763c84f2b235d18ccde15885d0c714b085", + "0x1485bc3b230da6cd97dd81db8afa2a0c60f8a4ed73d6d82b86670f7d26f69be1", + "0xb9cd873b3b93734040fa9abf5c867a6cfd9c7a58bd04a9d68949f9d513495cb4", + "0xb3b85ae9c30c9a66783730c1e32b7c120543852e7ef2bbb5827d8a15c537478c", + "0x36452e6b3b7fd4b17476a429ea6708b8c06f0f2786923e2bf68ae52cddc84df0", + "0xb9032a6baa87da1f7b6c48cb00cbf21c0304ca49e9951c08588b9cde7492eb01", + "0x76bbe74500f790556ff66bce48c5456192436ced60355aa5aaa45cd549651a8e", + "0x3b765f68302bc19b2682dc5de0fc5c6e8e82953d62414c74df1274a29cf404b9", + "0x5a797683d466f5a256a20d6141c239d079c3d1b003eb9891c3767b2281273844", + "0xb789ec584bb0811cfd1d5491df32deb73660fa2f64329ddb3d71b4fa76b8bda5", + "0x0b0e69b821f708f5b86e4d75d9dfa9870ec72b82a0ca96d3e68c6d4f671d530e", + "0x506fb874a33e8e80b65bf55fc5efdd23734e86abe150ced7e18c518de3c93b81", + "0xd51363ce9a53449678b83eb8a083a8137b3c87e2e6750f2834887c4d3cec325f", + "0xfd03fc9a8810f5b5066529b8af38de0f404728ddf0f0813aef7c78cd644f4e93", + "0x1f32b92e19891cdb1fa6771ecba7edefbfe97613d1c75b863b9d1def3929a114", + "0xaf209ec861712fda0c95e228cc04c1789e4e432ee93abb08aacd0f2777872370", + "0xdab1a1858b608c092204e1b2000879090d9c356fee44bb2c79d738d24973d36a", + "0x3b8eae3caebf4a011cf24e35d42da5a769b779425b2be793726cfd29a0c25aef", + "0xfe661a177cc0932fc78619d2ca605c2b5cb21cc314aec3d07102977e86da2b26", + "0x81099b456321a56766f425572d86f5140a1c5adac0c325968aee54801c6cbaf7", + "0x9629ebcc5d107a338f4d4d6d90554bd6beb44e009493fc2957d15022331307d9", + "0x411d843c497015655abc8ae017f6c8adbf1ce52adae67d13e3adadd88116fdbd", + "0x458ceb9ef6549feb3a8a6938f5dea17bfdc355609168091df4911fc1595cad53", + "0x2b71649e13089a86dd8c0c1c5081342943d3603ad690e5ead98959c1d686e7eb", + "0xe8b298ddfcf62f30b19d80fa80d99d020b3b09f7130349842b1231b3a70645af", + "0x36c514c85f3caf8d20523a47572d0475c54a9c42a243feef9291dc679b4ff9da", + "0x457a8fa8ae3aea0f7ba861ed2e2b690d38c423c495cce91f0f9dce7488981966", + "0x8d195066df807b88acde7f29a9e9ad3498ab8a90f2de2efeb804a8b1139db3f7", + "0x3d4bdc98bb6dcd363d9cab40816294086b85633999f7fab221d064c35e329b1f", + "0x6a8f2c0cb4cd11cbf2fe39e7c1385dfdebc18db53fdfd553d18c632c46e2dde6", + "0xfa818fa1ebc8848b03890051d1b24bf8d151b494b57d7f744615d36aec0db675", + "0xac2b249ff31fbdb19aca82718353f2535b45a403495b1b9dd468307f60d98c1e", + "0x043e4829c45e250b5f468f5a5ce6da7cb80cc22e8b39cf8032cc86012432cc84", + "0x1e576b0877c05ca0e3bd93f8ac2d5396bcd141401751601015907430408a1527", + "0x08eadfcc05f4c72efa77bfbae1da0be69ab0fb3c35c7eb568ba93d5d9a072354", + "0xaf584d18fed3cd45fa374e9b2b7b9c2c92b1a13d3710d8a9c85e3d8a4e9c87e3", + "0xbba83c31c86df1f18007bf62eeeabc364512d490ac6f4ac2a19d5c94e02892f9", + "0x64ba9a791d21bf9ebc9b7eb5906006ca99c2f8d82533bc575e910c459b6c837a", + "0x1d9e2af1472c96ca43fbbaa293dd7d0934c5604f97cd83f5ecc8d1192205f832", + "0x73b035d933685c94ad6ce8ee9cd330f6de4e58e69a4b67ede772c625d08336fd", + "0x15bd38181e750225222645a6a0a994266f3961dbcf922f4b9094bbe883e7d283", + "0xbcf07b08a9d71b3d35621436d4b07e6b9f54cf250a7c100ebec46b0e85c64cca", + "0x1916e862ac6ac13cd4d536a785cdb5fe9e7900e9cd0116e495516ac7f8eaf9e7", + "0x64667df61f3ea30a8df061dc9c3063f7e53d9d617f7c97351a47ff2bfec22d4f", + "0x854a14169dec6c155afaecbb4d511b6c513be9da27568c0d64ef94b88151e8f7", + "0xdba8470330f3b6190f1fcdbeb6e1bda7705e95ffe539633e4ed39f05b9ef4bd7", + "0xc71a75c73354d8accaab246eafb170be2e740e800d2b8fa269e710c0ae5e0318", + "0x1e50fdc54fddb8b9ec8cc5559dd09537f6062caae18f377b9638aa15572cd74b", + "0x3608775dac141092631d66b6a722b58588dc4217a8b6a33dace5d9beddbec657", + "0xcc4929d85b2d45ef071b8bb74ce6ad9c7a1820c5838615b94b0d8c9b5d0c4488", + "0xeb82d368783b186067be65faba3ed37051b4608f29469dbe746d77171e8c1b5e", + "0xd4c595dbf9937b36d1ff1212431e4d0b7ade86a49dc56b62afe2eb7b8cc3cb39", + "0x8b2b6c343f36af2dc6a30ef3e9954c789f1236cdd9ee970cc34bd126d5e1c8b8", + "0x2bcb0aafc9b29b5c6f7d416dd3aa4ea2b3711c1a551cd9173bf3469cafc6a0e8", + "0xe6f04922427e5d7f4c292b9d8f17128fafef19bf20acbb179402c4b83575d024", + "0x7c8ee3a97999f0d1c2d65d74ca72ecdd592ed0f504d7cfc02a691a2a2ee87ace", + "0xbccdd3bae30bd8a51cf23d218dedcf7d2a2d19fd7f16b3ce2965411d6a8b5000", + "0x7e30ab210475c0c73047e2a19ef5c00de6f88cad38fc45e1c7324b2d9b1b7848", + "0x0f388ae201bbde36fd43522ba45beb8a6aa9c63bffb0c8937ddcf52f1d6a119b", + "0xec6b556c591fe61f349d3b1ef8452b3ed73b7d1dd532372f6fce7595c20453ad", + "0xdef410ea480cc214857c404f3560128abf451a131c8bbdc9ac9c726b09eb876e", + "0x53cf6a57275ab72a3a0c0e7ab573f39de720d254ab2f3898b5d9446c87c84747", + "0xf7c0b80b9a3ddacb729249bc117531902bdb4e0f32b2bb9f289bf2e6da8d40ec", + "0x4f27b8550a1ccc34f235fc0cbd2c8a9ebc23ee63f849541af017a474262ea9ac", + "0xa463469b7e38dd31f077c838bcfd7e0863f8dbfd73e5066eff1a54a4d05f4ce0", + "0xff74aff9fb5807dbe34a595ea457e37412dbca7572b5a44eb5a01fed29a6ba88", + "0x908a052d390b315a0f6a96be93ec83a944a9f0364d3d66408db0fc89646f0c92", + "0xa44a0ad82a8261aebc439dbb855ab79fc16e32b5379a02cd9a35bf7540de7568", + "0xcaa390abae456f7341ad03a6c3f75f5e8ce37ad7b475040fd9da26c1b4759c58", + "0xd27db4849e8d13d09bae2edab4ebb53f4a9e3a482b42aba03a5da8c09f313d61", + "0x64a2804dd657f03b432f511609a7c3f4ccdcb95d7a0795f93ad78ac25f16f6d9", + "0x8df793bf7ea14f04f97402e7e32b38bef2a67338a4b07e2fd9eb56bde2a2bf07", + "0x61af9dff3186bf0683a32e5d9c4f4b19c486c015257fa010fb5a78a13e6ddf5e", + "0x95b7445c6f7a4829ebc26ce2810571cfb0feff98baaf4bb614f119f5f1da28d9", + "0x803ed381cee8191cfab87f046d8a4a52c44430a27af9ed734dc45fe098c66ed5", + "0xa0403d2f502ed8c0276b89d5266e2f4e0a6239808cb597e64273c065676a3d47", + "0x6f873dd4b1c1212fc1d27db1244e7b05b92cba90a2cc7def330662d3dfa883d6", + "0x777f773b7458d3cab3d343d1f5ec39902465aa33d8c93dbea0a7b3d780c3c334", + "0x5105901dbcb4680e2fe9ac03f95d014073ca54513ba9f9e7e83a2de46c0a6bba", + "0x0183af52777466a1777064712f9255965c73fa24b69de42aa6bb259c19beccc3", + "0x938bd32da6b99e0ce404e79790115d9d6678d13ee73e7ca41a6f62d39250f288", + "0x7ce5d07372133ed0b39e39e2d342f6eb307171bf58025f48be599a868308ee6c", + "0xaeab8e20a6a7933d03a240481df80881df64f96363e114e75af8c95ef37840d9", + "0xbd3a5c163974691b00ff0c2fb8a5c99461df825f803f685342fbe8963fa113e5", + "0x11b0bf19a5e7f6431ce978222aa961d6b4807462a7991fc79cdbb730bb0573e1", + "0xe52aba6a911de3310416eaaa6566280f6c092f36a2c5265290a94e5d55116f16", + "0xe1c44c8dcb79e1f4fb5fb104deba26de64d640120e183c5b7e49a1b645743d17", + "0x6ef7c7469ee5f5578cdf12ef9b1392df8268e3cf6730697a8a38cd3794e7a9a4", + "0xb63357d84981d93c270bbc2b930d783098901a529d338683c2af494c59032bc2", + "0x43bf340e40f73e5e6130892e3b9e7febdaa8ab3010d02a2fc2b5be529509fab8", + "0xecb0e609e25033c3ab24565ae07580c0c3433ec51fc1338e9071d1a13de2ee31", + "0x0912295aa7a8ae5b781b6704b0c47ddc4f4a0c91b4ef79038f889070806781e3", + "0x7ded59d270f1dccac585627bb1f3a577b5f507a1e45de94796e0c8d1f861fe63", + "0x48750dc05ec66a4e9d9889ae06c58b36b80cd0b8019b7dacc7c3c441ad428e98", + "0x53b757f762c6b8f1fd2f9e9ff6dff31d3db0bf325cee0d595773f17585ace7b8", + "0xe00cd3d3e7e92feba2b431d7978188dc54feef4effb980c78f18c3646e04749e", + "0xc0327f98dad58853bb02588058fcfeaaca268f379228da1dcd1ab05672a055c9", + "0x8affeb37939d7ec174ea9c6ae6cd32433bade565494346eeb1c221f1559e1643", + "0x78b3c061f2cec2e0324b400933f979f2e8ce920b9c8555b9a5c366b75c3e2e5f", + "0xf84eb7d08007ae4891c274208b6f1ce98be7201078e53493f1ef94b9795345ee", + "0x6b549294005d285ba7375596c060f2c2dd8d42ba18f533a2b836f7e33c1294f8", + "0x2db95fee415c28b95957a54168d542d2659383b602e490f7a76881706f4cddff", + "0x558f76d84c39fd6b226672758172f0fb94599061b00700f7c3e360d1464f2faf", + "0x5ddca9fb2881b9ae4d0e3ff488987b04856e72ab13b227aa90b277ac18e63c4c", + "0xd4a5c132154217e9d026f005fbaf367fccff273091102f04fbd4a7e18fdd2036", + "0x6fcd2319ee9439bcc80b6b43e7e4e7755dff4c43a17602a3749c8cb0b5af899b", + "0x2159d0c84d1bd380f110b144017096f3307cb229bd33b48ad06796fb95c27179", + "0x3ae630c2eab81c778e997ad714e6633d6b71d833c35073853785a53075eed2f9", + "0x45b99759dd456a15b1dc318bb4e8067618f18ff18c54fce71655d14b91a32d9e", + "0x472ee91d3312972f8df1839027818f5cb890dcab810aed0636a868490d0038d1", + "0x4e31c58a256bf19d1e715de52ed0a909fbfa1466292bf00ad759178d4e1745eb", + "0x8de82fa65607d7de5bc24a7d44664db7cce9edd606fb7f63efcf2c1e5ac696a7", + "0x9b9c7b302722ffbe115c3d3e04871ea434485baaaa7132eef6f0b2113bc8e41e", + "0x2e1f2b7dd68827ec0e15e96b67159dc07d5ff796be6f6dae578afc42a3a335a4", + "0x9fe4d2e36e10377b604112c507929a43bcd9929034d06d82a83e060614738ef6", + "0x5ae4fb3f4b6194ff92b565ce3044de3b8f0fa4b6c026b3df743bf5d5f1defedb", + "0xcad14e9d379330699382f121820a82b9465b1f34fe369d596309da29b49d4e0a", + "0xd13c8ad553db419a6eca3a9202f8fbdac08e878a4e7a58300135e65a8f1d9bf1", + "0x5d71aff2a12d4f1d05c7f760d07b417a39eb0eaa72a01333befc6a2eb6b7d72a", + "0x8dd7de9195d2852aeb6812638ba22e73ff5ca0a8ad921c6e924cae1dd5952255", + "0x8f1828b4cdc6c38c112b1ffee7790953112dd2225ec82581a5095e5ae4d71cae", + "0xfeac88ae6c8529e87a55a259f475b7d162d01e8fa5f36c90d4665dd6105b1743", + "0x2e37011bd97c6e8a24e130fdc2c60c39b14ab3eb426a4f654bf3158a19aca88b", + "0xdb59b565de21902c50e2e204374ae1ce487656eb74145c103a86707b45a63eaf", + "0xf75c26a7214acf2d050ff5c7cc8b76e1a90540410b5c8b2bc9edbfe8fb2268e6", + "0x6ca7554f2abfd22951bec80f9d280abb6f060dde4a9a829ff7a0457d67a99edd", + "0x0324bceb8b61fa7092396764d7e1933697806c6d785446e3bbab3fc3be0ab259", + "0xeb4880f177e3e673f8ee04be1451a38bd8a2c0bac681d82a19327ae2d9769d32", + "0xec6a868cd9fba9e4f5b0d4276f44aee71056fbb7f425f717d0ce9d1fa5442ded", + "0xdc12b36d165eae197487ec930e35489545d2867b6fb9f8604d279337b6a8f949", + "0xcf1241b1c9b054df34638e99447bb0359aa01ad13c38650b872f2d727e6f68f6", + "0x713765e9b76c73c2de58c480600a7125972246fdcce2324993cd6bbe49cce67f", + "0x81e096e97dd8bf1d206d0ed41c9feaad24d344323ff74707112ee8fac218994e", + "0x8943c2246d5ae3e8db5fc012e9613642c6b713e5f2a89d00f09fa73246f88d5f", + "0x5b2d0bcbd893fab4e58d4ef698d1e8d3001799b61e758b7711f319e2b8eaa645", + "0xf3e4da2cf4579f52b7e4d632d93b79714487ef179a8f5d5c46af9154efad20fd", + "0xa2348ea2cd7a5a32779e9d292a9428fa475fae790f08e42f7699ef5eb2489188", + "0x62dd923966e02db7d0d27cfdd4aeac081f9827288c8b54d9f19035331a109f53", + "0xaa1aafa8f9d9d3e0668eff761fbfc2657d1e1906c077d93200ec000643c6c272", + "0xbf40cb21561989004434d6d908451d5b63045c89c2ac9b1eb617ec0054dc18be", + "0xdae53edbb07fe84623451da0e25da631ad3465e5bc12ef8fd8323c8a72f57130", + "0x685115b38f307f984c7c90e85d167d62b0ec2c924a0bca5f23b1cac12a8f72fa", + "0x2ad7e8f86c872504d7c2c48b0db141955d770acc84222fd725ffbd2dc4095b1d", + "0x9268b3b175aa6025b959b8fcdb416c39dd339e6f1fde3c427bd1bada36e4384c", + "0x502ee814cecc8454abb95591b0d07ed5170db94af7fda8878b9b4287fd68c9f8", + "0x6b19baf6b7eae36c0b1d2754645ff282fc2905802ca6394ac00bc22eb1582eb9", + "0xecad17ae39f897ab38850cac40480b4fafcafd6624f8fdfcaa69849f3fa101ec", + "0xb0804719b391b4b5f554a49f99df3a9d1c3a9884cefc268dcb27e3821aebe385", + "0x3018401c9a31f97881852c1bd65a964bfd3011659725c849a8de4b5ad8f26490", + "0x48a6b687e62a42dc44ecb56f4187e293d6f87d328b1edf409c8f2fa6568dfddc", + "0x8e3bc1ec926a68e22ed525485186a4d9160a54bd3e80107bb77c09911564effa", + "0xd7a7cce632e1746120476a3271ea09689380eb833d5538310fa0029f9174e0de", + "0x7bae074c51f3b547568d18e85b73fcb9b5f8040ed5f96f3523f53197150517a4", + "0x9ba39f376b9444dab04e0a52e4728ec842a0aa4880d9aa9819de3f0694f46e60", + "0x40a2b84bd3d05d28d51a39deae5f23b4f7370c70ac70d1cc81224eac4939d69f", + "0x2b9f57c8c43284ba929df8f896a966afbdd341f145b6b2b2fa98382950ad915d", + "0xcaf3d2a336cf17c9b2d7116a14e654bcece012b07bc020ac30feb71d7f6cead1", + "0xd3b68cf2337ca26a9c4bf6b6b286dc65bf66641d5e9c241f4c1b147994253ac5", + "0xefc11a5944a8061c87f274515e810fee13f4c350c625a988c27ed276b6c55b6d", + "0x7a93732151f7145059424aa823b24e26341cfa57f612e6de3bddbe23562ae918", + "0x2594b625d0f5ed52425ccda4e7898a8a554300791027af6f3a19239a15868ea8", + "0x1db00091145b1b0830983b5eaa5cd3d0e4ad71c09d1b2dc20c47815bc2de5917", + "0x60563bce11f028691cf78da7326f22a4ab01d980020e61bcf2e4bdb5912b7b1d", + "0xe6515bdf1f22469a4218f54791d12698d1bc555b3e54b04cf46b10effa8ce74c", + "0x990831a56958a6bf131697e2f35ab2a45fa228eb7435c7e65814ba28778d513f", + "0x1b6e4085f0e291a8ee4d7e90158dcf15702b4e6e634d1d3bb5c4bab11bf70068", + "0xd0d4a6061bcab0f8e645ea16b285eee7f2ff84c7765d7543aa318edbced2408d", + "0x2da1a609eb1b572a47f187dd5a1e9f4cb1e1885c841f91ca82137e01a9eb4288", + "0x1293686df427f9ee1c2116000735642b3d09511cf2889dde21e1bee427d8c273", + "0x8a990d66370eaab3a46d9e4fa9b7d0c621020cd3b897d9e5b3e5fea6a6979f3c", + "0x10030534d5a06bce47d72998ad4c042f5e445a505920723d14b1d93a3a23af82", + "0xf29a399e8879386e4c2bd8e873dc8aed612cfa8dfa9e5b56f9c51d4c4d1774ad", + "0xb252062ccbb11c3181338d9912ed0d4dabcfa4d61860c211f2f702a641fe936e", + "0x822c7abd11b80c862bd67d39e16a208c8462936ca86b5cd5dd20c51d35cbfbb1", + "0x6b62aea651f1407f94906db704a364f70d827e0efba981a8515d1f515a46b266", + "0xa57b7661c0471cbd7eb35becdf468622df8338a48a075b722ebc5550bbf6b9ae", + "0xefc593d38afead5ee1fea5d8b41a52bd2a5b5a059774d0b951bb7eadaa41a46a", + "0xa556e684c26e7fd6f902b82ecdf721fc292c35e0d2240c1f362c4861c366c4c6", + "0xc9f274efc308d1e97ba9b59c92735d1ab2a72d033ed02a543dab301610e96e33", + "0xd7b43559126f88c59392fc54e2b416d2a67014abce12ddf61764df989a897bd3", + "0xc860842132de3d8c1d0ba2cdc0a7c2853ee568789f1190738862667e3539a958", + "0x2f330354084635eb507cd54549ab89fecc41886d295b1d8c91efd8ca27fe4f7d", + "0xda6edc97997b9cea1bc90662c6a8180fa03cef6189e09c86f36adb91400abe74", + "0x0d2853b5a3f02ae9e4a1c5a0534a5329d2e877d4d77f60dddb36b84b4fdf7e2f", + "0xf048b5acc9e9191ce0ab8c390bfe03d89cbed91db5b9e7c7452b01bf56bcf5ac", + "0x30fb6f6093bf59794d37ddf850c315dd9491a4cf5df378b4468dca96acf78e77", + "0xa04eeaa9d1d767c0f93553af3a259390a9576e8b6015ffa8f0e4fdf37f41f28e", + "0x02411cd53ac55407e0d31520a8c3274a2f4d1fbb2541bb140f30f25843c76860", + "0x65bc790d632d5fe2446c65325df875ba59af3c3aa7357bbbbf47c7e5f7663a7d", + "0x5f364562fed351d932eff956c3ac489ea51ad2cb12a81bd8db4fe0b76e3cbb92", + "0x104f7070d5da1aca5c8b20a96d36638e4b5f8be4e86be83f0aed7234fcece445", + "0xb2fc7a73d8d859d531e51532928671ea59ae6538d4572fd5c2d76c70920aff7f", + "0x7ebecf446825dd0010fbf47afce8b9c3b3901c839ec46269eb8744bd799699ca", + "0xc64002b5a70f18b7c51ea3d3f5246fe8db16781e146d777aaa12f3b765d108e9", + "0x9d136068c7002d2780abfefcaedc79424d3e89b17718ec369d9e64ab7b63a81f", + "0x7b9819e62e92dcead89329bcb3f1a1d6bd10794d1a22d30c3d0369a264029543", + "0x8a8c9e66f343d09d5b7897c491c851143ca4f337ddcb5c2b1462b150e22c6f47", + "0x9d86faa1a5d355d6071e09c8cca50e2dd7e7dc117c2e4f6c0136a2789e84aa8b", + "0x234e156c10a80422ca1aafd49d614e02b698a0d89a7080f87db5dd5169b419bf", + "0xafbb572b8d9119ba8126fdd5a593663db3a3e6165a60f1f439902a6321a8d243", + "0xcbfeb8af8c93b11eaddb05df2f2a8772da694f9cc16878d3154d0857f17274ae", + "0x7253cf6bd2b4d158c2bd60acf5fda9dff6cbc6468ca9b549efcd824410d2e719", + "0x67fa14af20fe738ec5c9414401149a1f198207969768a5b982454146ef720b85", + "0x6c0ddef53c7d58839c3013f2accb72190b7dcc52fbe5d71f4a20f849dd72725f", + "0x89e77c0dd9fcb4b4d4d10c25903ff5b905f5d64b6bed9a0736e9dc2035ade3eb", + "0x42466344821fc29dcdb5fe7dcbda00b3779736ca90f87ca1802207f61633877b", + "0x6e2303e8ed41e6d39488c57dff8d50c548a7079a26c3fb86d925c0aca5b8f67b", + "0xb8a14969606442bd94048f2b2dc7b87662d801097537f51c8eb8f026c52f1fe9", + "0xd7ee25e0bfd080d89c475942575fa055ce5ae268a6f01b916b399f6ff7e94a39", + "0xaf5e7da13dc0ab08ba5185074657acaa2ce753a20a364f3a97d230c247bc8d1c", + "0x92f9106bc9ccbb4e0b4c0d1b96c5bf347d856884eca91a0bcf29e896789fd9c2", + "0x4bc12bfadacd6af0737646b813b1a4a9c005e97ef4b090bb74b7475b50c85dfe", + "0x91e4ef72d0bdef33e2e2c8acbdd7926182568f559397bfc086b96979e7c4f53b", + "0xb2f57e050021b238e0b47b0b46a641644645db5bbd987e8d957038655d1fa83a", + "0xaf221401f4cfa3db7879237b40c68300060df9f65dbf68bb02694837eaa8af7a", + "0x2dd280e98a0d6bc950b7f3f0bd11a9e74105d4d15463184a3f8c03d40f3193ef", + "0x2538560e5b802a89a021685f994acbdb3181f25d0cae17160aedfc619ca2954b", + "0x133cfa3f5d6a00f7392a6b0c6a97a9ba10ec50b24cfbbe6028995258cbaa065e", + "0xc120807872f07adeb144905ff323ea79880389a2815f8441befbfa82835555b2", + "0xa2c5c5a3cbf6db506dfc13285b07c24ca7e70d9e75d80fe711c3082ba119d77a", + "0x837622b7bbb8bb18b3d42058426ef97e3fbc2842d2b64b339733b52313557562", + "0x29eda2468556699747beef75f015e6772980056cf367b819d05a4822b7d54712", + "0xc6ec29323368dc29a1d4c3c11e945ef7fdb56db78808c4c9688ab5f9eb7f27cd", + "0x44b368ab63e1fe0e0da031a4e6628ed1a4fc69fa4083cc056dd9443400be3326", + "0xf153dbc5fc03a89e80d2808ecd45e9fe6453d112508d32ffc6305d5a577d14d8", + "0x32452c0d51df7a85eac3edec46bbfe376c971ac4df4512d7e050e6fa711373ca", + "0x70cb25f3d60126cf0104a40b2a49b44ef8a42f60b93f929594938ac00647b639", + "0xed63fb33d707b93e45e958d5d5f9d3f0898c3676e43eeca55c788cbb2df3170d", + "0x93ff103a026350b0e9c2b30c36e079145892e8e3756678e8ae4b0065fb6a04ec", + "0xa466cdf6063bfe155ed75c115484ce113227385eff2cdc07dd90405239842f3f", + "0x2883c296d9ce6b1e6e7b4f471e841437603ecbb867570cbc46d86f0f26871600", + "0xea5e5b84183a3a709a51c1c6f3e7b039c4663d7495b9bdcfbd4ecb0a95ea994c", + "0xc0e97318bd3ee2957c09d6acedac77ce6b219608e5dd63ef512aa08d63c3a114", + "0xd3ccc7fcd24076afdf6249f671de402b515a131913df2da17118be47b3720b33", + "0x4f5be5a6edd66ec496207b33cefd00722f3167b9e6f2a44d9613c4c7d6541aba", + "0xfecdd1844517d0523a7b45d7b51769728902b881b7fc308f486e850c870eef5b", + "0x01a22dea1d0e25885e0a03e56489bcaf6747e712ceb5a42c74430fa6ffcc1c21", + "0x06cc521a05ce856dc55041b90dc4bbafffee578c1c315b5cfa4cc2d1ccba891f", + "0xac21d4b08fbf2891e0b3645b870695434fe703101f74e7fcf0d0e1304ce65b54", + "0xd62584c47aa1d8554cc08cf675bed128e541df54900fbfae958877595ad168ff", + "0xd8f1806ddaee8e729218fea1911efc5e663666ffb3acad4a2fda3757700d6d88", + "0x9dab2acfe01506a185276145deeecdb5c8fe0937feacffd40fb25a83e8eecc72", + "0xf0b74c6b1a441fc2ee8b2f25d2f03307164014d42a0784683a9d6cb7d2179064", + "0x7d590f0bcc891e30996adf8583803a9dd1271442c3f0e69502addbd371437767", + "0x3a66601fff95b0aa0d0660c12788ad56d2383cae290ceb2fb9ff41794abbc55a", + "0x36e94b03402f18c689f5234973ce1e626a82aac085dbdd682b51cce21f8c1872", + "0x00abd1d34c7e55f58681866558cb844c11faa55e8cac70ede75811f55341cfde", + "0x9983fc20e63e77ec0680522035b03167403681674ec62293cd6b7fe360c69157", + "0xe98b658fb8b6b7fba7463562f86348bf1e3534bc9148e8559423b3ee5ab68472" ] }, "accounts": { diff --git a/ethcore/res/ethereum/morden.json b/ethcore/res/ethereum/morden.json index b61799c0c9d8c73c01b3eb3af57d2bd9aa7a014a..3664c3e9c29c06614bdfc4ba42f9df38be3bfd18 100644 --- a/ethcore/res/ethereum/morden.json +++ b/ethcore/res/ethereum/morden.json @@ -55,7 +55,15 @@ "enode://fd008499e9c4662f384b3cff23438879d31ced24e2d19504c6389bc6da6c882f9c2f8dbed972f7058d7650337f54e4ba17bb49c7d11882dd1731d26a6e62e3cb@35.187.57.94:30304", "enode://30a1fd71f28aa6f66fe662af9ecc75f0a6980f06b71598f2b19d3dda04223fc0e53b47e40c9171d5014e9f5b59d9954de125782da592f5d95ea39066e2591d5d@104.237.131.102:30304", "enode://7909d51011d8a153351169f21d3a7bbedb3be1e17d38c1f2fad06504dd5aa07a00f00845835d535fe702bf379c4d7209a51f4d1b723e0ca8b8732bd21fba3b30@139.162.133.42:30303", - "enode://a088dfb2f5305be9232e8071c5535f13718a4017e247a0b35074b807d43d99e022880c27302cdb5b1e98ad34c083dbbb483f2b17bdc66149bad037154d6ace96@139.162.127.72:30303" + "enode://a088dfb2f5305be9232e8071c5535f13718a4017e247a0b35074b807d43d99e022880c27302cdb5b1e98ad34c083dbbb483f2b17bdc66149bad037154d6ace96@139.162.127.72:30303", + "enode://1fac84e8fe252d63764563f4f526323393b52aaaf832693f7a8a1637f6920311d7d04a7cb91945273e6c644d5c3b01a6bf8a172ae653c918e1bf8eb79e7e6baf@94.152.212.32:40404", + "enode://3666177e0e2e56bebaef318c8ba4aed3d05ce788df1eb0e48b79fce40fcf3445feb4ccc4ce2fd4aadc3c146858e276bdef1cb63437215f17e6e5dd8c41403427@144.202.23.122:30303", + "enode://3666177e0e2e56bebaef318c8ba4aed3d05ce788df1eb0e48b79fce40fcf3445feb4ccc4ce2fd4aadc3c146858e276bdef1cb63437215f17e6e5dd8c41403427@45.76.16.230:30303", + "enode://78d8897b376e549c2b47664e4c81fd023b089d0a417275731760739b7f98dd639d632bb7b75e92606c7d6abbbe96f69f06d85e0a41a143f1f0a3c55ff2b1d732@144.202.101.214:30303", + "enode://a329e2399e6d72009690faa15a82ae13ef2015bc5e72ffb22f92ea83cf3bfc9ce45d43c38b3c2289c148939d3911e9d1a9e940f41698dba54508b59489072b2a@5.135.157.4:30303", + "enode://d79b12fc48a494ba7053bbc30cbe510060ebb3a2ce9bb4f88076303e97e31e2af263c61e797af0af20419b7268b2bfb2d2f196b57242a454035ecb6001cc69a2@94.23.49.75:30303", + "enode://f4a1805a51cfdf5afdddf0b43b8d4b687657497311797464046dce65388b9e5a538b55bdb23ae4eac54485a81d47adad48731294efc9d73fbc9f297f625aec70@198.27.80.32:30303", + "enode://f570df80b5589dfb0a7657adb62b93dc55e76d491694d8965c6382964e6f397ae0b8c3548ef0a108151f3b1485c75769ff203df2db7ace385ee98fdb2766ba3b@86.8.233.254:30303" ], "accounts": { "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, diff --git a/ethcore/res/ethereum/musicoin.json b/ethcore/res/ethereum/musicoin.json index 724f11478bf1186429d1a73045282bc21a24c9d5..f9c4e046d6dd1d198d5e16444b0a11d74fa0c04a 100644 --- a/ethcore/res/ethereum/musicoin.json +++ b/ethcore/res/ethereum/musicoin.json @@ -62,7 +62,15 @@ "enode://b58c0c71f08864c0cf7fa9dea2c4cbefae5ae7a36cc30d286603b24982d25f3ccc056b589119324c51768fc2054b8c529ecf682e06e1e9980170b93ff194ed7a@132.148.132.9:30303", "enode://d302f52c8789ad87ee528f1431a67f1aa646c9bec17babb4665dfb3d61de5b9119a70aa77b2147a5f28854092ba09769323c1c552a6ac6f6a34cbcf767e2d2fe@158.69.248.48:30303", "enode://c72564bce8331ae298fb8ece113a456e3927d7e5989c2be3e445678b3600579f722410ef9bbfe339335d676af77343cb21b5b1703b7bebc32be85fce937a2220@191.252.185.71:30303", - "enode://e3ae4d25ee64791ff98bf17c37acf90933359f2505c00f65c84f6863231a32a94153cadb0a462e428f18f35ded6bd91cd91033d26576a28558c22678be9cfaee@5.63.158.137:35555" + "enode://e3ae4d25ee64791ff98bf17c37acf90933359f2505c00f65c84f6863231a32a94153cadb0a462e428f18f35ded6bd91cd91033d26576a28558c22678be9cfaee@5.63.158.137:35555", + "enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303", + "enode://3f1d12044546b76342d59d4a05532c14b85aa669704bfe1f864fe079415aa2c02d743e03218e57a33fb94523adb54032871a6c51b2cc5514cb7c7e35b3ed0a99@13.93.211.84:30303", + "enode://78de8a0916848093c73790ead81d1928bec737d565119932b98c6b100d944b7a95e94f847f689fc723399d2e31129d182f7ef3863f2b4c820abbf3ab2722344d@191.235.84.50:30303", + "enode://158f8aab45f6d19c6cbf4a089c2670541a8da11978a2f90dbf6a502a4a3bab80d288afdbeb7ec0ef6d92de563767f3b1ea9e8e334ca711e9f8e2df5a0385e8e6@13.75.154.138:30303", + "enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303", + "enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303", + "enode://d302f52c8789ad87ee528f1431a67f1aa646c9bec17babb4665dfb3d61de5b9119a70aa77b2147a5f28854092ba09769323c1c552a6ac6f6a34cbcf767e2d2fe@158.69.248.48:30303", + "enode://c72564bce8331ae298fb8ece113a456e3927d7e5989c2be3e445678b3600579f722410ef9bbfe339335d676af77343cb21b5b1703b7bebc32be85fce937a2220@191.252.185.71:30303" ], "accounts":{ "0000000000000000000000000000000000000001":{ diff --git a/ethcore/res/ethereum/ropsten.json b/ethcore/res/ethereum/ropsten.json index bddf5c0084f71a7a83cfa519f17791802fa99f96..1e5972313a12f628cc744041c916eb004607fe39 100644 --- a/ethcore/res/ethereum/ropsten.json +++ b/ethcore/res/ethereum/ropsten.json @@ -22,8 +22,8 @@ "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x3", - "forkBlock": 641350, - "forkCanonHash": "0x8033403e9fe5811a7b6d6b469905915de1c59207ce2172cbcf5d6ff14fa6a2eb", + "forkBlock": 3383558, + "forkCanonHash": "0x6b4b80d65951375a70bc1ecf9a270d152dd355454d57869abbae2e42c213e0f3", "maxCodeSize": 24576, "maxCodeSizeTransition": 10, "eip150Transition": 0, @@ -52,9 +52,9 @@ "extraData": "0x3535353535353535353535353535353535353535353535353535353535353535", "gasLimit": "0x1000000" }, - "hardcodedSync": { - "header": "f90214a0e11154bd22ac6a45e9569882d75fca57d12e44e5def1050de0a7b99452fb80d9a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794006b2b96ab71a8df73dfabc11ae790f9c8c259a1a0d6216dd88ad006659c6214fd81887150e1bd1f87b248316d3a58cbfe40f521eea026802d5f81a58db8519436e768eae8b11f7de071d7f274487e5b5dd9e6954d7fa03ab8cae24350c9290ed5bb29777ae22498e0b8aa87f0ca85f2bfa74fd95c61b3b901000000000000004002000001000010000004000000000000010000001060000000000000040000000000000000004000040202000c0000000000000421002681102000000001000000000000080010000000010400000410900000000000000210000000025040080000000100000220100010000010000000200000100048008000000000000400800420020004000000208010000000002000000000800000000000000000005000800000000100200000100000000000000000000000000220802180020000000100040000010200000200000000000000000904000000420000008000000022000000000000000000001800000000100000000000008000108412d5f8f8832f60018347b78483449c5b845ae0127896d5830109058650617269747986312e32342e31827769a04a1c4062b2593568cf5fe861cd1b9b9024189927a3c75d09471efa029f7483b08863e584beff5c7905", - "totalDifficulty": "8154014315272113", + "hardcodedSync":{ + "header": "f90213a0f6a1b2e8155af1d1d77879826e2535cb6023ba35705934380ab05f65bcbfb107a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794f3af96f89b3d7cdcbe0c083690a28185feb0b3cea015ca95dffe4c5de6d9c02d9282df0db94855b0d602738f4b6fcb2268694cd92aa07ecb0900077c45bd4d3ca910218099f726fea18461f90be18897710767a51559a0251f2cb798e965c5d9b11c882f37c69fd2c42b314fabe64d2b4998c76eb93ae8b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008439b475f9833720018389769d82f618845b45928b96d583010b038650617269747986312e32362e31826c69a0fbd0db05012df54423a6b25395ec4f6e66d9f11af8b9c492c4fb7197fcd6a5ba8877d4a227c2bdf4de", + "totalDifficulty": "8809217991079619", "CHTs": [ "0x614648fc0a459451850bdfe353a932b5ff824e1b568478394f78b3ed5427e37a", "0x1eae561c582dbb7f4e041998e084e165d0332c915d3a6da367638a8d24f3fafc", @@ -1571,7 +1571,255 @@ "0x89ebc269c4a123f9622e89fd221d22776def13c4a9637a7f69176504ed48ac2e", "0x808d7a4793aa0afd91d35a6a46eb4f3ed522c77716fbd27765ad2104d2638d75", "0x5766e58d79181a27639e4e2b1c141de7825e6abe3996d3d06a518bc87044abb0", - "0x53e304b2ae212fac8b059d283f8f97553cb16fb3332e8833305a32db18abb5fa" + "0x53e304b2ae212fac8b059d283f8f97553cb16fb3332e8833305a32db18abb5fa", + "0xae7cbb3a3c753f730905201d09056662cbdd85c288fe94265aec6f1791ecea09", + "0xf6521ebf26b89ec9e3f437a8e3f60aee8063a821aa8e2e0694a90835b782b2df", + "0xb1e372bf9048f7e44d08b12c45b0a17028571fa84238954760da69bf7565cfa5", + "0xfce7f2160459a7e6aae2c85d9d48b5005179c05d703ce890a74b21d993fdb05e", + "0xc630b644d1083d77a698f658819ff7440c3e688aa89e18480167e651f8d1ec67", + "0x15ce3af581eaafaf4456af97352c4feb66b25aa20d3bd711221bdf8532639406", + "0x84600535f9a3338270d3055cb823c2d5a3e7e8a0ad2cc8be198557ea69d15c01", + "0x970435f2511428138573c6f1d67c860703ba5504cefcd675c0a77c37b17640f5", + "0xa6c0ac36032f2848a2ca230a5773760f2ea3afbd1294c0c8c8734d24f9a2c6ac", + "0x3cc9fcbd313d84afa7277112910029782b3b083500080ff34e10507b8b85c249", + "0x84cb76db3547f6ae1c91b7cf3196f8db451c020353776199f44b8b529c810ae4", + "0xff50e061106f378ccee04ddeaacb2aaf2af4ee90b1504f13a88ee325de268eb7", + "0xfc0d53a97fcc0a95f8681674e2f174f789becf7301c0742405c6cd28749acf3a", + "0xc0853233a2d93a9fcd5c67da4c233a248df9bd424d3765546c1ed39c42a437e5", + "0x8fdfabd694bd2266c71796cf19e8d4967ab9a42dc0d6aaac495c47ed4da9373c", + "0x2a8dc4cb7db4cf55beb0eb8662747d464e2907a3dfd0d58ce1067c85de2be0e8", + "0xf082d07fdff2f3665019d0fceece5b202c79f8c3b13d4f533f2eab2a83925f23", + "0xc155e24d5513d109af50284b49b723cdb1f812ded6d65eb1336cbc2d95b91f0b", + "0x435a39e77aa40920f0e7a67fa4547f67e2f099775f3f8a3db3dd1e48b0b2c376", + "0xc9a68f80733f9b39794101dc6750747cb6550b7858773de7e323140b1248839d", + "0x482140091ed9921f8774a0a1acc3644d2ec7b7019a5d50a0e8f42d9cc729e94e", + "0x88e75515699bc267d85f9410411ffa8ea0a852d7ee2fd2826e1260ca0218d497", + "0xee78dc1b01b7938dab9691b3a44d10497684fdecbfa4b175c3c688b22c9f563c", + "0xf7982d19a9779ea1077bf9cf6392057aa68b834ea3f8b301530484c0b9bbd567", + "0x125ef0450026699707ec50bee796181e783efddbf4141f3cdaa000ceada9b77a", + "0x3091b7728400f191e3764d5e9ecb8b4887e5e99fdc36b67d1a6f006c16e75ff1", + "0x169d3504fb8dd8fe74afef89d5eecaba66adc07f119f1fdc03b4b22419d6c586", + "0x6fe28b55a792cb900d1b830a047653e15d12374408a4b5d261e6b0daaa6a654f", + "0xe4adf68e5daeb9bedcb6329924c76eb6ff1770e93a7b3ad77d456bfb414c0b94", + "0x2ca7094ccb9beb1654ef7aac79af810e31f48e0063525e96ea4cc7548283b120", + "0xf087f8821c63865ada8f912bd4da2f6590d00a8a8e530c50d09600be91ea879d", + "0xbc106c39ae71e3d8d9c0b8869c63d21a2833cd09104a7fe13c988a1bc115dcfd", + "0x8310fa11f25180a7eaec83ad49e58f8344bc1b7b48f15ec12c16afb4399d4b28", + "0x5d9902bf98d0edfdf77a8605f15dc36c0d9fbe8fc16330099d8491450ed97819", + "0xe1715793831ca9e851f293dca235f53d1985ade89ec0dd08d8478ffac8837fac", + "0x86bd483291ed25a967f742e4eabd3f77e178be0fe9af43ce61595fd26e4089a5", + "0x3c01d8d2282c6406878471d453f97bc4247ba285ce0bd1fe7bafd21f617fa760", + "0xbfc1bfa277a866dc1b1a6739648202e15a90718c67db76af083ea57229e9ea03", + "0x1ab9c0778dfb859bc6e13cf425f29c796de5889593130ed9b591e1f854de51f9", + "0x235936c148f7a6c4875dfbf30b9a4101cbf329e3d682ec3bd2a6c79473efcd61", + "0x70c8282991bed0d69a19adf4c95312dc44f24822f59b915c8aa93a2e8bc322f3", + "0xeb2111dc14eec6dc250a382b529af8314a7d8a25bb7672c35685a53d0a6eaf2e", + "0x98242a2cef0a5d9258fde45048730a73321b46af2d218203bfd3da274bc3ecea", + "0x41de7ce88b052390dedb6dae965ef4b3254dfdb91ef0cff77ed0f990e6d53d1d", + "0xb307a83fb32e43ce73d5be05b8dec5791b55ea97abfa2916c3a118540cd8cf14", + "0x19c74a02ae96e9581017b8d1845344c0c20f7cb8b8f1cc0e298608e25429ba40", + "0x8fd7b83114f3294d9ef1994f96cc5dc3309b80feb86d7384c4797bd88914b4eb", + "0x6cbe4c1f28f393db37851436a41d739bc6d64e32553bc3b74a6d390390e29c9b", + "0xaff1d11010b3a90a863334bc65678fd1b719a424271c6a384321eaced720521c", + "0xb30947d573b684f02f2bdaf32241f9984e0fe1ccd2398013d7f55d0de0e8db7b", + "0x2777c4133201edad3b7478cf06b4418573bbb0b35a94956489f2c207a8ce07d1", + "0x852612bd283bec671358a009c4c02f57d7b150c466a673ffb7094ab8167e195b", + "0xb9b88021540165e714518c5ea97152e7a57214c2bb30143d0aeecd650b69c011", + "0xfa3a3d52ffe85f56b28a7d3613c50ab16a98dd0e5b14690676a0917b0d9821a6", + "0x1b4251f32144ee3ff35ec96c13739bf11940a7b7c0ad7819fb14508e37318179", + "0xb47b35b1a9efb47e5267e75bdd43cca5730b1dfe7c74fe70c854c26bc67eac20", + "0xcfcb740a8d76d44484ac862bc7bdf6b932a76a1128c77f4543e3310ad408416f", + "0x3c01a05b0ca98646fdcc76b2a95ff1ff958f61aa6f7ff199bdda9e354a7de21b", + "0x337c18196aa613d56cd098d128126403cb03b5172175f9b0cb3599c76499c358", + "0xe1773100b144b6612c5a811e80b6c4ce002ca6c0afedf9e2c82228c0d499586a", + "0x7f10533e666fe853571ed79da196262e8a69c2cb99222d26e0165808ab6d7582", + "0x2532a4dca10fcdb5d33c84c0b295dc6bddaec6f29030f4a74585a7718aa04bd7", + "0x1f6c65ac839c5e76c955848ef97b3aa1a095b9b77faa155278f793996cb8d438", + "0xc80d98e457a316951cb28828744885346b14e545dee625ce24c062ae30fb7867", + "0xb12c58437021718ad76e64e66259186a53421366acf78f871d53ecceab7bfaf3", + "0x4fced8fe6a8c19e32144376daaf080b4d6c8a77ab8e7f91d099881fbbfc091fc", + "0x1c2afc3229797fcaeb2df0293259564f45b4cf1fba17c2e5e266747fd24472d1", + "0x087e44d23f6cbc2233738ab793cf30306c222445e2404e1346c1609ccafae040", + "0x75e290747c7001e7e2fd8d26ea54c3b733e697a6dc5832e9c518041d58810a31", + "0xe7e457e551cd6797d18ce084d19d4d87ed31d07cde475f2e25f5ed1b750c2c64", + "0xde5c26097beb3a1d3212c9aa0de1970f599a16ecd9197abee5b3a3b281e57cfc", + "0x45a1df846c4b8b4e2ff8d674d7133bac3e98098ca6b594714007d2e5f211950e", + "0x6617fad5c634c52d5fa9118e6cf0a53d5f13eec7c1ac9220f15ef53746c82aa8", + "0xd34a1393ebb316793e8fce4212a9853a4f44710fc9a9838caa605518b4fca573", + "0x3e8a846225e07e62bc18df6e31929b830aba74aa96fe661d5cc0b100fd999b17", + "0x3193c7cfbe7d2ecca6d37e6385d69463362d4b12e6f9e4d2f6ee996e6413afdc", + "0x2ce3aaebfe489553bca7435ae95401731f4cdfa2256a570f64abfb407f7063ed", + "0x3173dd10922eb73900cf8e32f91dac0ad05d347c9068905b549f743a8f16a751", + "0x62fd37c8031ef4693dc0de52dbe06c293249ce2ce4b3be0b7a02c607bfded1c4", + "0xc2580dae73e6b96af85676116914b8a247ab8b368ebb1d2d38640b8a726fe0fd", + "0x8025d1c443ce28c8d35974af5e31d934bb3b08cd10a24c95bbd1efc78bc7eb10", + "0x7a05e4e6aee417c062142c03a47a8be9674d57b445ec0f8629936dc9f5bfd52f", + "0xac55c7dc4cd5f7a90bfd9a386d598e95501b8aad159cdd0d8ddab691eba76049", + "0x3296a64eb4b70230366b27a448b42177c5cee1fa7913938d4767696a6570b4f8", + "0x478ecfbe71160700d04a9052cbb91d62920db80489534887c382be5399776faf", + "0x4530a0a6e3fe3fee4e79c60bd0599c76dc82e841523ef667885d4b1cd02ddd4f", + "0x25d4fa59ecec69d0ff70e70fcba3c7fa6ca5b0689048ce038141293775a8dcd0", + "0x03020dc01c0785c3e3fed74535db3aa3546916d25cd49876839632a929e51268", + "0xeb9ba2f7ea0d80cf7a563ce5e7edbc4ef638962a5a4c16f74ba8feca76668a0d", + "0x6a7a46ffefc8ff2edaffb608a0b7f57ff514398e54f4dc10a1d4cf218b20c7a9", + "0x5bc4c7f447e2821b1b4c94e2eaf754e9478c50d2488d246243b524e8addd18d3", + "0xd3eed3c14d29c81ec39a8ff6f75bbea5a8eae9f713e2e2e54bb6b824ed05028c", + "0x39429d962be1e6aa0b47cef6fb92c3433c54775718d865d5cf7110463613b7ae", + "0x51f19c8404e99f31c464e2cdbc5e44ed0d9486cd0efeea7894c740fae39ea641", + "0xc3695934786b04d41b3c5da84445a06e1fbb5a20e344146c1065845acc9abcd1", + "0xf177f104e6bb76e81e553ed80eb7064d3e6b74b2617c96a446ab9742e2d62002", + "0xe827aacb085e41a63526fa9809b3044f2a5186a04ef4e257dff1621c9052cb32", + "0x9fdd2ae7875a3129242552756462870f1bb831077f48b436608fbc9c11a0d629", + "0xacc8c222a52ca74e17aafa6f0f1d962107c0ab9ce4445a429ad955692d7c7aac", + "0xfea8015b875507e5621ad868954241c2b6de02545a2acaeb2f9109fa30384215", + "0x869cfeeb4898e17ab4850bd5e3797bc141f4814e5409df02725d345b57c64ad3", + "0x38b6c1377ada6abc07a7e7f3a92779907ce2f1064abd0b9be038d6ae51a4b276", + "0xf54091e4e9e9a758fdd8b00b9a78b4c91e17c01ce305041b4bf69d21c743fc45", + "0xd230e2b5c01fbb2ae97c27d70a8a1264c003e815809fb4240f7b500c63bfe82e", + "0xc126f31bd32f9aecb8012f206c64e6c05b60f863af3a9225c8971903290990ad", + "0xf6cdbf25100cc3839c4944180eb9f3f1beec798737a3f6f6074e612520d3de30", + "0xea3098d0600c35c4c62b440181092fd61676c207bddf3482c31bcd19fb352c87", + "0xc0c9da7c976544e331c40b34830f208b9638670fff5103d0c800542ee3f81b9f", + "0x5fa65f0d1c70d8340feb251a52e955a10151b0cb8200c00514b4a8df1995ca8e", + "0xeb44462413e46dcd9f49c3d5cb556eccc8e881861459fa35d83e256e7e007dac", + "0x3e44a1713f55e1f6f9130b8846dce91f710c1fb8c77298de2d09425c725c04e7", + "0x66fd8f8922d09de2f4e9dbd8d45c04a9461bdb5d88c5df9e897acf165f7634f5", + "0x6ad50a6f3f0db27728a9e948bd18db4d8ad025878bc1401fe8f9786446163bc2", + "0xe93822a027e88efdf7089adc382857f2fdc960c906314284759b6b5b6d3d4181", + "0x883772056f1957b772374333addcd927ca88de3f750ef89cf8dd4ba9f6f212dc", + "0x588861a7f2b707bdc3c85168ae2116c9775321b2d8c6f877309fb02e17a42c84", + "0xc8a88e9261c63b7a96b2345b7ce9d3a9b94d99469b68a400d73d808d84c5b0e0", + "0x1d7e0b13963d58e279ef24c9ce3d67d010dea519afc4bfad84e518a719f73755", + "0x057ab7682cc73ccdde80b76f64ceaf1702da7010953691e1d2d305daaa0e2770", + "0xb3e06d340bedc968190ec1aa0f7c2798472bce88eb07e016ab81033037b7ca96", + "0x6c4a17d4fbfd0ee8ced914ba9c2c83e394527fa36e2027e1b22cfcc49f069de7", + "0x9c66d88937ac802e5fd961fd0da8f5e493de32f6ff63bb8d2ab785e8f87192f5", + "0x3fdb9093f1a679d472e4ea81dacaaec8b3a060f71422ce815e3318ba212fad97", + "0x17792f6c2d5c2be0666702249fcb36904fe029bb7f6b1dca95af32182295f3e1", + "0xe6aafe170dac781c3e576d7616bf963dbfd5d1d27738e0cd6fdd759e6174700a", + "0x6321683aa65da9013794d27333fd3b7d570c4e100156d44e999a930a634a3cdd", + "0x8aa56c35f7c70629a4b9272b1391e13c080c97c03b3ed675bd46737119f341b8", + "0x0f8384a649c8dfc242484c669ac4a798bb19b89f85d4d245b8415aa4dad0711d", + "0x041669c526354ff960ef721d72306b3a9d5e5a59501d565aaf1036f8d6d1aa0d", + "0x0af7915a53ade49d28eaefc8f43f24500a5a12acd06f23c80b8ab675220ade3e", + "0x5aeee4a33bacd934feac2c3e6a46cae5d00cac6ff8fa57167100d66e5ee73456", + "0x44aa02ff76be04a0ac59b4491ae9a6ae8cd475fb058dbd4c94220d26d554126a", + "0xed5b8883a073d192663e45eaaa55eaa840155bb9a201065cc61eefe2917c6ed2", + "0x4d856173cdfb61fb83d755b1957e39609a915c45f3b29950acb4cffd012cc3ad", + "0x50af3f28ce9ce9e95f664d2fa59afa461e88e949a0584407a92c113828248844", + "0x2ab900c46ed0980623eaa1cb61df89ff92d949bfdccc568ccb2183f83ef622a1", + "0xf2765636da2615454790b314148be63ad8008d0f6880dfc7767d36b88b753c31", + "0xc5df53c2589fbb388cae91b2efd03c1c707615e05e12f3e681def70e0d913697", + "0xa386bbfb9634a6f910e7052e188a81c9a6a1a318d340703c8e29dcee4b57eea6", + "0xad19889349d7d41230cb039ed46289e7e9ea0fb76ef2ee427d5a05892fe680ef", + "0xda6802024bf8ce4c2152fd2f1c166868159a2c4c70df00b28ede48644ee731cc", + "0xa563da16e6fa8a65b523d67399fdb3b5492508901037ad76f5f41aaa174a780d", + "0x9ee367b021d6ac2e516f16f48961de800b89f9b7115ae616b52d746b7ba8ef0b", + "0x37aeefeb48b2613b4afac289022e1707da0c596d6d8b85e59505ec5a3f47b7f5", + "0xbd0a3c7cb0d4c60411db3290cd2d0cda5c21cf22d9e36b8dc77fb7f572c806b7", + "0xe5d875bca8c6da0c24c0b7ee191168e22af7c99d3b7d58246eb1675bd3c090f4", + "0x9365c55d9be42230ba376054ca9df4346803e63ea4cb683261de4c497f92b329", + "0x0b8024d771e5f167db261b3da6f16e745198fb5ff550c51e689c3387fafc3efd", + "0x9cb78e33aed15fa5b6094e978883d147e8329ccd7371518cbf6da96b97dc9f70", + "0x6f6dcaf8f0ae184c7c065e322e390f27e27f3c4c554158bee433430aa5319108", + "0x0c729da3730254b379cc130776a9ea79575e7cd88071423a0635aa18f4aed0d5", + "0x0f918fff241f4492e630717a91c58af660b02201a64bd14d3a577b1c9390f5bc", + "0x6a33af88b454aeb3fcddcfa5043af313158de701d5227915e2d835bd8f2eb7db", + "0x7344a8e8ceafb36aee8bc1e3a1ca73168f583ecc7959e72b8a223fe252ad60dc", + "0xf457f0572ddee6c71e79f5f8d0643e4b59abd1798ac9dc5f158ea75efaff389d", + "0x0cbe584ca5e7a45b7fabdda306eb5c0f9b015cfe6f30ca451065bb38541b2bfd", + "0x91f35848c79274053eb0294be8395082ce4e5c08b5e6560fb9f3758609066ccc", + "0x4999f6428a7e0077f71eb127218270468f57561da1799470cfd736992013e074", + "0x042f9db538d5b8344279fadd5d3c8da5b4b9b455ee1d94aac1606272d052eca3", + "0xfb28b022f556e4344360b479d809cdad7ba7ee86a5e4943928f1dcf3f57a133d", + "0x687178fcd4ced35dc148a0e142276524d03240f750fe5cfa3d034e3fb9fcb4eb", + "0x441172f8e8b24698a50668aa6136b489bc85b7b21648e29f8ed1683399e7c56a", + "0x5f8c54d03b4fd64a2e5b526058bad1a27ba26f0feafc914fd6fb01b7fd31eb57", + "0x112af02bf0fafb42cc9e7b2b3985c5be78c3320550768d8bd271d62743a3a04c", + "0xf84b6ecc88fdd759a1c2263a0a4226a753b62a10df3fd7f094a1c9df7ea5918e", + "0x54ae04f6da0a8351f4ee4a2e36e1832329d5b6dd22452374abe1335914b36baa", + "0x52ab4533e536b7649979822857b1369df6cb0299f0f4ab32da6b8a7d2cff864c", + "0x8fc44fa1f6fe9e0b96b1f72da8b9936419a10a49ea5c02ba543a22b9f32e0618", + "0x95ee4eeba33f81a8d5eda57de81c3617fe03f785e7d9e90c085b91fe23a57a1c", + "0xadbc77bb5afc1c93a42d799fdff05e15998a17aa17d477611d9ba1d68b4abaa0", + "0x80ef051da1139c8f714f152629ca8b4607e82abc097d5f67bf66e26e3ec4b83b", + "0x6dad58c6230b60017db9536548b99c725644168f55d4cb2a1a0353a5e948b0de", + "0x8baa0703e1a050c40f85dc850fe477881f432c951b1cc1b2b71ffb68ab7fe0d7", + "0x14ca94dfd343548e32ef5659c043d6e28f0e577fd38da1ee12f11c08e281d775", + "0xef25357970c76a8b72a6e52f49bc30651f711c7df70444d4667e80febc0e3b2a", + "0x41b8b4ebd5919dad3bc609ded524b97403d88f019367f0f4f622561131644ffb", + "0xb29a8ad1157621d0120aedbd8dfeb4b318979bd43a5b018bf7b9ce33d85da312", + "0x9ddf78b5d67ef40454867ed33de83a01cbd8c18fe09da3d9f991a196811dfccd", + "0x3604121f9cfbb5cf552cf8bfc9a7958332eb97131158e4f40f4eda481e553991", + "0xf1778830f694720a6f990f9d476b0f365e8a74880253b55ee16f5cbd6c8082a4", + "0x89831626d154fbe84a4c62c3e2638cd00e42b3844c7c7b98cfad113abdbc5347", + "0x650573f5ef274b2aeb40642e25fbd661cb0eff66245d7cc8f6fb9e9daa80fc12", + "0x479f6c652173efe94abaa850bffe1557847b26f286467013a4d72973e05e8e54", + "0x7096619d5716c34592ac2d9907ac28a74c6f6b1ebb1962a0217df82bf3e714d4", + "0xb7c7edbd8ae7eed58e973dc0750adfd04042ed56baabf372b111fce3e4b4469a", + "0x25529b597bd15317e55767b3fbfecad0657aaeda99f098186b41b70811f7af2a", + "0xd790747b09f925fd155b7bbdb5ccd89d873277163e4fe7054bbf71c0b26b8072", + "0x3aa0b221d1c4743a06692f645f38a8128d55f1c07cfa6e9711b0d2e0f2e0e738", + "0x26fb5017218cbe4250d2ceae751e99b9a34d7befa162dc248ac008c5d1221e71", + "0x0e4ada59854027601f8f81fbdceb95228db667eb65fed97cefbb35dba21d3b52", + "0xd3be75ae2da3e271dd85cd8226d789aa12d108a4b0d2681462f6539637572e50", + "0x6f041891c8219b508138f67c95a1765d08c5ec06b9ce585f52f837806fce0609", + "0x9e106515d0e80b41397b2e8e98adbb7333e76265917339a62063a07d9a7ed311", + "0x25f47483ecc5ec32f94b3dbcb4d42a4cdbf5c279e93567e14afc742a4619d3e0", + "0x5d81afc54f6b68bd820dcc629ff7e9d8397da56ffedef9addab0eec620de0757", + "0x36e192130485f248925d4b0d2fd98745a76099eb13f53093621d216d0aff0d6c", + "0xb906e5e33b63f6cc355c13b8461a260ee25376ee96909fad2c6ac121ad831496", + "0xd68e7e0d136e30f67ccb7c21e4dc43b0ad5536584e4b77c9da8d903a04e9d212", + "0x5aa7847a4bddda7fbffa62325da920a21a11524ac1b691bc3b55e4d1790f24bc", + "0x331f95f062ed1d38dd02b5ab6a95dd238ef97c5ee9777c938697340c902b4b5d", + "0x8c6a580c8b07567f747bf20946023c3b581c51075cce5cd5d47b0d81d8922135", + "0x8b89483810a49626f90846a0b49ad3e2172657dfa3003d58fa2a43d12c8f4090", + "0x944f9a5754800a33d903c8a464d602fc9da6af8ff3990c3eb669ac9cd17891f9", + "0xc75c82a2c1ecd875d16f343a58835d756740902c246d3b1deae97e49aa19f98b", + "0x1d2e0f2f87ff2b08514b18855c343966d42e0f1a048ddd3d316dca6e06292db9", + "0xa6508507463e53b3a840dd55ed9be57c8a56e1533c9001276750bdf19796f8ea", + "0x01eb6b636b1852e8f9066c12d4e6b7b06b90a325be4d97e08f7f560bab4796a1", + "0x8a0d77fb41f50808ff0a46dc9f3831a2b5093f55ec2e94a3d2e92373ff3b5695", + "0xea3383ba1d30891d1e236db2b31373541f51a9e5c4b4d017cc4960480dd20311", + "0x01129e8d7eff516a225cc0db090e4e38362d9eb2d0571ce00f4417836de2e375", + "0x92feaefb7f9466814a0220e536fe5ee73560507d071e059827d406329e609f87", + "0xac149150c11b3bdc660320a0e955f154fa3137549a73951207659e2b903c145b", + "0xcb68cdb224f9b3b0b0f3ca0056e70817146c9ebc75876dd952e6ca8ea896f2ac", + "0x157565282a12d790452e343c9762c2124456039729f3a8f97a2cee60d85628fa", + "0x42eadc181d59d8d8b26b37e0e9c9052e45bde72090d330bf9cf21d9d3c7d9048", + "0x1ea0ec8879b200e259a3a2a0f2a7aa292301784fa422f7c32ed5d945183948b2", + "0x06aeb2956be9d74ae4ff0b8a6c1874ed8ba46a186616356dc060bea1cbe5c628", + "0x814b0382b52a155a4e35639aeb3d8c859afc4fe5d151de3b0f1bac646e40f2eb", + "0xb30bf3e85be41a2a9e53321ee9f03c7078516c72c7e2d8e7e3134de709b61c36", + "0x1f97f5d334b5e6ebc72f5b846f24c7911f4fd1653f89b3477ce4b8108342810f", + "0x84c6fd181c28ad159ff18d203d14f966668468c9ef0a5d6dbd863886a7e0af1e", + "0x4b2e6947d55ea504bf205bae9dfc0e5402efd33757eea4da00a8ed2a6a3838ae", + "0x85f31d45128bb91cd3490b58a0a641ef77246ea9c83de30fa89b621307fd96f3", + "0xd362f5e6f8cbb216e66eaf49e4df25e01504ac729da86c530871a34e11d302f6", + "0xb7860983b043bc13ce5a27135eea12ffaeff71879404b18af3079b98da156bf2", + "0xf2ff82a679b2b90cb9f4a3bb903eb7ab36ee1c47cbe40024d8d570f5e16bbf4e", + "0x7e34a7e6673146b6bb7f78593b6093ef15b8e9fd1271b33dc5f7d17876b31871", + "0x725c97f83b4cf213296ef353e1c8d64854ef08983fd61320088b8d9e2ab33849", + "0x18085800d10fc7845148835d0ef0ac980a82eeafc44e12bfa296f9c38fc6e19d", + "0xc6c3cf95310cfd0254f0f8e93a3c25bad2b17df04f9c51a25927b80d02e06b69", + "0x822213c1b03cf68ecadc0b7572d37266207d5fe4efd5e56a924b0a1aab8a8e84", + "0x1ff46ffd2dd880cca76244f6af1fd8bddbb4b9ec58f86639821a16f2ff08f3a8", + "0xe9d00df19d716dc859922f2e6c907263191c8e531498ea557869ea1115317c95", + "0x6d3f1edebd562e9d1a236ed7a1d9104fd8f5a086cd78d35c7a65f27c269d98ca", + "0xfea701ced5bca0d5043512700598d3eafa0b89dc02f3c157cd1d52bcf4d84d9b", + "0x556c1cd8ff3ebc2ccd4eee9f1ad3837e346ecda961da17c0ee9cd4d084a47653", + "0x5606be2fba065424af76c94d4156ea82f77d9872ddac7a4c2517957a169e58f9", + "0x8d0223425b48487db1b371c966c7688435f4b9fcda75b088f0aac203d6657cb1", + "0xfceb55d8f3048a3f2255562e0a9ee342439253abcd048fac151ef4b910048e22", + "0x360f76e4f2ef49632e3bf8cfc3afeccff6917e98a48d3568148c3bb13f9d2d7e", + "0xd87bbf8397204cc2af883362646b0ae95392303935ec1997ab052c194e0ef117", + "0x9f1dad9dfecaaf117ab5277caf672b70540578e703c2024d3f23bb7cf8d6410b", + "0x5e130ccb23b7b66dd2fbdd912d6006d2820071dafe2890f593f952028aaa19c0", + "0xccd2f182107992fb9b002b87cdf7990cb2810b202b2ae5d6ef5e0b3bd69632e2", + "0x4b40cd83205f8b946ca9f11fc3306872650e658e631511fd4080bc8ca749d913", + "0x652acc59b71ca20bb65ca195d1a4b3e177f6a3985bdcd6120e1a45b7d4a0c7ca", + "0x49a5e2580ceb329665244e489592aea27d54da8189a665d9435e037ea70c46a5", + "0x379801356beb3a8e5fa7311792c69c7ac1f675a9c08c837f9f0e9f53c243d6a7" ] }, "nodes": [ diff --git a/ethcore/res/ethereum/social.json b/ethcore/res/ethereum/social.json index 52b442d0886b844f9029297bd24e175b138d8ae1..2ad8fec8b06a20a874b811cf4f4c7117fe1de338 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/ethereum/tobalaba.json b/ethcore/res/ethereum/tobalaba.json new file mode 100644 index 0000000000000000000000000000000000000000..e9345c69615de5368c58cd91e0328154e10e2a4a --- /dev/null +++ b/ethcore/res/ethereum/tobalaba.json @@ -0,0 +1,54 @@ +{ + "name": "Tobalaba", + "engine": { + "authorityRound": { + "params": { + "stepDuration": "3", + "validators": { + "contract": "0x1000000000000000000000000000000000000005" + }, + "maximumUncleCount": 999999 + } + } + }, + "params": { + "maximumExtraDataSize": "0x20", + "gasLimitBoundDivisor": "0x400", + "minGasLimit": "0x1388", + "networkID": "0x62121", + "wasmActivationTransition": 4000000 + }, + "genesis": { + "seal": { + "authorityRound": { + "step": "0x0", + "signature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + }, + "difficulty": "0x20000", + "gasLimit": "0x800000" + }, + "accounts": { + "0x1000000000000000000000000000000000000005": { + "balance": "1", + "constructor": "6060604052341561000f57600080fd5b5b60048054600160a060020a03199081167310000000000000000000000000000000000000061790915560028054909116731000000000000000000000000000000000000007179055600080546001810161006a8382610115565b916000526020600020900160005b8154600160a060020a036101009290920a9182021916734ba15b56452521c0826a35a6f2022e1210fc519b90910217905550600180548082016100bb8382610115565b916000526020600020900160005b8154600160a060020a036101009290920a9182021916734ba15b56452521c0826a35a6f2022e1210fc519b9182021790915560038054600160a060020a0319169091179055505b610160565b8154818355818115116101395760008381526020902061013991810190830161013f565b5b505050565b61015d91905b808211156101595760008155600101610145565b5090565b90565b610a208061016f6000396000f300606060405236156100ee5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166303aca792811461013d578063063a54c91461016f57806311ae9ed21461019e578063170f9291146102055780631cd3e85814610237578063480b4619146102585780636c1247e5146102bf5780637a1a9e60146102ee578063830f0bc6146103205780638da5cb5b146103525780639b2ae4c614610381578063b6f783f2146103a6578063b7ab4db5146103d5578063c55642be1461043c578063e2de215e1461045d578063fe5d935c1461048c578063ff7a071b146104f3575b34156100f957600080fd5b5b600454600160a060020a0316600036604051808383808284378201915050925050506000604051808303818561646e5a03f4915050151561013a57600080fd5b5b005b341561014857600080fd5b610153600435610518565b604051600160a060020a03909116815260200160405180910390f35b341561017a57600080fd5b61015361054a565b604051600160a060020a03909116815260200160405180910390f35b34156101a957600080fd5b6101b161055a565b60405160208082528190810183818151815260200191508051906020019060200280838360005b838110156101f15780820151818401525b6020016101d8565b505050509050019250505060405180910390f35b341561021057600080fd5b6101536004356105c3565b604051600160a060020a03909116815260200160405180910390f35b341561024257600080fd5b61013a600160a060020a03600435166105f5565b005b341561026357600080fd5b6101b16106d1565b60405160208082528190810183818151815260200191508051906020019060200280838360005b838110156101f15780820151818401525b6020016101d8565b505050509050019250505060405180910390f35b34156102ca57600080fd5b61015361073a565b604051600160a060020a03909116815260200160405180910390f35b34156102f957600080fd5b610153600435610749565b604051600160a060020a03909116815260200160405180910390f35b341561032b57600080fd5b61015360043561077b565b604051600160a060020a03909116815260200160405180910390f35b341561035d57600080fd5b6101536107ad565b604051600160a060020a03909116815260200160405180910390f35b341561038c57600080fd5b6103946107bc565b60405190815260200160405180910390f35b34156103b157600080fd5b6101536107c3565b604051600160a060020a03909116815260200160405180910390f35b34156103e057600080fd5b6101b16107d3565b60405160208082528190810183818151815260200191508051906020019060200280838360005b838110156101f15780820151818401525b6020016101d8565b505050509050019250505060405180910390f35b341561044757600080fd5b61013a600160a060020a036004351661083c565b005b341561046857600080fd5b610153610918565b604051600160a060020a03909116815260200160405180910390f35b341561049757600080fd5b6101b1610927565b60405160208082528190810183818151815260200191508051906020019060200280838360005b838110156101f15780820151818401525b6020016101d8565b505050509050019250505060405180910390f35b34156104fe57600080fd5b610394610990565b60405190815260200160405180910390f35b600180548290811061052657fe5b906000526020600020900160005b915054906101000a9004600160a060020a031681565b600254600160a060020a03165b90565b610562610997565b60018054806020026020016040519081016040528092919081815260200182805480156105b857602002820191906000526020600020905b8154600160a060020a0316815260019091019060200180831161059a575b505050505090505b90565b600080548290811061052657fe5b906000526020600020900160005b915054906101000a9004600160a060020a031681565b60035433600160a060020a0390811691161461061057600080fd5b600254600160a060020a038281169116141561062b57600080fd5b600680546001810161063d83826109a9565b916000526020600020900160005b600280548354600160a060020a036101009490940a848102199091169184160217909255815473ffffffffffffffffffffffffffffffffffffffff1916908416179055507f78603ac34f42fe53d8aad96b7b37aeee79dc7ed07c26f57a13cdf64ac72b0f1181604051600160a060020a03909116815260200160405180910390a15b5b50565b6106d9610997565b60058054806020026020016040519081016040528092919081815260200182805480156105b857602002820191906000526020600020905b8154600160a060020a0316815260019091019060200180831161059a575b505050505090505b90565b600254600160a060020a031681565b600680548290811061052657fe5b906000526020600020900160005b915054906101000a9004600160a060020a031681565b600580548290811061052657fe5b906000526020600020900160005b915054906101000a9004600160a060020a031681565b600354600160a060020a031681565b6001545b90565b600454600160a060020a03165b90565b6107db610997565b60008054806020026020016040519081016040528092919081815260200182805480156105b857602002820191906000526020600020905b8154600160a060020a0316815260019091019060200180831161059a575b505050505090505b90565b60035433600160a060020a0390811691161461085757600080fd5b600454600160a060020a038281169116141561087257600080fd5b600580546001810161088483826109a9565b916000526020600020900160005b600480548354600160a060020a036101009490940a848102199091169184160217909255815473ffffffffffffffffffffffffffffffffffffffff1916908416179055507fadcbcb6339ee0b34abbe8d1524c53b813794e1537a43136c6a7768019599625781604051600160a060020a03909116815260200160405180910390a15b5b50565b600454600160a060020a031681565b61092f610997565b60068054806020026020016040519081016040528092919081815260200182805480156105b857602002820191906000526020600020905b8154600160a060020a0316815260019091019060200180831161059a575b505050505090505b90565b6000545b90565b60206040519081016040526000815290565b8154818355818115116109cd576000838152602090206109cd9181019083016109d3565b5b505050565b61055791905b808211156109ed57600081556001016109d9565b5090565b905600a165627a7a72305820e9d3839061bfeb56c1cc57b2b2ec8dd7882afd848b4ae489c218d6f9674316660029" + }, + "0x1000000000000000000000000000000000000006": { + "balance": "1", + "constructor": "6060604052341561000f57600080fd5b5b60028054600160a060020a0319167310000000000000000000000000000000000000071790555b5b610abb806100476000396000f300606060405236156100885763ffffffff60e060020a60003504166303aca792811461008d578063170f9291146100bf57806340a141ff146100f15780634d238c8e146101125780634d655aff1461013357806375286211146101625780638da5cb5b14610177578063a6f9dae1146101a6578063c476dd40146101c7578063d69f13bb1461022e575b600080fd5b341561009857600080fd5b6100a3600435610252565b604051600160a060020a03909116815260200160405180910390f35b34156100ca57600080fd5b6100a3600435610284565b604051600160a060020a03909116815260200160405180910390f35b34156100fc57600080fd5b610110600160a060020a03600435166102b6565b005b341561011d57600080fd5b610110600160a060020a036004351661064d565b005b341561013e57600080fd5b6100a36107a1565b604051600160a060020a03909116815260200160405180910390f35b341561016d57600080fd5b6101106107b0565b005b341561018257600080fd5b6100a36107ed565b604051600160a060020a03909116815260200160405180910390f35b34156101b157600080fd5b610110600160a060020a03600435166107fc565b005b34156101d257600080fd5b61011060048035600160a060020a03169060248035919060649060443590810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284375094965061084495505050505050565b005b341561023957600080fd5b610110600160a060020a0360043516602435610926565b005b600180548290811061026057fe5b906000526020600020900160005b915054906101000a9004600160a060020a031681565b600080548290811061026057fe5b906000526020600020900160005b915054906101000a9004600160a060020a031681565b60035460009033600160a060020a039081169116146102d457600080fd5b600254600160a060020a031663b31610db8360006040516020015260405160e060020a63ffffffff8416028152600160a060020a039091166004820152602401602060405180830381600087803b151561032d57600080fd5b6102c65a03f1151561033e57600080fd5b50505060405180511515905061035357600080fd5b60008054600019810190811061036557fe5b906000526020600020900160005b9054600254600160a060020a036101009390930a9091048216925082916001911663b31610db8560006040516020015260405160e060020a63ffffffff8416028152600160a060020a039091166004820152602401602060405180830381600087803b15156103e157600080fd5b6102c65a03f115156103f257600080fd5b50505060405180518254909150811061040757fe5b906000526020600020900160005b6101000a815481600160a060020a030219169083600160a060020a0316021790555060018080805490500381548110151561044c57fe5b906000526020600020900160005b81546101009190910a600160a060020a0302191690556001805460001901906104839082610991565b50600254600160a060020a0316635caf5a6a828263b31610db8660006040516020015260405160e060020a63ffffffff8416028152600160a060020a039091166004820152602401602060405180830381600087803b15156104e457600080fd5b6102c65a03f115156104f557600080fd5b5050506040518051905060405160e060020a63ffffffff8516028152600160a060020a0390921660048301526024820152604401600060405180830381600087803b151561054257600080fd5b6102c65a03f1151561055357600080fd5b5050600254600160a060020a03169050635caf5a6a83600060405160e060020a63ffffffff8516028152600160a060020a0390921660048301526024820152604401600060405180830381600087803b15156105ae57600080fd5b6102c65a03f115156105bf57600080fd5b5050506000194301407f55252fa6eee4741b4e24a74a70e9c11fd2c2281df8d6ea13126ff845f7825c89600160405160208082528254908201819052819060408201908490801561063957602002820191906000526020600020905b8154600160a060020a0316815260019091019060200180831161061b575b50509250505060405180910390a25b5b5050565b60035433600160a060020a0390811691161461066857600080fd5b600180548082016106798382610991565b916000526020600020900160005b81546101009190910a600160a060020a0381810219909216858316919091021790915560025460015491169150635caf5a6a9083906000190160405160e060020a63ffffffff8516028152600160a060020a0390921660048301526024820152604401600060405180830381600087803b151561070357600080fd5b6102c65a03f1151561071457600080fd5b5050506000194301407f55252fa6eee4741b4e24a74a70e9c11fd2c2281df8d6ea13126ff845f7825c89600160405160208082528254908201819052819060408201908490801561078e57602002820191906000526020600020905b8154600160a060020a03168152600190910190602001808311610770575b50509250505060405180910390a25b5b50565b600254600160a060020a031681565b73fffffffffffffffffffffffffffffffffffffffe600160a060020a033316146107d957600080fd5b6001805461079d916000916109e5565b505b565b600354600160a060020a031681565b60035433600160a060020a0390811691161461081757600080fd5b6003805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b5b50565b73fffffffffffffffffffffffffffffffffffffffe600160a060020a0333161461086d57600080fd5b7f8498b6f07a5f800443a5fd85ac8171cf40cda44faea60caabe9b297d9dfa8424838383604051600160a060020a03841681526020810183905260606040820181815290820183818151815260200191508051906020019080838360005b838110156108e45780820151818401525b6020016108cb565b50505050905090810190601f1680156109115780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a15b505050565b73fffffffffffffffffffffffffffffffffffffffe600160a060020a0333161461094f57600080fd5b81600160a060020a03167f31bc112157435aab6dd7e9a059abea7f0fce172e3e68e272a6375bbb01eb96c18260405190815260200160405180910390a25b5050565b81548183558181151161092157600083815260209020610921918101908301610a36565b5b505050565b81548183558181151161092157600083815260209020610921918101908301610a36565b5b505050565b828054828255906000526020600020908101928215610a255760005260206000209182015b82811115610a25578254825591600101919060010190610a0a565b5b50610a32929150610a57565b5090565b610a5491905b80821115610a325760008155600101610a3c565b5090565b90565b610a5491905b80821115610a3257805473ffffffffffffffffffffffffffffffffffffffff19168155600101610a5d565b5090565b905600a165627a7a72305820cae3ca62c5821766e8122461884affeaabdc6c2fe79f5a3200207a536e5b0e260029" + }, + "0x1000000000000000000000000000000000000007": { + "balance": "1", + "constructor": "6060604052341561000f57600080fd5b5b60018054600160a060020a0319167310000000000000000000000000000000000000051790555b5b6101bb806100476000396000f300606060405263ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166318def8ef811461005e5780635caf5a6a1461008f5780638da5cb5b146100b3578063b31610db146100e2575b600080fd5b341561006957600080fd5b61007d600160a060020a0360043516610113565b60405190815260200160405180910390f35b341561009a57600080fd5b6100b1600160a060020a0360043516602435610125565b005b34156100be57600080fd5b6100c6610161565b604051600160a060020a03909116815260200160405180910390f35b34156100ed57600080fd5b61007d600160a060020a0360043516610170565b60405190815260200160405180910390f35b60006020819052908152604090205481565b60015433600160a060020a0390811691161461014057600080fd5b600160a060020a03821660009081526020819052604090208190555b5b5050565b600154600160a060020a031681565b600160a060020a0381166000908152602081905260409020545b9190505600a165627a7a7230582085b261e548fa6e3065a32e485c6417d200c7145f3548c0097d4c92022ac7fb1e0029" + }, + "0x4ba15b56452521c0826a35a6f2022e1210fc519b": { + "balance": "0x7E37BE2022B2B09472D89C0000" + } + }, + "nodes": [ + "enode://147573f46fe9f5cc38fbe070089a31390baec5dd2827c8f2ef168833e4d0254fbee3969a02c5b9910ea5d5b23d86a6ed5eabcda17cc12007b7d9178b6c697aa5@37.120.168.56:30303", + "enode://a370d5fd55959f20af6d1565b151a760c1372f5a2aaf674d4892cd4fd2de0d1f672781cd40e0d4e4b51c5823527ddec73b31cc14ac685449d9f0866996a16b9f@13.76.165.180:30303", + "enode://da019fa5fb1fda105100d68a986938ec15ac5c6ff69d6e4ad3e350e377057f3e67e33aea5feb22d5cdcfc22041d141c8453c77baa64a216fff98f191ca76b3ec@18.220.108.238:30303", + "enode://49498fb8cdcd79c813ccdaa9496a3a4be0a187a3183e99adbc04d9c90b9a62ad59f0b6832f6e43b48e63fbebf74ec5438eb0d6d9098330edf36413d276fedf81@13.80.148.117:30303" + ] +} diff --git a/ethcore/res/tx_permission_tests/contract_ver_2_genesis.json b/ethcore/res/tx_permission_tests/contract_ver_2_genesis.json new file mode 100644 index 0000000000000000000000000000000000000000..b165625a1651e1ff8744b770da69cbbb3b628f66 --- /dev/null +++ b/ethcore/res/tx_permission_tests/contract_ver_2_genesis.json @@ -0,0 +1,43 @@ +{ + "name": "TestNodeFilterContract", + "engine": { + "authorityRound": { + "params": { + "stepDuration": 1, + "startStep": 2, + "validators": { + "contract": "0x0000000000000000000000000000000000000000" + } + } + } + }, + "params": { + "accountStartNonce": "0x0", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID" : "0x69", + "gasLimitBoundDivisor": "0x0400", + "transactionPermissionContract": "0x0000000000000000000000000000000000000005" + }, + "genesis": { + "seal": { + "generic": "0xc180" + }, + "difficulty": "0x20000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x", + "gasLimit": "0x222222" + }, + "accounts": { + "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "0000000000000000000000000000000000000005": { + "balance": "1", + "constructor": "608060405234801561001057600080fd5b506104eb806100206000396000f300608060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063469ab1e31461006757806375d0c0dc1461009a578063a0a8e4601461012a578063d4b03ee014610155575b600080fd5b34801561007357600080fd5b5061007c6101ed565b60405180826000191660001916815260200191505060405180910390f35b3480156100a657600080fd5b506100af61025e565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100ef5780820151818401526020810190506100d4565b50505050905090810190601f16801561011c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561013657600080fd5b5061013f61029b565b6040518082815260200191505060405180910390f35b34801561016157600080fd5b506101c0600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506102a4565b604051808363ffffffff1663ffffffff168152602001821515151581526020019250505060405180910390f35b60006101f761025e565b6040518082805190602001908083835b60208310151561022c5780518252602082019150602081019050602083039250610207565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020905090565b60606040805190810160405280601681526020017f54585f5045524d495353494f4e5f434f4e545241435400000000000000000000815250905090565b60006002905090565b600080737e5f4552091a69125d5dfcb7b8c2659029395bdf8573ffffffffffffffffffffffffffffffffffffffff1614156102e95763ffffffff6001915091506104b7565b732b5ad5c4795c026514f8317c7a215e218dccd6cf8573ffffffffffffffffffffffffffffffffffffffff16141561032b5760026001176001915091506104b7565b736813eb9362372eef6200f3b1dbc3f819671cba698573ffffffffffffffffffffffffffffffffffffffff16141561036957600180915091506104b7565b73e1ab8145f7e55dc933d51a18c793f901a3a0b2768573ffffffffffffffffffffffffffffffffffffffff161480156103a25750600083145b156103b75763ffffffff6000915091506104b7565b73e57bfe9f44b819898f47bf37e5af72a0783e11418573ffffffffffffffffffffffffffffffffffffffff16148015610419575073d41c057fd1c78805aac12b0a94a405c0461a6fbb8473ffffffffffffffffffffffffffffffffffffffff16145b1561042b5760016000915091506104b7565b73d41c057fd1c78805aac12b0a94a405c0461a6fbb8573ffffffffffffffffffffffffffffffffffffffff1614801561048d575073e57bfe9f44b819898f47bf37e5af72a0783e11418473ffffffffffffffffffffffffffffffffffffffff16145b80156104995750600083145b156104ae5763ffffffff6000915091506104b7565b60006001915091505b9350939150505600a165627a7a723058204982adea2aa10a7b8328ec3829472ee17c62a86957ef6737f2eb729b2c3faf910029" + } + } +} diff --git a/ethcore/res/tx_permission_tests/deprecated_contract_genesis.json b/ethcore/res/tx_permission_tests/deprecated_contract_genesis.json new file mode 100644 index 0000000000000000000000000000000000000000..92fde908089b51eb55fb58bed2f8f3bef0bcbf1a --- /dev/null +++ b/ethcore/res/tx_permission_tests/deprecated_contract_genesis.json @@ -0,0 +1,43 @@ +{ + "name": "TestNodeFilterContract", + "engine": { + "authorityRound": { + "params": { + "stepDuration": 1, + "startStep": 2, + "validators": { + "contract": "0x0000000000000000000000000000000000000000" + } + } + } + }, + "params": { + "accountStartNonce": "0x0", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID" : "0x69", + "gasLimitBoundDivisor": "0x0400", + "transactionPermissionContract": "0x0000000000000000000000000000000000000005" + }, + "genesis": { + "seal": { + "generic": "0xc180" + }, + "difficulty": "0x20000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x", + "gasLimit": "0x222222" + }, + "accounts": { + "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "0000000000000000000000000000000000000005": { + "balance": "1", + "constructor": "6060604052341561000f57600080fd5b5b6101868061001f6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063e17512211461003e575b600080fd5b341561004957600080fd5b610075600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610097565b604051808263ffffffff1663ffffffff16815260200191505060405180910390f35b6000737e5f4552091a69125d5dfcb7b8c2659029395bdf8273ffffffffffffffffffffffffffffffffffffffff1614156100d75763ffffffff9050610155565b732b5ad5c4795c026514f8317c7a215e218dccd6cf8273ffffffffffffffffffffffffffffffffffffffff1614156101155760026001179050610155565b736813eb9362372eef6200f3b1dbc3f819671cba698273ffffffffffffffffffffffffffffffffffffffff1614156101505760019050610155565b600090505b9190505600a165627a7a72305820f1f21cb978925a8a92c6e30c8c81adf598adff6d1ef941cf5ed6c0ec7ad1ae3d0029" + } + } +} diff --git a/ethcore/service/Cargo.toml b/ethcore/service/Cargo.toml index 3a10849b61f9e792c2224d7d8276e929b2e63c38..245bce787781eafd17905cb6c4f5472b719dbd2d 100644 --- a/ethcore/service/Cargo.toml +++ b/ethcore/service/Cargo.toml @@ -5,16 +5,17 @@ authors = ["Parity Technologies "] [dependencies] ansi_term = "0.10" -error-chain = { version = "0.11", default-features = false } +error-chain = { version = "0.12", default-features = false } ethcore = { path = ".." } ethcore-io = { path = "../../util/io" } ethcore-private-tx = { path = "../private-tx" } ethcore-sync = { path = "../sync" } -kvdb = { path = "../../util/kvdb" } +kvdb = { git = "https://github.com/paritytech/parity-common" } log = "0.3" stop-guard = { path = "../../util/stop-guard" } trace-time = { path = "../../util/trace-time" } [dev-dependencies] +ethcore = { path = "..", features = ["test-helpers"] } tempdir = "0.3" -kvdb-rocksdb = { path = "../../util/kvdb-rocksdb" } +kvdb-rocksdb = { git = "https://github.com/paritytech/parity-common" } diff --git a/ethcore/service/src/service.rs b/ethcore/service/src/service.rs index f703329d611ba229fcf50faddf8fbb5c7db43cd2..81997be079ea2c9b13b00ec99f7b4271a099410e 100644 --- a/ethcore/service/src/service.rs +++ b/ethcore/service/src/service.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -22,10 +22,10 @@ use std::time::Duration; use ansi_term::Colour; use io::{IoContext, TimerToken, IoHandler, IoService, IoError}; -use kvdb::{KeyValueDB, KeyValueDBHandler}; use stop_guard::StopGuard; use sync::PrivateTxHandler; +use ethcore::{BlockChainDB, BlockChainDBHandler}; use ethcore::client::{Client, ClientConfig, ChainNotify, ClientIoMessage}; use ethcore::miner::Miner; use ethcore::snapshot::service::{Service as SnapshotService, ServiceParams as SnapServiceParams}; @@ -69,7 +69,7 @@ pub struct ClientService { client: Arc, snapshot: Arc, private_tx: Arc, - database: Arc, + database: Arc, _stop_guard: StopGuard, } @@ -78,9 +78,9 @@ impl ClientService { pub fn start( config: ClientConfig, spec: &Spec, - client_db: Arc, + blockchain_db: Arc, snapshot_path: &Path, - restoration_db_handler: Box, + restoration_db_handler: Box, _ipc_path: &Path, miner: Arc, account_provider: Arc, @@ -93,7 +93,8 @@ impl ClientService { info!("Configured for {} using {} engine", Colour::White.bold().paint(spec.name.clone()), Colour::Yellow.bold().paint(spec.engine.name())); let pruning = config.pruning; - let client = Client::new(config, &spec, client_db.clone(), miner.clone(), io_service.channel())?; + let client = Client::new(config, &spec, blockchain_db.clone(), miner.clone(), io_service.channel())?; + miner.set_io_channel(io_service.channel()); let snapshot_params = SnapServiceParams { engine: spec.engine.clone(), @@ -131,7 +132,7 @@ impl ClientService { client: client, snapshot: snapshot, private_tx, - database: client_db, + database: blockchain_db, _stop_guard: stop_guard, }) } @@ -167,7 +168,7 @@ impl ClientService { } /// Get a handle to the database. - pub fn db(&self) -> Arc { self.database.clone() } + pub fn db(&self) -> Arc { self.database.clone() } /// Shutdown the Client Service pub fn shutdown(&self) { @@ -259,8 +260,8 @@ mod tests { use ethcore::miner::Miner; use ethcore::spec::Spec; use ethcore::db::NUM_COLUMNS; - use kvdb::Error; - use kvdb_rocksdb::{Database, DatabaseConfig, CompactionProfile}; + use ethcore::test_helpers; + use kvdb_rocksdb::{DatabaseConfig, CompactionProfile}; use super::*; use ethcore_private_tx; @@ -276,26 +277,10 @@ mod tests { client_db_config.memory_budget = client_config.db_cache_size; client_db_config.compaction = CompactionProfile::auto(&client_path); - client_db_config.wal = client_config.db_wal; - let client_db = Arc::new(Database::open( - &client_db_config, - &client_path.to_str().expect("DB path could not be converted to string.") - ).unwrap()); - - struct RestorationDBHandler { - config: DatabaseConfig, - } - - impl KeyValueDBHandler for RestorationDBHandler { - fn open(&self, db_path: &Path) -> Result, Error> { - Ok(Arc::new(Database::open(&self.config, &db_path.to_string_lossy())?)) - } - } - - let restoration_db_handler = Box::new(RestorationDBHandler { - config: client_db_config, - }); + let client_db_handler = test_helpers::restoration_db_handler(client_db_config.clone()); + let client_db = client_db_handler.open(&client_path).unwrap(); + let restoration_db_handler = test_helpers::restoration_db_handler(client_db_config); let spec = Spec::new_test(); let service = ClientService::start( diff --git a/ethcore/src/account_db.rs b/ethcore/src/account_db.rs index 4e715766d7ae66202e25feb0c0db98e46605f63a..dd05d22cbc6808a4d8b2b986e6d382db230a88e5 100644 --- a/ethcore/src/account_db.rs +++ b/ethcore/src/account_db.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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/account_provider/mod.rs b/ethcore/src/account_provider/mod.rs index 9d6b814c6f6b7a0971b18c2a1c1e5c4e5b482d30..e4289c60a5720bd0d1f47ec072e7e147cc20fd24 100644 --- a/ethcore/src/account_provider/mod.rs +++ b/ethcore/src/account_provider/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -20,28 +20,30 @@ mod stores; use self::stores::{AddressBook, DappsSettingsStore, NewDappsPolicy}; -use std::fmt; use std::collections::{HashMap, HashSet}; +use std::fmt; use std::time::{Instant, Duration}; -use parking_lot::RwLock; + +use ethstore::accounts_dir::MemoryDirectory; +use ethstore::ethkey::{Address, Message, Public, Secret, Password, Random, Generator}; +use ethjson::misc::AccountMeta; use ethstore::{ SimpleSecretStore, SecretStore, Error as SSError, EthStore, EthMultiStore, random_string, SecretVaultRef, StoreAccountRef, OpaqueSecret, }; -use ethstore::accounts_dir::MemoryDirectory; -use ethstore::ethkey::{Address, Message, Public, Secret, Random, Generator}; -use ethjson::misc::AccountMeta; -use hardware_wallet::{Error as HardwareError, HardwareWalletManager, KeyPath, TransactionInfo}; -use super::transaction::{Action, Transaction}; +use parking_lot::RwLock; + pub use ethstore::ethkey::Signature; pub use ethstore::{Derivation, IndexDerivation, KeyFile}; +pub use hardware_wallet::{Error as HardwareError, HardwareWalletManager, KeyPath, TransactionInfo}; +pub use super::transaction::{Action, Transaction}; /// Type of unlock. #[derive(Clone, PartialEq)] enum Unlock { /// If account is unlocked temporarily, it should be locked after first usage. OneTime, - /// Account unlocked permantently can always sign message. + /// Account unlocked permanently can always sign message. /// Use with caution. Perm, /// Account unlocked with a timeout @@ -52,7 +54,7 @@ enum Unlock { #[derive(Clone)] struct AccountData { unlock: Unlock, - password: String, + password: Password, } /// Signing error @@ -112,7 +114,7 @@ fn transient_sstore() -> EthMultiStore { EthMultiStore::open(Box::new(MemoryDirectory::default())).expect("MemoryDirectory load always succeeds; qed") } -type AccountToken = String; +type AccountToken = Password; /// Account management. /// Responsible for unlocking accounts. @@ -165,6 +167,7 @@ impl AccountProvider { /// Creates new account provider. pub fn new(sstore: Box, settings: AccountProviderSettings) -> Self { let mut hardware_store = None; + if settings.enable_hardware_wallets { match HardwareWalletManager::new() { Ok(manager) => { @@ -217,12 +220,12 @@ impl AccountProvider { } /// Creates new random account. - pub fn new_account(&self, password: &str) -> Result { + pub fn new_account(&self, password: &Password) -> Result { self.new_account_and_public(password).map(|d| d.0) } /// Creates new random account and returns address and public key - pub fn new_account_and_public(&self, password: &str) -> Result<(Address, Public), Error> { + pub fn new_account_and_public(&self, password: &Password) -> Result<(Address, Public), Error> { let acc = Random.generate().expect("secp context has generation capabilities; qed"); let public = acc.public().clone(); let secret = acc.secret().clone(); @@ -232,7 +235,7 @@ impl AccountProvider { /// Inserts new account into underlying store. /// Does not unlock account! - pub fn insert_account(&self, secret: Secret, password: &str) -> Result { + pub fn insert_account(&self, secret: Secret, password: &Password) -> Result { let account = self.sstore.insert_account(SecretVaultRef::Root, secret, password)?; if self.blacklisted_accounts.contains(&account.address) { self.sstore.remove_account(&account, password)?; @@ -244,7 +247,7 @@ impl AccountProvider { /// Generates new derived account based on the existing one /// If password is not provided, account must be unlocked /// New account will be created with the same password (if save: true) - pub fn derive_account(&self, address: &Address, password: Option, derivation: Derivation, save: bool) + pub fn derive_account(&self, address: &Address, password: Option, derivation: Derivation, save: bool) -> Result { let account = self.sstore.account_ref(&address)?; @@ -256,13 +259,13 @@ impl AccountProvider { } /// Import a new presale wallet. - pub fn import_presale(&self, presale_json: &[u8], password: &str) -> Result { + pub fn import_presale(&self, presale_json: &[u8], password: &Password) -> Result { let account = self.sstore.import_presale(SecretVaultRef::Root, presale_json, password)?; Ok(Address::from(account.address).into()) } /// Import a new wallet. - pub fn import_wallet(&self, json: &[u8], password: &str, gen_id: bool) -> Result { + pub fn import_wallet(&self, json: &[u8], password: &Password, gen_id: bool) -> Result { let account = self.sstore.import_wallet(SecretVaultRef::Root, json, password, gen_id)?; if self.blacklisted_accounts.contains(&account.address) { self.sstore.remove_account(&account, password)?; @@ -272,25 +275,29 @@ impl AccountProvider { } /// Checks whether an account with a given address is present. - pub fn has_account(&self, address: Address) -> Result { - Ok(self.sstore.account_ref(&address).is_ok() && !self.blacklisted_accounts.contains(&address)) + pub fn has_account(&self, address: Address) -> bool { + self.sstore.account_ref(&address).is_ok() && !self.blacklisted_accounts.contains(&address) } /// Returns addresses of all accounts. pub fn accounts(&self) -> Result, Error> { let accounts = self.sstore.accounts()?; Ok(accounts - .into_iter() - .map(|a| a.address) - .filter(|address| !self.blacklisted_accounts.contains(address)) - .collect() + .into_iter() + .map(|a| a.address) + .filter(|address| !self.blacklisted_accounts.contains(address)) + .collect() ) } /// Returns addresses of hardware accounts. pub fn hardware_accounts(&self) -> Result, Error> { - let accounts = self.hardware_store.as_ref().map_or(Vec::new(), |h| h.list_wallets()); - Ok(accounts.into_iter().map(|a| a.address).collect()) + if let Some(accounts) = self.hardware_store.as_ref().map(|h| h.list_wallets()) { + if !accounts.is_empty() { + return Ok(accounts.into_iter().map(|a| a.address).collect()); + } + } + Err(SSError::Custom("No hardware wallet accounts were found".into())) } /// Get a list of paths to locked hardware wallets @@ -301,7 +308,7 @@ impl AccountProvider { Some(Ok(s)) => Ok(s), } } - + /// Provide a pin to a locked hardware wallet on USB path to unlock it pub fn hardware_pin_matrix_ack(&self, path: &str, pin: &str) -> Result { match self.hardware_store.as_ref().map(|h| h.pin_matrix_ack(path, pin)) { @@ -495,7 +502,7 @@ impl AccountProvider { self.address_book.write().set_meta(account, meta) } - /// Removes and address from the addressbook + /// Removes and address from the address book pub fn remove_address(&self, addr: Address) { self.address_book.write().remove(addr) } @@ -543,7 +550,7 @@ impl AccountProvider { } /// Returns account public key. - pub fn account_public(&self, address: Address, password: &str) -> Result { + pub fn account_public(&self, address: Address, password: &Password) -> Result { self.sstore.public(&self.sstore.account_ref(&address)?, password) } @@ -560,32 +567,32 @@ impl AccountProvider { } /// Returns `true` if the password for `account` is `password`. `false` if not. - pub fn test_password(&self, address: &Address, password: &str) -> Result { + pub fn test_password(&self, address: &Address, password: &Password) -> Result { self.sstore.test_password(&self.sstore.account_ref(&address)?, password) .map_err(Into::into) } /// Permanently removes an account. - pub fn kill_account(&self, address: &Address, password: &str) -> Result<(), Error> { + pub fn kill_account(&self, address: &Address, password: &Password) -> Result<(), Error> { self.sstore.remove_account(&self.sstore.account_ref(&address)?, &password)?; Ok(()) } /// Changes the password of `account` from `password` to `new_password`. Fails if incorrect `password` given. - pub fn change_password(&self, address: &Address, password: String, new_password: String) -> Result<(), Error> { + pub fn change_password(&self, address: &Address, password: Password, new_password: Password) -> Result<(), Error> { self.sstore.change_password(&self.sstore.account_ref(address)?, &password, &new_password) } /// Exports an account for given address. - pub fn export_account(&self, address: &Address, password: String) -> Result { + pub fn export_account(&self, address: &Address, password: Password) -> Result { self.sstore.export_account(&self.sstore.account_ref(address)?, &password) } /// Helper method used for unlocking accounts. - fn unlock_account(&self, address: Address, password: String, unlock: Unlock) -> Result<(), Error> { + fn unlock_account(&self, address: Address, password: Password, unlock: Unlock) -> Result<(), Error> { let account = self.sstore.account_ref(&address)?; - // check if account is already unlocked pernamently, if it is, do nothing + // check if account is already unlocked permanently, if it is, do nothing let mut unlocked = self.unlocked.write(); if let Some(data) = unlocked.get(&account) { if let Unlock::Perm = data.unlock { @@ -612,7 +619,7 @@ impl AccountProvider { Ok(()) } - fn password(&self, account: &StoreAccountRef) -> Result { + fn password(&self, account: &StoreAccountRef) -> Result { let mut unlocked = self.unlocked.write(); let data = unlocked.get(account).ok_or(SignError::NotUnlocked)?.clone(); if let Unlock::OneTime = data.unlock { @@ -624,21 +631,21 @@ impl AccountProvider { return Err(SignError::NotUnlocked); } } - Ok(data.password.clone()) + Ok(data.password) } /// Unlocks account permanently. - pub fn unlock_account_permanently(&self, account: Address, password: String) -> Result<(), Error> { + pub fn unlock_account_permanently(&self, account: Address, password: Password) -> Result<(), Error> { self.unlock_account(account, password, Unlock::Perm) } /// Unlocks account temporarily (for one signing). - pub fn unlock_account_temporarily(&self, account: Address, password: String) -> Result<(), Error> { + pub fn unlock_account_temporarily(&self, account: Address, password: Password) -> Result<(), Error> { self.unlock_account(account, password, Unlock::OneTime) } /// Unlocks account temporarily with a timeout. - pub fn unlock_account_timed(&self, account: Address, password: String, duration: Duration) -> Result<(), Error> { + pub fn unlock_account_timed(&self, account: Address, password: Password, duration: Duration) -> Result<(), Error> { self.unlock_account(account, password, Unlock::Timed(Instant::now() + duration)) } @@ -660,7 +667,7 @@ impl AccountProvider { } /// Signs the message. If password is not provided the account must be unlocked. - pub fn sign(&self, address: Address, password: Option, message: Message) -> Result { + pub fn sign(&self, address: Address, password: Option, message: Message) -> Result { let account = self.sstore.account_ref(&address)?; match self.unlocked_secrets.read().get(&account) { Some(secret) => { @@ -674,7 +681,7 @@ impl AccountProvider { } /// Signs message using the derived secret. If password is not provided the account must be unlocked. - pub fn sign_derived(&self, address: &Address, password: Option, derivation: Derivation, message: Message) + pub fn sign_derived(&self, address: &Address, password: Option, derivation: Derivation, message: Message) -> Result { let account = self.sstore.account_ref(address)?; @@ -687,7 +694,7 @@ impl AccountProvider { let account = self.sstore.account_ref(&address)?; let is_std_password = self.sstore.test_password(&account, &token)?; - let new_token = random_string(16); + let new_token = Password::from(random_string(16)); let signature = if is_std_password { // Insert to transient store self.sstore.copy_account(&self.transient_sstore, SecretVaultRef::Root, &account, &token, &new_token)?; @@ -710,7 +717,7 @@ impl AccountProvider { let account = self.sstore.account_ref(&address)?; let is_std_password = self.sstore.test_password(&account, &token)?; - let new_token = random_string(16); + let new_token = Password::from(random_string(16)); let message = if is_std_password { // Insert to transient store self.sstore.copy_account(&self.transient_sstore, SecretVaultRef::Root, &account, &token, &new_token)?; @@ -727,14 +734,14 @@ impl AccountProvider { } /// Decrypts a message. If password is not provided the account must be unlocked. - pub fn decrypt(&self, address: Address, password: Option, shared_mac: &[u8], message: &[u8]) -> Result, SignError> { + pub fn decrypt(&self, address: Address, password: Option, shared_mac: &[u8], message: &[u8]) -> Result, SignError> { let account = self.sstore.account_ref(&address)?; let password = password.map(Ok).unwrap_or_else(|| self.password(&account))?; Ok(self.sstore.decrypt(&account, &password, shared_mac, message)?) } /// Agree on shared key. - pub fn agree(&self, address: Address, password: Option, other_public: &Public) -> Result { + pub fn agree(&self, address: Address, password: Option, other_public: &Public) -> Result { let account = self.sstore.account_ref(&address)?; let password = password.map(Ok).unwrap_or_else(|| self.password(&account))?; Ok(self.sstore.agree(&account, &password, other_public)?) @@ -753,13 +760,13 @@ impl AccountProvider { } /// Create new vault. - pub fn create_vault(&self, name: &str, password: &str) -> Result<(), Error> { + pub fn create_vault(&self, name: &str, password: &Password) -> Result<(), Error> { self.sstore.create_vault(name, password) .map_err(Into::into) } /// Open existing vault. - pub fn open_vault(&self, name: &str, password: &str) -> Result<(), Error> { + pub fn open_vault(&self, name: &str, password: &Password) -> Result<(), Error> { self.sstore.open_vault(name, password) .map_err(Into::into) } @@ -783,7 +790,7 @@ impl AccountProvider { } /// Change vault password. - pub fn change_vault_password(&self, name: &str, new_password: &str) -> Result<(), Error> { + pub fn change_vault_password(&self, name: &str, new_password: &Password) -> Result<(), Error> { self.sstore.change_vault_password(name, new_password) .map_err(Into::into) } @@ -809,8 +816,17 @@ impl AccountProvider { .map_err(Into::into) } + /// Sign message with hardware wallet. + pub fn sign_message_with_hardware(&self, address: &Address, message: &[u8]) -> Result { + match self.hardware_store.as_ref().map(|s| s.sign_message(address, message)) { + None | Some(Err(HardwareError::KeyNotFound)) => Err(SignError::NotFound), + Some(Err(e)) => Err(From::from(e)), + Some(Ok(s)) => Ok(s), + } + } + /// Sign transaction with hardware wallet. - pub fn sign_with_hardware(&self, address: Address, transaction: &Transaction, chain_id: Option, rlp_encoded_transaction: &[u8]) -> Result { + pub fn sign_transaction_with_hardware(&self, address: &Address, transaction: &Transaction, chain_id: Option, rlp_encoded_transaction: &[u8]) -> Result { let t_info = TransactionInfo { nonce: transaction.nonce, gas_price: transaction.gas_price, @@ -843,7 +859,7 @@ mod tests { fn unlock_account_temp() { let kp = Random.generate().unwrap(); let ap = AccountProvider::transient_provider(); - assert!(ap.insert_account(kp.secret().clone(), "test").is_ok()); + assert!(ap.insert_account(kp.secret().clone(), &"test".into()).is_ok()); assert!(ap.unlock_account_temporarily(kp.address(), "test1".into()).is_err()); assert!(ap.unlock_account_temporarily(kp.address(), "test".into()).is_ok()); assert!(ap.sign(kp.address(), None, Default::default()).is_ok()); @@ -854,7 +870,7 @@ mod tests { fn derived_account_nosave() { let kp = Random.generate().unwrap(); let ap = AccountProvider::transient_provider(); - assert!(ap.insert_account(kp.secret().clone(), "base").is_ok()); + assert!(ap.insert_account(kp.secret().clone(), &"base".into()).is_ok()); assert!(ap.unlock_account_permanently(kp.address(), "base".into()).is_ok()); let derived_addr = ap.derive_account( @@ -872,7 +888,7 @@ mod tests { fn derived_account_save() { let kp = Random.generate().unwrap(); let ap = AccountProvider::transient_provider(); - assert!(ap.insert_account(kp.secret().clone(), "base").is_ok()); + assert!(ap.insert_account(kp.secret().clone(), &"base".into()).is_ok()); assert!(ap.unlock_account_permanently(kp.address(), "base".into()).is_ok()); let derived_addr = ap.derive_account( @@ -893,7 +909,7 @@ mod tests { fn derived_account_sign() { let kp = Random.generate().unwrap(); let ap = AccountProvider::transient_provider(); - assert!(ap.insert_account(kp.secret().clone(), "base").is_ok()); + assert!(ap.insert_account(kp.secret().clone(), &"base".into()).is_ok()); assert!(ap.unlock_account_permanently(kp.address(), "base".into()).is_ok()); let derived_addr = ap.derive_account( @@ -923,7 +939,7 @@ mod tests { fn unlock_account_perm() { let kp = Random.generate().unwrap(); let ap = AccountProvider::transient_provider(); - assert!(ap.insert_account(kp.secret().clone(), "test").is_ok()); + assert!(ap.insert_account(kp.secret().clone(), &"test".into()).is_ok()); assert!(ap.unlock_account_permanently(kp.address(), "test1".into()).is_err()); assert!(ap.unlock_account_permanently(kp.address(), "test".into()).is_ok()); assert!(ap.sign(kp.address(), None, Default::default()).is_ok()); @@ -937,7 +953,7 @@ mod tests { fn unlock_account_timer() { let kp = Random.generate().unwrap(); let ap = AccountProvider::transient_provider(); - assert!(ap.insert_account(kp.secret().clone(), "test").is_ok()); + assert!(ap.insert_account(kp.secret().clone(), &"test".into()).is_ok()); assert!(ap.unlock_account_timed(kp.address(), "test1".into(), Duration::from_secs(60)).is_err()); assert!(ap.unlock_account_timed(kp.address(), "test".into(), Duration::from_secs(60)).is_ok()); assert!(ap.sign(kp.address(), None, Default::default()).is_ok()); @@ -950,7 +966,7 @@ mod tests { // given let kp = Random.generate().unwrap(); let ap = AccountProvider::transient_provider(); - assert!(ap.insert_account(kp.secret().clone(), "test").is_ok()); + assert!(ap.insert_account(kp.secret().clone(), &"test".into()).is_ok()); // when let (_signature, token) = ap.sign_with_token(kp.address(), "test".into(), Default::default()).unwrap(); @@ -1018,7 +1034,7 @@ mod tests { // default_account should be always available assert_eq!(ap.new_dapps_default_address().unwrap(), 0.into()); - let address = ap.new_account("test").unwrap(); + let address = ap.new_account(&"test".into()).unwrap(); ap.set_address_name(1.into(), "1".into()); // Default account set to first account by default @@ -1055,7 +1071,7 @@ mod tests { fn should_not_return_blacklisted_account() { // given let mut ap = AccountProvider::transient_provider(); - let acc = ap.new_account("test").unwrap(); + let acc = ap.new_account(&"test".into()).unwrap(); ap.blacklisted_accounts = vec![acc]; // then diff --git a/ethcore/src/account_provider/stores.rs b/ethcore/src/account_provider/stores.rs index 1563d21bc6716384fbd2fedb42d4276f651cc688..d7725deb7e35858a1c994a1ddbc90a0dec0cc4a5 100644 --- a/ethcore/src/account_provider/stores.rs +++ b/ethcore/src/account_provider/stores.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 4c470896773bb44b6abbff534a20439f2e2ea2a6..9fd3957fb34b3cb8b29341127ea02f6bef410aff 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,31 +14,44 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! Blockchain block. +//! Base data structure of this module is `Block`. +//! +//! Blocks can be produced by a local node or they may be received from the network. +//! +//! To create a block locally, we start with an `OpenBlock`. This block is mutable +//! and can be appended to with transactions and uncles. +//! +//! When ready, `OpenBlock` can be closed and turned into a `ClosedBlock`. A `ClosedBlock` can +//! be reopend again by a miner under certain circumstances. On block close, state commit is +//! performed. +//! +//! `LockedBlock` is a version of a `ClosedBlock` that cannot be reopened. It can be sealed +//! using an engine. +//! +//! `ExecutedBlock` is an underlaying data structure used by all structs above to store block +//! related info. 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; 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)] @@ -52,11 +65,6 @@ pub struct Block { } impl Block { - /// Returns true if the given bytes form a valid encoding of a block in RLP. - pub fn is_good(b: &[u8]) -> bool { - Rlp::new(b).as_val::().is_ok() - } - /// Get the RLP-encoding of the block with the seal. pub fn rlp_bytes(&self) -> Bytes { let mut block_rlp = RlpStream::new_list(3); @@ -86,16 +94,22 @@ impl Decodable for Block { /// An internal type for a block's common elements. #[derive(Clone)] pub struct ExecutedBlock { - header: Header, - transactions: Vec, - uncles: Vec
, - receipts: Vec, - transactions_set: HashSet, - state: State, - traces: Tracing, - last_hashes: Arc, - is_finalized: bool, - metadata: Option>, + /// Executed block header. + pub header: Header, + /// Executed transactions. + pub transactions: Vec, + /// Uncles. + pub uncles: Vec
, + /// Transaction receipts. + pub receipts: Vec, + /// Hashes of already executed transactions. + pub transactions_set: HashSet, + /// Underlaying state. + pub state: State, + /// Transaction traces. + pub traces: Tracing, + /// Hashes of last 256 blocks. + pub last_hashes: Arc, } impl ExecutedBlock { @@ -114,8 +128,6 @@ impl ExecutedBlock { Tracing::Disabled }, last_hashes: last_hashes, - is_finalized: false, - metadata: None, } } @@ -170,20 +182,14 @@ pub trait IsBlock { /// Get all information on receipts in this block. fn receipts(&self) -> &[Receipt] { &self.block().receipts } - /// Get all information concerning transaction tracing in this block. - fn traces(&self) -> &Tracing { &self.block().traces } - /// Get all uncles in this block. fn uncles(&self) -> &[Header] { &self.block().uncles } - - /// Get tracing enabled flag for this block. - fn tracing_enabled(&self) -> bool { self.block().traces.is_enabled() } } -/// Trait for a object that has a state database. +/// Trait for an object that owns an `ExecutedBlock` pub trait Drain { - /// Drop this object and return the underlying database. - fn drain(self) -> StateDB; + /// Returns `ExecutedBlock` + fn drain(self) -> ExecutedBlock; } impl IsBlock for ExecutedBlock { @@ -210,26 +216,6 @@ impl ::parity_machine::Transactions for ExecutedBlock { } } -impl ::parity_machine::Finalizable for ExecutedBlock { - fn is_finalized(&self) -> bool { - self.is_finalized - } - - fn mark_finalized(&mut self) { - self.is_finalized = true; - } -} - -impl ::parity_machine::WithMetadata for ExecutedBlock { - fn metadata(&self) -> Option<&[u8]> { - self.metadata.as_ref().map(|v| v.as_ref()) - } - - fn set_metadata(&mut self, value: Option>) { - self.metadata = value; - } -} - /// Block that is ready for transactions to be added. /// /// It's a bit like a Vec, except that whenever a transaction is pushed, we execute it and @@ -246,10 +232,7 @@ pub struct OpenBlock<'x> { #[derive(Clone)] pub struct ClosedBlock { block: ExecutedBlock, - uncle_bytes: Bytes, unclosed_state: State, - unclosed_finalization_state: bool, - unclosed_metadata: Option>, } /// Just like `ClosedBlock` except that we can't reopen it and it's faster. @@ -258,7 +241,6 @@ pub struct ClosedBlock { #[derive(Clone)] pub struct LockedBlock { block: ExecutedBlock, - uncle_bytes: Bytes, } /// A block that has a valid seal. @@ -266,7 +248,6 @@ pub struct LockedBlock { /// The block's header has valid seal arguments. The block cannot be reversed into a `ClosedBlock` or `OpenBlock`. pub struct SealedBlock { block: ExecutedBlock, - uncle_bytes: Bytes, } impl<'x> OpenBlock<'x> { @@ -385,7 +366,7 @@ impl<'x> OpenBlock<'x> { let took = start.elapsed(); let took_ms = took.as_secs() * 1000 + took.subsec_nanos() as u64 / 1000000; if took > time::Duration::from_millis(slow_tx) { - warn!("Heavy ({} ms) transaction in block {:?}: {:?}", took_ms, block.header().number(), hash); + warn!("Heavy ({} ms) transaction in block {:?}: {:?}", took_ms, self.block.header().number(), hash); } debug!(target: "tx", "Transaction {:?} took: {} ms", hash, took_ms); } @@ -410,74 +391,37 @@ impl<'x> OpenBlock<'x> { } /// Turn this into a `ClosedBlock`. - pub fn close(self) -> ClosedBlock { - let mut s = self; + pub fn close(self) -> Result { + let unclosed_state = self.block.state.clone(); + let locked = self.close_and_lock()?; - let unclosed_state = s.block.state.clone(); - let unclosed_metadata = s.block.metadata.clone(); - let unclosed_finalization_state = s.block.is_finalized; - - if let Err(e) = s.engine.on_close_block(&mut s.block) { - warn!("Encountered error on closing the block: {}", e); - } - - if let Err(e) = s.block.state.commit() { - warn!("Encountered error on state commit: {}", e); - } - s.block.header.set_transactions_root(ordered_trie_root(s.block.transactions.iter().map(|e| e.rlp_bytes()))); - let uncle_bytes = encode_list(&s.block.uncles).into_vec(); - s.block.header.set_uncles_hash(keccak(&uncle_bytes)); - s.block.header.set_state_root(s.block.state.root().clone()); - s.block.header.set_receipts_root(ordered_trie_root(s.block.receipts.iter().map(|r| r.rlp_bytes()))); - s.block.header.set_log_bloom(s.block.receipts.iter().fold(Bloom::zero(), |mut b, r| { - b.accrue_bloom(&r.log_bloom); - b - })); - s.block.header.set_gas_used(s.block.receipts.last().map_or_else(U256::zero, |r| r.gas_used)); - - ClosedBlock { - block: s.block, - uncle_bytes, + Ok(ClosedBlock { + block: locked.block, unclosed_state, - unclosed_metadata, - unclosed_finalization_state, - } + }) } /// Turn this into a `LockedBlock`. - pub fn close_and_lock(self) -> LockedBlock { + pub fn close_and_lock(self) -> Result { let mut s = self; - if let Err(e) = s.engine.on_close_block(&mut s.block) { - warn!("Encountered error on closing the block: {}", e); - } - - if let Err(e) = s.block.state.commit() { - warn!("Encountered error on state commit: {}", e); - } - - if s.block.header.transactions_root().is_zero() || s.block.header.transactions_root() == &KECCAK_NULL_RLP { - s.block.header.set_transactions_root(ordered_trie_root(s.block.transactions.iter().map(|e| e.rlp_bytes()))); - } - let uncle_bytes = encode_list(&s.block.uncles).into_vec(); - if s.block.header.uncles_hash().is_zero() || s.block.header.uncles_hash() == &KECCAK_EMPTY_LIST_RLP { - s.block.header.set_uncles_hash(keccak(&uncle_bytes)); - } - if s.block.header.receipts_root().is_zero() || s.block.header.receipts_root() == &KECCAK_NULL_RLP { - s.block.header.set_receipts_root(ordered_trie_root(s.block.receipts.iter().map(|r| r.rlp_bytes()))); - } + s.engine.on_close_block(&mut s.block)?; + s.block.state.commit()?; + s.block.header.set_transactions_root(ordered_trie_root(s.block.transactions.iter().map(|e| e.rlp_bytes()))); + let uncle_bytes = encode_list(&s.block.uncles); + s.block.header.set_uncles_hash(keccak(&uncle_bytes)); s.block.header.set_state_root(s.block.state.root().clone()); + s.block.header.set_receipts_root(ordered_trie_root(s.block.receipts.iter().map(|r| r.rlp_bytes()))); s.block.header.set_log_bloom(s.block.receipts.iter().fold(Bloom::zero(), |mut b, r| { b.accrue_bloom(&r.log_bloom); b })); s.block.header.set_gas_used(s.block.receipts.last().map_or_else(U256::zero, |r| r.gas_used)); - LockedBlock { + Ok(LockedBlock { block: s.block, - uncle_bytes, - } + }) } #[cfg(test)] @@ -489,11 +433,11 @@ impl<'x> IsBlock for OpenBlock<'x> { fn block(&self) -> &ExecutedBlock { &self.block } } -impl<'x> IsBlock for ClosedBlock { +impl IsBlock for ClosedBlock { fn block(&self) -> &ExecutedBlock { &self.block } } -impl<'x> IsBlock for LockedBlock { +impl IsBlock for LockedBlock { fn block(&self) -> &ExecutedBlock { &self.block } } @@ -505,7 +449,6 @@ impl ClosedBlock { pub fn lock(self) -> LockedBlock { LockedBlock { block: self.block, - uncle_bytes: self.uncle_bytes, } } @@ -514,8 +457,6 @@ impl ClosedBlock { // revert rewards (i.e. set state back at last transaction's state). let mut block = self.block; block.state = self.unclosed_state; - block.metadata = self.unclosed_metadata; - block.is_finalized = self.unclosed_finalization_state; OpenBlock { block: block, engine: engine, @@ -524,7 +465,6 @@ impl ClosedBlock { } impl LockedBlock { - /// Removes outcomes from receipts and updates the receipt root. /// /// This is done after the block is enacted for historical reasons. @@ -557,7 +497,9 @@ impl LockedBlock { } s.block.header.set_seal(seal); s.block.header.compute_hash(); - Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }) + Ok(SealedBlock { + block: s.block + }) } /// Provide a valid seal in order to turn this into a `SealedBlock`. @@ -567,23 +509,22 @@ impl LockedBlock { self, engine: &EthEngine, seal: Vec, - ) -> Result { + ) -> Result { let mut s = self; s.block.header.set_seal(seal); s.block.header.compute_hash(); // TODO: passing state context to avoid engines owning it? - match engine.verify_local_seal(&s.block.header) { - Err(e) => Err((e, s)), - _ => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }), - } + engine.verify_local_seal(&s.block.header)?; + Ok(SealedBlock { + block: s.block + }) } } impl Drain for LockedBlock { - /// Drop this object and return the underlieing database. - fn drain(self) -> StateDB { - self.block.state.drop().1 + fn drain(self) -> ExecutedBlock { + self.block } } @@ -593,15 +534,14 @@ impl SealedBlock { let mut block_rlp = RlpStream::new_list(3); block_rlp.append(&self.block.header); block_rlp.append_list(&self.block.transactions); - block_rlp.append_raw(&self.uncle_bytes, 1); + block_rlp.append_list(&self.block.uncles); block_rlp.out() } } impl Drain for SealedBlock { - /// Drop this object and return the underlieing database. - fn drain(self) -> StateDB { - self.block.state.drop().1 + fn drain(self) -> ExecutedBlock { + self.block } } @@ -652,7 +592,7 @@ fn enact( b.push_uncle(u)?; } - Ok(b.close_and_lock()) + b.close_and_lock() } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header @@ -667,12 +607,11 @@ pub fn enact_verified( is_epoch_begin: bool, ancestry: &mut Iterator, ) -> Result { - let view = view!(BlockView, &block.bytes); enact( block.header, block.transactions, - view.uncles(), + block.uncles, engine, tracing, db, @@ -748,7 +687,7 @@ mod tests { b.push_uncle(u.clone())?; } - Ok(b.close_and_lock()) + b.close_and_lock() } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards @@ -773,7 +712,7 @@ mod tests { let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(&*spec.engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); - let b = b.close_and_lock(); + let b = b.close_and_lock().unwrap(); let _ = b.seal(&*spec.engine, vec![]); } @@ -787,16 +726,16 @@ mod tests { let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap() - .close_and_lock().seal(engine, vec![]).unwrap(); + .close_and_lock().unwrap().seal(engine, vec![]).unwrap(); let orig_bytes = b.rlp_bytes(); - let orig_db = b.drain(); + let orig_db = b.drain().state.drop().1; let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, Default::default()).unwrap(); assert_eq!(e.rlp_bytes(), orig_bytes); - let db = e.drain(); + let db = e.drain().state.drop().1; assert_eq!(orig_db.journal_db().keys(), db.journal_db().keys()); assert!(orig_db.journal_db().keys().iter().filter(|k| orig_db.journal_db().get(k.0) != db.journal_db().get(k.0)).next() == None); } @@ -817,10 +756,10 @@ mod tests { uncle2_header.set_extra_data(b"uncle2".to_vec()); open_block.push_uncle(uncle1_header).unwrap(); open_block.push_uncle(uncle2_header).unwrap(); - let b = open_block.close_and_lock().seal(engine, vec![]).unwrap(); + let b = open_block.close_and_lock().unwrap().seal(engine, vec![]).unwrap(); let orig_bytes = b.rlp_bytes(); - let orig_db = b.drain(); + let orig_db = b.drain().state.drop().1; let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, Default::default()).unwrap(); @@ -830,7 +769,7 @@ mod tests { let uncles = view!(BlockView, &bytes).uncles(); assert_eq!(uncles[1].extra_data(), b"uncle2"); - let db = e.drain(); + let db = e.drain().state.drop().1; assert_eq!(orig_db.journal_db().keys(), db.journal_db().keys()); assert!(orig_db.journal_db().keys().iter().filter(|k| orig_db.journal_db().get(k.0) != db.journal_db().get(k.0)).next() == None); } diff --git a/ethcore/src/blockchain/best_block.rs b/ethcore/src/blockchain/best_block.rs index 017c4f86ea041144b34917a71d87f4d82c10977b..adfaf68aadd8514d9627a2474a6294645ee60993 100644 --- a/ethcore/src/blockchain/best_block.rs +++ b/ethcore/src/blockchain/best_block.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/blockchain/block_info.rs b/ethcore/src/blockchain/block_info.rs index ee8a50d09d9eee44fc4483447b581b7089de1f6a..6a48e9244730e344c78ed62ba81ffcb650ed4b49 100644 --- a/ethcore/src/blockchain/block_info.rs +++ b/ethcore/src/blockchain/block_info.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index f2621d00e1b5da25956e2eca30548a611554582c..01becd1820e5b85b6233f49eea16b7c512a85e36 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -16,41 +16,58 @@ //! Blockchain database. -use std::collections::{HashMap, HashSet, hash_map}; +use std::collections::{HashMap, HashSet}; +use std::{mem, io}; +use std::path::Path; use std::sync::Arc; -use std::mem; -use itertools::Itertools; -use bloomchain as bc; -use heapsize::HeapSizeOf; -use ethereum_types::{H256, Bloom, 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 blooms::{BloomGroup, GroupPosition}; + +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 { + /// Generic key value store. + fn key_value(&self) -> &Arc; -const LOG_BLOOMS_LEVELS: usize = 3; -const LOG_BLOOMS_ELEMENTS_PER_INDEX: usize = 16; + /// Header blooms database. + fn blooms(&self) -> &blooms_db::Database; + + /// Trace blooms database. + fn trace_blooms(&self) -> &blooms_db::Database; +} + +/// Generic database handler. This trait contains one function `open`. When called, it opens database with a +/// predefined config. +pub trait BlockChainDBHandler: Send + Sync { + /// Open the predefined key-value database. + fn open(&self, path: &Path) -> io::Result>; +} /// Interface for querying blocks by hash and by number. pub trait BlockProvider { @@ -152,7 +169,12 @@ pub trait BlockProvider { } /// Returns numbers of blocks containing given bloom. - fn blocks_with_bloom(&self, bloom: &Bloom, from_block: BlockNumber, to_block: BlockNumber) -> Vec; + fn blocks_with_bloom<'a, B, I, II>(&self, blooms: II, from_block: BlockNumber, to_block: BlockNumber) -> Vec + where + BloomRef<'a>: From, + II: IntoIterator + Copy, + I: Iterator, + Self: Sized; /// Returns logs matching given filter. fn logs(&self, blocks: Vec, matches: F, limit: Option) -> Vec @@ -166,26 +188,14 @@ enum CacheId { BlockDetails(H256), BlockHashes(BlockNumber), TransactionAddresses(H256), - BlocksBlooms(GroupPosition), BlockReceipts(H256), } -impl bc::group::BloomGroupDatabase for BlockChain { - fn blooms_at(&self, position: &bc::group::GroupPosition) -> Option { - let position = GroupPosition::from(position.clone()); - let result = self.db.read_with_cache(db::COL_EXTRA, &self.blocks_blooms, &position).map(Into::into); - self.cache_man.lock().note_used(CacheId::BlocksBlooms(position)); - result - } -} - /// Structure providing fast access to blockchain data. /// /// **Does not do input data verification.** pub struct BlockChain { // All locks must be captured in the order declared here. - blooms_config: bc::Config, - best_block: RwLock, // Stores best block of the first uninterrupted sequence of blocks. `None` if there are no gaps. // Only updated with `insert_unordered_block`. @@ -202,10 +212,9 @@ pub struct BlockChain { block_details: RwLock>, block_hashes: RwLock>, transaction_addresses: RwLock>, - blocks_blooms: RwLock>, block_receipts: RwLock>, - db: Arc, + db: Arc, cache_man: Mutex>, @@ -219,7 +228,7 @@ impl BlockProvider for BlockChain { /// Returns true if the given block is known /// (though not necessarily a part of the canon chain). fn is_known(&self, hash: &H256) -> bool { - self.db.exists_with_cache(db::COL_EXTRA, &self.block_details, hash) + self.db.key_value().exists_with_cache(db::COL_EXTRA, &self.block_details, hash) } fn first_block(&self) -> Option { @@ -260,8 +269,8 @@ impl BlockProvider for BlockChain { } // Read from DB and populate cache - let b = self.db.get(db::COL_HEADERS, hash) - .expect("Low level database error. Some issue with disk?")?; + let b = self.db.key_value().get(db::COL_HEADERS, hash) + .expect("Low level database error when fetching block header data. Some issue with disk?")?; let header = encoded::Header::new(decompress(&b, blocks_swapper()).into_vec()); let mut write = self.block_headers.write(); @@ -290,8 +299,8 @@ impl BlockProvider for BlockChain { } // Read from DB and populate cache - let b = self.db.get(db::COL_BODIES, hash) - .expect("Low level database error. Some issue with disk?")?; + let b = self.db.key_value().get(db::COL_BODIES, hash) + .expect("Low level database error when fetching block body data. Some issue with disk?")?; let body = encoded::Body::new(decompress(&b, blocks_swapper()).into_vec()); let mut write = self.block_bodies.write(); @@ -303,40 +312,41 @@ impl BlockProvider for BlockChain { /// Get the familial details concerning a block. fn block_details(&self, hash: &H256) -> Option { - let result = self.db.read_with_cache(db::COL_EXTRA, &self.block_details, hash)?; + let result = self.db.key_value().read_with_cache(db::COL_EXTRA, &self.block_details, hash)?; self.cache_man.lock().note_used(CacheId::BlockDetails(*hash)); Some(result) } /// Get the hash of given block's number. fn block_hash(&self, index: BlockNumber) -> Option { - let result = self.db.read_with_cache(db::COL_EXTRA, &self.block_hashes, &index)?; + let result = self.db.key_value().read_with_cache(db::COL_EXTRA, &self.block_hashes, &index)?; self.cache_man.lock().note_used(CacheId::BlockHashes(index)); Some(result) } /// Get the address of transaction with given hash. fn transaction_address(&self, hash: &H256) -> Option { - let result = self.db.read_with_cache(db::COL_EXTRA, &self.transaction_addresses, hash)?; + let result = self.db.key_value().read_with_cache(db::COL_EXTRA, &self.transaction_addresses, hash)?; self.cache_man.lock().note_used(CacheId::TransactionAddresses(*hash)); Some(result) } /// Get receipts of block with given hash. fn block_receipts(&self, hash: &H256) -> Option { - let result = self.db.read_with_cache(db::COL_EXTRA, &self.block_receipts, hash)?; + let result = self.db.key_value().read_with_cache(db::COL_EXTRA, &self.block_receipts, hash)?; self.cache_man.lock().note_used(CacheId::BlockReceipts(*hash)); Some(result) } /// Returns numbers of blocks containing given bloom. - fn blocks_with_bloom(&self, bloom: &Bloom, from_block: BlockNumber, to_block: BlockNumber) -> Vec { - let range = from_block as bc::Number..to_block as bc::Number; - let chain = bc::group::BloomGroupChain::new(self.blooms_config, self); - chain.with_bloom(&range, bloom) - .into_iter() - .map(|b| b as BlockNumber) - .collect() + fn blocks_with_bloom<'a, B, I, II>(&self, blooms: II, from_block: BlockNumber, to_block: BlockNumber) -> Vec + where + BloomRef<'a>: From, + II: IntoIterator + Copy, + I: Iterator { + self.db.blooms() + .filter(from_block, to_block, blooms) + .expect("Low level database error when searching blooms. Some issue with disk?") } /// Returns logs matching given filter. The order of logs returned will be the same as the order of the blocks @@ -440,9 +450,7 @@ impl<'a> Iterator for AncestryWithMetadataIter<'a> { Some(ExtendedHeader { parent_total_difficulty: details.total_difficulty - *header.difficulty(), is_finalized: details.is_finalized, - metadata: details.metadata, - - header: header, + header, }) }, _ => { @@ -498,15 +506,11 @@ impl<'a> Iterator for EpochTransitionIter<'a> { impl BlockChain { /// Create new instance of blockchain from given Genesis. - pub fn new(config: Config, genesis: &[u8], db: Arc) -> BlockChain { + pub fn new(config: Config, genesis: &[u8], db: Arc) -> BlockChain { // 400 is the average size of the key let cache_man = CacheManager::new(config.pref_cache_size, config.max_cache_size, 400); let mut bc = BlockChain { - blooms_config: bc::Config { - levels: LOG_BLOOMS_LEVELS, - elements_per_index: LOG_BLOOMS_ELEMENTS_PER_INDEX, - }, first_block: None, best_block: RwLock::new(BestBlock { // BestBlock will be overwritten anyway. @@ -520,7 +524,6 @@ impl BlockChain { block_details: RwLock::new(HashMap::new()), block_hashes: RwLock::new(HashMap::new()), transaction_addresses: RwLock::new(HashMap::new()), - blocks_blooms: RwLock::new(HashMap::new()), block_receipts: RwLock::new(HashMap::new()), db: db.clone(), cache_man: Mutex::new(cache_man), @@ -531,7 +534,9 @@ impl BlockChain { }; // load best block - let best_block_hash = match bc.db.get(db::COL_EXTRA, b"best").unwrap() { + let best_block_hash = match bc.db.key_value().get(db::COL_EXTRA, b"best") + .expect("Low-level database error when fetching 'best' block. Some issue with disk?") + { Some(best) => { H256::from_slice(&best) } @@ -548,7 +553,6 @@ impl BlockChain { parent: header.parent_hash(), children: vec![], is_finalized: false, - metadata: None, }; let mut batch = DBTransaction::new(); @@ -559,15 +563,18 @@ impl BlockChain { batch.write(db::COL_EXTRA, &header.number(), &hash); batch.put(db::COL_EXTRA, b"best", &hash); - bc.db.write(batch).expect("Low level database error. Some issue with disk?"); + bc.db.key_value().write(batch).expect("Low level database error when fetching 'best' block. Some issue with disk?"); hash } }; { // Fetch best block details - let best_block_total_difficulty = bc.block_details(&best_block_hash).unwrap().total_difficulty; - let best_block_rlp = bc.block(&best_block_hash).unwrap(); + let best_block_total_difficulty = bc.block_details(&best_block_hash) + .expect("Best block is from a known block hash; a known block hash always comes with a known block detail; qed") + .total_difficulty; + let best_block_rlp = bc.block(&best_block_hash) + .expect("Best block is from a known block hash; qed"); // and write them let mut best_block = bc.best_block.write(); @@ -581,8 +588,12 @@ impl BlockChain { { let best_block_number = bc.best_block.read().header.number(); // Fetch first and best ancient block details - let raw_first = bc.db.get(db::COL_EXTRA, b"first").unwrap().map(|v| v.into_vec()); - let mut best_ancient = bc.db.get(db::COL_EXTRA, b"ancient").unwrap().map(|h| H256::from_slice(&h)); + let raw_first = bc.db.key_value().get(db::COL_EXTRA, b"first") + .expect("Low level database error when fetching 'first' block. Some issue with disk?") + .map(|v| v.into_vec()); + let mut best_ancient = bc.db.key_value().get(db::COL_EXTRA, b"ancient") + .expect("Low level database error when fetching 'best ancient' block. Some issue with disk?") + .map(|h| H256::from_slice(&h)); let best_ancient_number; if best_ancient.is_none() && best_block_number > 1 && bc.block_hash(1).is_none() { best_ancient = Some(bc.genesis_hash()); @@ -611,9 +622,9 @@ impl BlockChain { if hash != bc.genesis_hash() { trace!("First block calculated: {:?}", hash); - let mut batch = db.transaction(); + let mut batch = db.key_value().transaction(); batch.put(db::COL_EXTRA, b"first", &hash); - db.write(batch).expect("Low level database error."); + db.key_value().write(batch).expect("Low level database error when writing 'first' block. Some issue with disk?"); bc.first_block = Some(hash); } }, @@ -638,7 +649,7 @@ impl BlockChain { /// Returns true if the given parent block has given child /// (though not necessarily a part of the canon chain). fn is_known_child(&self, parent: &H256, hash: &H256) -> bool { - self.db.read_with_cache(db::COL_EXTRA, &self.block_details, parent).map_or(false, |d| d.children.contains(hash)) + self.db.key_value().read_with_cache(db::COL_EXTRA, &self.block_details, parent).map_or(false, |d| d.children.contains(hash)) } /// Returns a tree route between `from` and `to`, which is a tuple of: @@ -745,10 +756,11 @@ impl BlockChain { /// `parent_td` is a parent total diffuculty /// Supply a dummy parent total difficulty when the parent block may not be in the chain. /// Returns true if the block is disconnected. - pub fn insert_unordered_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec, parent_td: Option, is_best: bool, is_ancient: bool) -> bool { - let block = view!(BlockView, bytes); - let header = block.header_view(); - let hash = header.hash(); + pub fn insert_unordered_block(&self, batch: &mut DBTransaction, block: encoded::Block, receipts: Vec, parent_td: Option, is_best: bool, is_ancient: bool) -> bool { + let block_number = block.header_view().number(); + let block_parent_hash = block.header_view().parent_hash(); + let block_difficulty = block.header_view().difficulty(); + let hash = block.header_view().hash(); if self.is_known(&hash) { return false; @@ -756,45 +768,45 @@ impl BlockChain { assert!(self.pending_best_block.read().is_none()); - let compressed_header = compress(block.header_rlp().as_raw(), blocks_swapper()); - let compressed_body = compress(&Self::block_to_body(bytes), blocks_swapper()); + let compressed_header = compress(block.header_view().rlp().as_raw(), blocks_swapper()); + let compressed_body = compress(&Self::block_to_body(block.raw()), blocks_swapper()); // store block in db batch.put(db::COL_HEADERS, &hash, &compressed_header); batch.put(db::COL_BODIES, &hash, &compressed_body); - let maybe_parent = self.block_details(&header.parent_hash()); + let maybe_parent = self.block_details(&block_parent_hash); if let Some(parent_details) = maybe_parent { // parent known to be in chain. let info = BlockInfo { hash: hash, - number: header.number(), - total_difficulty: parent_details.total_difficulty + header.difficulty(), + number: block_number, + total_difficulty: parent_details.total_difficulty + block_difficulty, location: BlockLocation::CanonChain, }; self.prepare_update(batch, ExtrasUpdate { - block_hashes: self.prepare_block_hashes_update(bytes, &info), - block_details: self.prepare_block_details_update(bytes, &info, false, None), + block_hashes: self.prepare_block_hashes_update(&info), + block_details: self.prepare_block_details_update(block_parent_hash, &info, false), block_receipts: self.prepare_block_receipts_update(receipts, &info), - blocks_blooms: self.prepare_block_blooms_update(bytes, &info), - transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info), + blocks_blooms: self.prepare_block_blooms_update(block.header_view().log_bloom(), &info), + transactions_addresses: self.prepare_transaction_addresses_update(block.view().transaction_hashes(), &info), info: info, - block: bytes + block, }, is_best); if is_ancient { let mut best_ancient_block = self.best_ancient_block.write(); let ancient_number = best_ancient_block.as_ref().map_or(0, |b| b.number); - if self.block_hash(header.number() + 1).is_some() { + if self.block_hash(block_number + 1).is_some() { batch.delete(db::COL_EXTRA, b"ancient"); *best_ancient_block = None; - } else if header.number() > ancient_number { + } else if block_number > ancient_number { batch.put(db::COL_EXTRA, b"ancient", &hash); *best_ancient_block = Some(BestAncientBlock { hash: hash, - number: header.number(), + number: block_number, }); } } @@ -807,32 +819,31 @@ impl BlockChain { let info = BlockInfo { hash: hash, - number: header.number(), - total_difficulty: d + header.difficulty(), + number: block_number, + total_difficulty: d + block_difficulty, location: BlockLocation::CanonChain, }; // TODO [sorpaas] support warp sync insertion of finalization and metadata. let block_details = BlockDetails { - number: header.number(), + number: block_number, total_difficulty: info.total_difficulty, - parent: header.parent_hash(), + parent: block_parent_hash, children: Vec::new(), is_finalized: false, - metadata: None, }; let mut update = HashMap::new(); update.insert(hash, block_details); self.prepare_update(batch, ExtrasUpdate { - block_hashes: self.prepare_block_hashes_update(bytes, &info), + block_hashes: self.prepare_block_hashes_update(&info), block_details: update, block_receipts: self.prepare_block_receipts_update(receipts, &info), - blocks_blooms: self.prepare_block_blooms_update(bytes, &info), - transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info), + blocks_blooms: self.prepare_block_blooms_update(block.header_view().log_bloom(), &info), + transactions_addresses: self.prepare_transaction_addresses_update(block.view().transaction_hashes(), &info), info: info, - block: bytes, + block, }, is_best); true } @@ -843,7 +854,7 @@ impl BlockChain { /// /// The block the transition occurred at should have already been inserted into the chain. pub fn insert_epoch_transition(&self, batch: &mut DBTransaction, epoch_num: u64, transition: EpochTransition) { - let mut transitions = match self.db.read(db::COL_EXTRA, &epoch_num) { + let mut transitions = match self.db.key_value().read(db::COL_EXTRA, &epoch_num) { Some(existing) => existing, None => EpochTransitions { number: epoch_num, @@ -861,7 +872,7 @@ impl BlockChain { /// Iterate over all epoch transitions. /// This will only return transitions within the canonical chain. pub fn epoch_transitions(&self) -> EpochTransitionIter { - let iter = self.db.iter_from_prefix(db::COL_EXTRA, &EPOCH_KEY_PREFIX[..]); + let iter = self.db.key_value().iter_from_prefix(db::COL_EXTRA, &EPOCH_KEY_PREFIX[..]); EpochTransitionIter { chain: self, prefix_iter: iter, @@ -873,7 +884,7 @@ impl BlockChain { trace!(target: "blockchain", "Loading epoch transition at block {}, {}", block_num, block_hash); - self.db.read(db::COL_EXTRA, &block_num).and_then(|transitions: EpochTransitions| { + self.db.key_value().read(db::COL_EXTRA, &block_num).and_then(|transitions: EpochTransitions| { transitions.candidates.into_iter().find(|c| c.block_hash == block_hash) }) } @@ -919,7 +930,7 @@ impl BlockChain { // TODO: implement removal safely: this can only be done upon finality of a block // that _uses_ the pending transition. pub fn get_pending_transition(&self, hash: H256) -> Option { - self.db.read(db::COL_EXTRA, &hash) + self.db.key_value().read(db::COL_EXTRA, &hash) } /// Add a child to a given block. Assumes that the block hash is in @@ -944,41 +955,36 @@ impl BlockChain { /// Inserts the block into backing cache database. /// Expects the block to be valid and already verified. /// If the block is already known, does nothing. - pub fn insert_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec, extras: ExtrasInsert) -> ImportRoute { - let block = view!(BlockView, bytes); - let header = block.header_view(); - - let parent_hash = header.parent_hash(); + pub fn insert_block(&self, batch: &mut DBTransaction, block: encoded::Block, receipts: Vec, extras: ExtrasInsert) -> ImportRoute { + let parent_hash = block.header_view().parent_hash(); let best_hash = self.best_block_hash(); let route = self.tree_route(best_hash, parent_hash).expect("forks are only kept when it has common ancestors; tree route from best to prospective's parent always exists; qed"); - self.insert_block_with_route(batch, bytes, receipts, route, extras) + self.insert_block_with_route(batch, block, receipts, route, extras) } /// Inserts the block into backing cache database with already generated route information. /// Expects the block to be valid and already verified and route is tree route information from current best block to new block's parent. /// If the block is already known, does nothing. - pub fn insert_block_with_route(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec, route: TreeRoute, extras: ExtrasInsert) -> ImportRoute { - // create views onto rlp - let block = view!(BlockView, bytes); - let header = block.header_view(); - let hash = header.hash(); + pub fn insert_block_with_route(&self, batch: &mut DBTransaction, block: encoded::Block, receipts: Vec, route: TreeRoute, extras: ExtrasInsert) -> ImportRoute { + let hash = block.header_view().hash(); + let parent_hash = block.header_view().parent_hash(); - if self.is_known_child(&header.parent_hash(), &hash) { + if self.is_known_child(&parent_hash, &hash) { return ImportRoute::none(); } assert!(self.pending_best_block.read().is_none()); - let compressed_header = compress(block.header_rlp().as_raw(), blocks_swapper()); - let compressed_body = compress(&Self::block_to_body(bytes), blocks_swapper()); + let compressed_header = compress(block.header_view().rlp().as_raw(), blocks_swapper()); + let compressed_body = compress(&Self::block_to_body(block.raw()), blocks_swapper()); // store block in db batch.put(db::COL_HEADERS, &hash, &compressed_header); batch.put(db::COL_BODIES, &hash, &compressed_body); - let info = self.block_info(&header, route, &extras); + let info = self.block_info(&block.header_view(), route, &extras); if let BlockLocation::BranchBecomingCanonChain(ref d) = info.location { info!(target: "reorg", "Reorg to {} ({} {} {})", @@ -990,13 +996,13 @@ impl BlockChain { } self.prepare_update(batch, ExtrasUpdate { - block_hashes: self.prepare_block_hashes_update(bytes, &info), - block_details: self.prepare_block_details_update(bytes, &info, extras.is_finalized, extras.metadata), + block_hashes: self.prepare_block_hashes_update(&info), + block_details: self.prepare_block_details_update(parent_hash, &info, extras.is_finalized), block_receipts: self.prepare_block_receipts_update(receipts, &info), - blocks_blooms: self.prepare_block_blooms_update(bytes, &info), - transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info), + blocks_blooms: self.prepare_block_blooms_update(block.header_view().log_bloom(), &info), + transactions_addresses: self.prepare_transaction_addresses_update(block.view().transaction_hashes(), &info), info: info.clone(), - block: bytes, + block, }, true); ImportRoute::from(info) @@ -1064,35 +1070,10 @@ impl BlockChain { batch.extend_with_cache(db::COL_EXTRA, &mut *write_receipts, update.block_receipts, CacheUpdatePolicy::Remove); } - { - let mut write_blocks_blooms = self.blocks_blooms.write(); - // update best block - match update.info.location { - BlockLocation::Branch => (), - BlockLocation::BranchBecomingCanonChain(_) => { - // clear all existing blooms, cause they may be created for block - // number higher than current best block - *write_blocks_blooms = update.blocks_blooms; - for (key, value) in write_blocks_blooms.iter() { - batch.write(db::COL_EXTRA, key, value); - } - }, - BlockLocation::CanonChain => { - // update all existing blooms groups - for (key, value) in update.blocks_blooms { - match write_blocks_blooms.entry(key) { - hash_map::Entry::Occupied(mut entry) => { - entry.get_mut().accrue_bloom_group(&value); - batch.write(db::COL_EXTRA, entry.key(), entry.get()); - }, - hash_map::Entry::Vacant(entry) => { - batch.write(db::COL_EXTRA, entry.key(), &value); - entry.insert(value); - }, - } - } - }, - } + if let Some((block, blooms)) = update.blocks_blooms { + self.db.blooms() + .insert_blooms(block, blooms.iter()) + .expect("Low level database error when updating blooms. Some issue with disk?"); } // These cached values must be updated last with all four locks taken to avoid @@ -1101,11 +1082,10 @@ impl BlockChain { let mut best_block = self.pending_best_block.write(); if is_best && update.info.location != BlockLocation::Branch { batch.put(db::COL_EXTRA, b"best", &update.info.hash); - let block = encoded::Block::new(update.block.to_vec()); *best_block = Some(BestBlock { total_difficulty: update.info.total_difficulty, - header: block.decode_header(), - block, + header: update.block.decode_header(), + block: update.block, }); } @@ -1225,16 +1205,13 @@ impl BlockChain { } /// This function returns modified block hashes. - fn prepare_block_hashes_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { + fn prepare_block_hashes_update(&self, info: &BlockInfo) -> HashMap { let mut block_hashes = HashMap::new(); - let block = view!(BlockView, block_bytes); - let header = block.header_view(); - let number = header.number(); match info.location { BlockLocation::Branch => (), BlockLocation::CanonChain => { - block_hashes.insert(number, info.hash); + block_hashes.insert(info.number, info.hash); }, BlockLocation::BranchBecomingCanonChain(ref data) => { let ancestor_number = self.block_number(&data.ancestor).expect("Block number of ancestor is always in DB"); @@ -1244,7 +1221,7 @@ impl BlockChain { block_hashes.insert(start_number + index as BlockNumber, hash); } - block_hashes.insert(number, info.hash); + block_hashes.insert(info.number, info.hash); } } @@ -1253,23 +1230,18 @@ impl BlockChain { /// This function returns modified block details. /// Uses the given parent details or attempts to load them from the database. - fn prepare_block_details_update(&self, block_bytes: &[u8], info: &BlockInfo, is_finalized: bool, metadata: Option>) -> HashMap { - let block = view!(BlockView, block_bytes); - let header = block.header_view(); - let parent_hash = header.parent_hash(); - + fn prepare_block_details_update(&self, parent_hash: H256, info: &BlockInfo, is_finalized: bool) -> HashMap { // update parent let mut parent_details = self.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); parent_details.children.push(info.hash); // create current block details. let details = BlockDetails { - number: header.number(), + number: info.number, total_difficulty: info.total_difficulty, parent: parent_hash, children: vec![], is_finalized: is_finalized, - metadata: metadata, }; // write to batch @@ -1287,10 +1259,7 @@ impl BlockChain { } /// This function returns modified transaction addresses. - fn prepare_transaction_addresses_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap> { - let block = view!(BlockView, block_bytes); - let transaction_hashes = block.transaction_hashes(); - + fn prepare_transaction_addresses_update(&self, transaction_hashes: Vec, info: &BlockInfo) -> HashMap> { match info.location { BlockLocation::CanonChain => { transaction_hashes.into_iter() @@ -1355,41 +1324,31 @@ impl BlockChain { /// Later, BloomIndexer is used to map bloom location on filter layer (BloomIndex) /// to bloom location in database (BlocksBloomLocation). /// - fn prepare_block_blooms_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { - let block = view!(BlockView, block_bytes); - let header = block.header_view(); - - let log_blooms = match info.location { - BlockLocation::Branch => HashMap::new(), + fn prepare_block_blooms_update(&self, log_bloom: Bloom, info: &BlockInfo) -> Option<(u64, Vec)> { + match info.location { + BlockLocation::Branch => None, BlockLocation::CanonChain => { - let log_bloom = header.log_bloom(); if log_bloom.is_zero() { - HashMap::new() + None } else { - let chain = bc::group::BloomGroupChain::new(self.blooms_config, self); - chain.insert(info.number as bc::Number, log_bloom) + Some((info.number, vec![log_bloom])) } }, BlockLocation::BranchBecomingCanonChain(ref data) => { - let ancestor_number = self.block_number(&data.ancestor).unwrap(); + let ancestor_number = self.block_number(&data.ancestor) + .expect("hash belongs to an ancestor of an inserted block; this branch is only reachable for normal block insertion (non-ancient); ancestors of an inserted block are always available for normal block insertion; block number of an inserted block is always available; qed"); let start_number = ancestor_number + 1; - let range = start_number as bc::Number..self.best_block_number() as bc::Number; let mut blooms: Vec = data.enacted.iter() - .map(|hash| self.block_header_data(hash).unwrap()) + .map(|hash| self.block_header_data(hash) + .expect("hash belongs to an inserted block; block header data of an inserted block is always available; qed")) .map(|h| h.log_bloom()) .collect(); - blooms.push(header.log_bloom()); - - let chain = bc::group::BloomGroupChain::new(self.blooms_config, self); - chain.replace(&range, blooms) + blooms.push(log_bloom); + Some((start_number, blooms)) } - }; - - log_blooms.into_iter() - .map(|p| (From::from(p.0), From::from(p.1))) - .collect() + } } /// Get best block hash. @@ -1423,7 +1382,6 @@ impl BlockChain { blocks: self.block_headers.read().heap_size_of_children() + self.block_bodies.read().heap_size_of_children(), block_details: self.block_details.read().heap_size_of_children(), transaction_addresses: self.transaction_addresses.read().heap_size_of_children(), - blocks_blooms: self.blocks_blooms.read().heap_size_of_children(), block_receipts: self.block_receipts.read().heap_size_of_children(), } } @@ -1437,7 +1395,6 @@ impl BlockChain { let mut block_details = self.block_details.write(); let mut block_hashes = self.block_hashes.write(); let mut transaction_addresses = self.transaction_addresses.write(); - let mut blocks_blooms = self.blocks_blooms.write(); let mut block_receipts = self.block_receipts.write(); let mut cache_man = self.cache_man.lock(); @@ -1449,7 +1406,6 @@ impl BlockChain { CacheId::BlockDetails(ref h) => { block_details.remove(h); } CacheId::BlockHashes(ref h) => { block_hashes.remove(h); } CacheId::TransactionAddresses(ref h) => { transaction_addresses.remove(h); } - CacheId::BlocksBlooms(ref h) => { blocks_blooms.remove(h); } CacheId::BlockReceipts(ref h) => { block_receipts.remove(h); } } } @@ -1459,7 +1415,6 @@ impl BlockChain { block_details.shrink_to_fit(); block_hashes.shrink_to_fit(); transaction_addresses.shrink_to_fit(); - blocks_blooms.shrink_to_fit(); block_receipts.shrink_to_fit(); block_headers.heap_size_of_children() + @@ -1467,7 +1422,6 @@ impl BlockChain { block_details.heap_size_of_children() + block_hashes.heap_size_of_children() + transaction_addresses.heap_size_of_children() + - blocks_blooms.heap_size_of_children() + block_receipts.heap_size_of_children() }); } @@ -1483,18 +1437,24 @@ impl BlockChain { /// Returns general blockchain information pub fn chain_info(&self) -> BlockChainInfo { + // Make sure to call internal methods first to avoid + // recursive locking of `best_block`. + let first_block_hash = self.first_block(); + let first_block_number = self.first_block_number().into(); + let genesis_hash = self.genesis_hash(); + // ensure data consistencly by locking everything first let best_block = self.best_block.read(); let best_ancient_block = self.best_ancient_block.read(); BlockChainInfo { total_difficulty: best_block.total_difficulty, pending_total_difficulty: best_block.total_difficulty, - genesis_hash: self.genesis_hash(), + genesis_hash, best_block_hash: best_block.header.hash(), best_block_number: best_block.header.number(), best_block_timestamp: best_block.header.timestamp(), - first_block_hash: self.first_block(), - first_block_number: From::from(self.first_block_number()), + first_block_hash, + first_block_number, ancient_block_hash: best_ancient_block.as_ref().map(|b| b.hash), ancient_block_number: best_ancient_block.as_ref().map(|b| b.number), } @@ -1507,11 +1467,10 @@ mod tests { use std::sync::Arc; use rustc_hex::FromHex; use hash::keccak; - use kvdb::{KeyValueDB, DBTransaction}; - use kvdb_memorydb; + use kvdb::DBTransaction; use ethereum_types::*; use receipt::{Receipt, TransactionOutcome}; - use blockchain::{BlockProvider, BlockChain, Config, ImportRoute}; + use blockchain::{BlockProvider, BlockChain, BlockChainDB, Config, ImportRoute}; use test_helpers::{ generate_dummy_blockchain, generate_dummy_blockchain_with_extra, generate_dummy_empty_blockchain @@ -1521,48 +1480,45 @@ mod tests { use transaction::{Transaction, Action}; use log_entry::{LogEntry, LocalizedLogEntry}; use ethkey::Secret; + use test_helpers::new_db; + use encoded; - fn new_db() -> Arc { - Arc::new(kvdb_memorydb::create(::db::NUM_COLUMNS.unwrap_or(0))) - } - - fn new_chain(genesis: &[u8], db: Arc) -> BlockChain { - BlockChain::new(Config::default(), genesis, db) + fn new_chain(genesis: encoded::Block, db: Arc) -> BlockChain { + BlockChain::new(Config::default(), genesis.raw(), db) } - fn insert_block(db: &Arc, bc: &BlockChain, bytes: &[u8], receipts: Vec) -> ImportRoute { - insert_block_commit(db, bc, bytes, receipts, true) + fn insert_block(db: &Arc, bc: &BlockChain, block: encoded::Block, receipts: Vec) -> ImportRoute { + insert_block_commit(db, bc, block, receipts, true) } - fn insert_block_commit(db: &Arc, bc: &BlockChain, bytes: &[u8], receipts: Vec, commit: bool) -> ImportRoute { - let mut batch = db.transaction(); - let res = insert_block_batch(&mut batch, bc, bytes, receipts); - db.write(batch).unwrap(); + fn insert_block_commit(db: &Arc, bc: &BlockChain, block: encoded::Block, receipts: Vec, commit: bool) -> ImportRoute { + let mut batch = db.key_value().transaction(); + let res = insert_block_batch(&mut batch, bc, block, receipts); + db.key_value().write(batch).unwrap(); if commit { bc.commit(); } res } - fn insert_block_batch(batch: &mut DBTransaction, bc: &BlockChain, bytes: &[u8], receipts: Vec) -> ImportRoute { - use views::BlockView; + fn insert_block_batch(batch: &mut DBTransaction, bc: &BlockChain, block: encoded::Block, receipts: Vec) -> ImportRoute { use blockchain::ExtrasInsert; - let block = view!(BlockView, bytes); - let header = block.header_view(); - let parent_hash = header.parent_hash(); - let parent_details = bc.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); - let block_total_difficulty = parent_details.total_difficulty + header.difficulty(); - let fork_choice = if block_total_difficulty > bc.best_block_total_difficulty() { - ::engines::ForkChoice::New - } else { - ::engines::ForkChoice::Old + let fork_choice = { + let header = block.header_view(); + let parent_hash = header.parent_hash(); + let parent_details = bc.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); + let block_total_difficulty = parent_details.total_difficulty + header.difficulty(); + if block_total_difficulty > bc.best_block_total_difficulty() { + ::engines::ForkChoice::New + } else { + ::engines::ForkChoice::Old + } }; - bc.insert_block(batch, bytes, receipts, ExtrasInsert { + bc.insert_block(batch, block, receipts, ExtrasInsert { fork_choice: fork_choice, is_finalized: false, - metadata: None }) } @@ -1573,11 +1529,11 @@ mod tests { let first = genesis.add_block(); let db = new_db(); - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); assert_eq!(bc.best_block_number(), 0); // when - insert_block_commit(&db, &bc, &first.last().encoded(), vec![], false); + insert_block_commit(&db, &bc, first.last().encoded(), vec![], false); assert_eq!(bc.best_block_number(), 0); bc.commit(); // NOTE no db.write here (we want to check if best block is cached) @@ -1598,7 +1554,7 @@ mod tests { let first_hash = first.hash(); let db = new_db(); - let bc = new_chain(&genesis.encoded(), db.clone()); + let bc = new_chain(genesis.encoded(), db.clone()); assert_eq!(bc.genesis_hash(), genesis_hash); assert_eq!(bc.best_block_hash(), genesis_hash); @@ -1606,9 +1562,9 @@ mod tests { assert_eq!(bc.block_hash(1), None); assert_eq!(bc.block_details(&genesis_hash).unwrap().children, vec![]); - let mut batch = db.transaction(); - insert_block_batch(&mut batch, &bc, &first.encoded(), vec![]); - db.write(batch).unwrap(); + let mut batch = db.key_value().transaction(); + insert_block_batch(&mut batch, &bc, first.encoded(), vec![]); + db.key_value().write(batch).unwrap(); bc.commit(); assert_eq!(bc.block_hash(0), Some(genesis_hash)); @@ -1627,16 +1583,16 @@ mod tests { let generator = BlockGenerator::new(vec![first_10]); let db = new_db(); - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); let mut block_hashes = vec![genesis.last().hash()]; - let mut batch = db.transaction(); + let mut batch = db.key_value().transaction(); for block in generator { block_hashes.push(block.hash()); - insert_block_batch(&mut batch, &bc, &block.encoded(), vec![]); + insert_block_batch(&mut batch, &bc, block.encoded(), vec![]); bc.commit(); } - db.write(batch).unwrap(); + db.key_value().write(batch).unwrap(); block_hashes.reverse(); @@ -1671,10 +1627,10 @@ mod tests { ); let db = new_db(); - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); for b in generator { - insert_block(&db, &bc, &b.encoded(), vec![]); + insert_block(&db, &bc, b.encoded(), vec![]); } assert_eq!(uncle_headers, bc.find_uncle_headers(&b4a_hash, 3).unwrap()); @@ -1707,14 +1663,14 @@ mod tests { let b2_hash = b2.last().hash(); let db = new_db(); - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); - let mut batch = db.transaction(); - let _ = insert_block_batch(&mut batch, &bc, &b1a.last().encoded(), vec![]); + let mut batch = db.key_value().transaction(); + let _ = insert_block_batch(&mut batch, &bc, b1a.last().encoded(), vec![]); bc.commit(); - let _ = insert_block_batch(&mut batch, &bc, &b1b.last().encoded(), vec![]); + let _ = insert_block_batch(&mut batch, &bc, b1b.last().encoded(), vec![]); bc.commit(); - db.write(batch).unwrap(); + db.key_value().write(batch).unwrap(); assert_eq!(bc.best_block_hash(), b1a_hash); assert_eq!(bc.transaction_address(&t1_hash), Some(TransactionAddress { @@ -1723,10 +1679,10 @@ mod tests { })); // now let's make forked chain the canon chain - let mut batch = db.transaction(); - let _ = insert_block_batch(&mut batch, &bc, &b2.last().encoded(), vec![]); + let mut batch = db.key_value().transaction(); + let _ = insert_block_batch(&mut batch, &bc, b2.last().encoded(), vec![]); bc.commit(); - db.write(batch).unwrap(); + db.key_value().write(batch).unwrap(); // Transaction should be retracted assert_eq!(bc.best_block_hash(), b2_hash); @@ -1782,14 +1738,14 @@ mod tests { let t3_hash = t3.hash(); let db = new_db(); - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); - let mut batch = db.transaction(); - let _ = insert_block_batch(&mut batch, &bc, &b1a.last().encoded(), vec![]); + let mut batch = db.key_value().transaction(); + let _ = insert_block_batch(&mut batch, &bc, b1a.last().encoded(), vec![]); bc.commit(); - let _ = insert_block_batch(&mut batch, &bc, &b1b.last().encoded(), vec![]); + let _ = insert_block_batch(&mut batch, &bc, b1b.last().encoded(), vec![]); bc.commit(); - db.write(batch).unwrap(); + db.key_value().write(batch).unwrap(); assert_eq!(bc.best_block_hash(), b1a_hash); assert_eq!(bc.transaction_address(&t1_hash), Some(TransactionAddress { @@ -1802,10 +1758,10 @@ mod tests { })); // now let's make forked chain the canon chain - let mut batch = db.transaction(); - let _ = insert_block_batch(&mut batch, &bc, &b2.last().encoded(), vec![]); + let mut batch = db.key_value().transaction(); + let _ = insert_block_batch(&mut batch, &bc, b2.last().encoded(), vec![]); bc.commit(); - db.write(batch).unwrap(); + db.key_value().write(batch).unwrap(); assert_eq!(bc.best_block_hash(), b2_hash); assert_eq!(bc.transaction_address(&t1_hash), Some(TransactionAddress { @@ -1840,21 +1796,21 @@ mod tests { let best_block_hash = b3a_hash; let db = new_db(); - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); - let mut batch = db.transaction(); - let ir1 = insert_block_batch(&mut batch, &bc, &b1.last().encoded(), vec![]); + let mut batch = db.key_value().transaction(); + let ir1 = insert_block_batch(&mut batch, &bc, b1.last().encoded(), vec![]); bc.commit(); - let ir2 = insert_block_batch(&mut batch, &bc, &b2.last().encoded(), vec![]); + let ir2 = insert_block_batch(&mut batch, &bc, b2.last().encoded(), vec![]); bc.commit(); - let ir3b = insert_block_batch(&mut batch, &bc, &b3b.last().encoded(), vec![]); + let ir3b = insert_block_batch(&mut batch, &bc, b3b.last().encoded(), vec![]); bc.commit(); - db.write(batch).unwrap(); + db.key_value().write(batch).unwrap(); assert_eq!(bc.block_hash(3).unwrap(), b3b_hash); - let mut batch = db.transaction(); - let ir3a = insert_block_batch(&mut batch, &bc, &b3a.last().encoded(), vec![]); + let mut batch = db.key_value().transaction(); + let ir3a = insert_block_batch(&mut batch, &bc, b3a.last().encoded(), vec![]); bc.commit(); - db.write(batch).unwrap(); + db.key_value().write(batch).unwrap(); assert_eq!(ir1, ImportRoute { enacted: vec![b1_hash], @@ -1954,17 +1910,17 @@ mod tests { let db = new_db(); { - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); assert_eq!(bc.best_block_hash(), genesis_hash); - let mut batch = db.transaction(); - insert_block_batch(&mut batch, &bc, &first.last().encoded(), vec![]); - db.write(batch).unwrap(); + let mut batch = db.key_value().transaction(); + insert_block_batch(&mut batch, &bc, first.last().encoded(), vec![]); + db.key_value().write(batch).unwrap(); bc.commit(); assert_eq!(bc.best_block_hash(), first_hash); } { - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); assert_eq!(bc.best_block_hash(), first_hash); } @@ -2014,10 +1970,10 @@ mod tests { let b1_hash: H256 = "f53f268d23a71e85c7d6d83a9504298712b84c1a2ba220441c86eeda0bf0b6e3".into(); let db = new_db(); - let bc = new_chain(&genesis, db.clone()); - let mut batch =db.transaction(); - insert_block_batch(&mut batch, &bc, &b1, vec![]); - db.write(batch).unwrap(); + let bc = new_chain(encoded::Block::new(genesis), db.clone()); + let mut batch = db.key_value().transaction(); + insert_block_batch(&mut batch, &bc, encoded::Block::new(b1), vec![]); + db.key_value().write(batch).unwrap(); bc.commit(); let transactions = bc.transactions(&b1_hash).unwrap(); @@ -2082,8 +2038,8 @@ mod tests { let b3_number = b3.last().number(); let db = new_db(); - let bc = new_chain(&genesis.last().encoded(), db.clone()); - insert_block(&db, &bc, &b1.last().encoded(), vec![Receipt { + let bc = new_chain(genesis.last().encoded(), db.clone()); + insert_block(&db, &bc, b1.last().encoded(), vec![Receipt { outcome: TransactionOutcome::StateRoot(H256::default()), gas_used: 10_000.into(), log_bloom: Default::default(), @@ -2100,7 +2056,7 @@ mod tests { LogEntry { address: Default::default(), topics: vec![], data: vec![3], }, ], }]); - insert_block(&db, &bc, &b2.last().encoded(), vec![ + insert_block(&db, &bc, b2.last().encoded(), vec![ Receipt { outcome: TransactionOutcome::StateRoot(H256::default()), gas_used: 10_000.into(), @@ -2110,7 +2066,7 @@ mod tests { ], } ]); - insert_block(&db, &bc, &b3.last().encoded(), vec![ + insert_block(&db, &bc, b3.last().encoded(), vec![ Receipt { outcome: TransactionOutcome::StateRoot(H256::default()), gas_used: 10_000.into(), @@ -2210,48 +2166,48 @@ mod tests { let b2a = b1a.add_block_with_bloom(bloom_ba); let db = new_db(); - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); - let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); - let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); + let blocks_b1 = bc.blocks_with_bloom(Some(&bloom_b1), 0, 5); + let blocks_b2 = bc.blocks_with_bloom(Some(&bloom_b2), 0, 5); assert!(blocks_b1.is_empty()); assert!(blocks_b2.is_empty()); - insert_block(&db, &bc, &b1.last().encoded(), vec![]); - let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); - let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); + insert_block(&db, &bc, b1.last().encoded(), vec![]); + let blocks_b1 = bc.blocks_with_bloom(Some(&bloom_b1), 0, 5); + let blocks_b2 = bc.blocks_with_bloom(Some(&bloom_b2), 0, 5); assert_eq!(blocks_b1, vec![1]); assert!(blocks_b2.is_empty()); - insert_block(&db, &bc, &b2.last().encoded(), vec![]); - let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); - let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); + insert_block(&db, &bc, b2.last().encoded(), vec![]); + let blocks_b1 = bc.blocks_with_bloom(Some(&bloom_b1), 0, 5); + let blocks_b2 = bc.blocks_with_bloom(Some(&bloom_b2), 0, 5); assert_eq!(blocks_b1, vec![1]); assert_eq!(blocks_b2, vec![2]); // hasn't been forked yet - insert_block(&db, &bc, &b1a.last().encoded(), vec![]); - let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); - let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); - let blocks_ba = bc.blocks_with_bloom(&bloom_ba, 0, 5); + insert_block(&db, &bc, b1a.last().encoded(), vec![]); + let blocks_b1 = bc.blocks_with_bloom(Some(&bloom_b1), 0, 5); + let blocks_b2 = bc.blocks_with_bloom(Some(&bloom_b2), 0, 5); + let blocks_ba = bc.blocks_with_bloom(Some(&bloom_ba), 0, 5); assert_eq!(blocks_b1, vec![1]); assert_eq!(blocks_b2, vec![2]); assert!(blocks_ba.is_empty()); // fork has happend - insert_block(&db, &bc, &b2a.last().encoded(), vec![]); - let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); - let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); - let blocks_ba = bc.blocks_with_bloom(&bloom_ba, 0, 5); + insert_block(&db, &bc, b2a.last().encoded(), vec![]); + let blocks_b1 = bc.blocks_with_bloom(Some(&bloom_b1), 0, 5); + let blocks_b2 = bc.blocks_with_bloom(Some(&bloom_b2), 0, 5); + let blocks_ba = bc.blocks_with_bloom(Some(&bloom_ba), 0, 5); assert!(blocks_b1.is_empty()); assert!(blocks_b2.is_empty()); assert_eq!(blocks_ba, vec![1, 2]); // fork back - insert_block(&db, &bc, &b3.last().encoded(), vec![]); - let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); - let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); - let blocks_ba = bc.blocks_with_bloom(&bloom_ba, 0, 5); + insert_block(&db, &bc, b3.last().encoded(), vec![]); + let blocks_b1 = bc.blocks_with_bloom(Some(&bloom_b1), 0, 5); + let blocks_b2 = bc.blocks_with_bloom(Some(&bloom_b2), 0, 5); + let blocks_ba = bc.blocks_with_bloom(Some(&bloom_ba), 0, 5); assert_eq!(blocks_b1, vec![1]); assert_eq!(blocks_b2, vec![2]); assert_eq!(blocks_ba, vec![3]); @@ -2272,24 +2228,24 @@ mod tests { let b1_total_difficulty = genesis.last().difficulty() + b1.last().difficulty(); let db = new_db(); - let bc = new_chain(&genesis.last().encoded(), db.clone()); - let mut batch = db.transaction(); - bc.insert_unordered_block(&mut batch, &b2.last().encoded(), vec![], Some(b1_total_difficulty), false, false); + let bc = new_chain(genesis.last().encoded(), db.clone()); + let mut batch = db.key_value().transaction(); + bc.insert_unordered_block(&mut batch, b2.last().encoded(), vec![], Some(b1_total_difficulty), false, false); bc.commit(); - bc.insert_unordered_block(&mut batch, &b3.last().encoded(), vec![], None, true, false); + bc.insert_unordered_block(&mut batch, b3.last().encoded(), vec![], None, true, false); bc.commit(); - bc.insert_unordered_block(&mut batch, &b1.last().encoded(), vec![], None, false, false); + bc.insert_unordered_block(&mut batch, b1.last().encoded(), vec![], None, false, false); bc.commit(); - db.write(batch).unwrap(); + db.key_value().write(batch).unwrap(); assert_eq!(bc.best_block_hash(), b3.last().hash()); assert_eq!(bc.block_hash(1).unwrap(), b1.last().hash()); assert_eq!(bc.block_hash(2).unwrap(), b2.last().hash()); assert_eq!(bc.block_hash(3).unwrap(), b3.last().hash()); - let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 3); - let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 3); - let blocks_b3 = bc.blocks_with_bloom(&bloom_b3, 0, 3); + let blocks_b1 = bc.blocks_with_bloom(Some(&bloom_b1), 0, 3); + let blocks_b2 = bc.blocks_with_bloom(Some(&bloom_b2), 0, 3); + let blocks_b3 = bc.blocks_with_bloom(Some(&bloom_b3), 0, 3); assert_eq!(blocks_b1, vec![1]); assert_eq!(blocks_b2, vec![2]); @@ -2305,23 +2261,23 @@ mod tests { let db = new_db(); { - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); - let mut batch = db.transaction(); + let mut batch = db.key_value().transaction(); // create a longer fork for block in generator { - insert_block_batch(&mut batch, &bc, &block.encoded(), vec![]); + insert_block_batch(&mut batch, &bc, block.encoded(), vec![]); bc.commit(); } assert_eq!(bc.best_block_number(), 5); - insert_block_batch(&mut batch, &bc, &uncle.last().encoded(), vec![]); - db.write(batch).unwrap(); + insert_block_batch(&mut batch, &bc, uncle.last().encoded(), vec![]); + db.key_value().write(batch).unwrap(); bc.commit(); } // re-loading the blockchain should load the correct best block. - let bc = new_chain(&genesis.last().encoded(), db); + let bc = new_chain(genesis.last().encoded(), db); assert_eq!(bc.best_block_number(), 5); } @@ -2336,13 +2292,13 @@ mod tests { let db = new_db(); { - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); - let mut batch = db.transaction(); + let mut batch = db.key_value().transaction(); // create a longer fork for (i, block) in generator.into_iter().enumerate() { - insert_block_batch(&mut batch, &bc, &block.encoded(), vec![]); + insert_block_batch(&mut batch, &bc, block.encoded(), vec![]); bc.insert_epoch_transition(&mut batch, i as u64, EpochTransition { block_hash: block.hash(), block_number: i as u64 + 1, @@ -2353,14 +2309,14 @@ mod tests { assert_eq!(bc.best_block_number(), 5); - insert_block_batch(&mut batch, &bc, &uncle.last().encoded(), vec![]); + insert_block_batch(&mut batch, &bc, uncle.last().encoded(), vec![]); bc.insert_epoch_transition(&mut batch, 999, EpochTransition { block_hash: uncle.last().hash(), block_number: 1, proof: vec![], }); - db.write(batch).unwrap(); + db.key_value().write(batch).unwrap(); bc.commit(); // epoch 999 not in canonical chain. @@ -2368,7 +2324,7 @@ mod tests { } // re-loading the blockchain should load the correct best block. - let bc = new_chain(&genesis.last().encoded(), db); + let bc = new_chain(genesis.last().encoded(), db); assert_eq!(bc.best_block_number(), 5); assert_eq!(bc.epoch_transitions().map(|(i, _)| i).collect::>(), vec![0, 1, 2, 3, 4]); @@ -2389,21 +2345,21 @@ mod tests { let db = new_db(); - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); - let mut batch = db.transaction(); + let mut batch = db.key_value().transaction(); bc.insert_epoch_transition(&mut batch, 0, EpochTransition { block_hash: bc.genesis_hash(), block_number: 0, proof: vec![], }); - db.write(batch).unwrap(); + db.key_value().write(batch).unwrap(); // set up a chain where we have a canonical chain of 10 blocks // and a non-canonical fork of 8 from genesis. let fork_hash = { for block in fork_generator { - insert_block(&db, &bc, &block.encoded(), vec![]); + insert_block(&db, &bc, block.encoded(), vec![]); } assert_eq!(bc.best_block_number(), 7); @@ -2411,18 +2367,18 @@ mod tests { }; for block in next_generator { - insert_block(&db, &bc, &block.encoded(), vec![]); + insert_block(&db, &bc, block.encoded(), vec![]); } assert_eq!(bc.best_block_number(), 10); - let mut batch = db.transaction(); + let mut batch = db.key_value().transaction(); bc.insert_epoch_transition(&mut batch, 4, EpochTransition { block_hash: bc.block_hash(4).unwrap(), block_number: 4, proof: vec![], }); - db.write(batch).unwrap(); + db.key_value().write(batch).unwrap(); // blocks where the parent is one of the first 4 will be part of genesis epoch. for i in 0..4 { diff --git a/ethcore/src/blockchain/cache.rs b/ethcore/src/blockchain/cache.rs index 999be423df7945a13270e9378558c45c994e8308..a924f2ad084b6ad03af020aed10308c92868b340 100644 --- a/ethcore/src/blockchain/cache.rs +++ b/ethcore/src/blockchain/cache.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -23,8 +23,6 @@ pub struct CacheSize { pub block_details: usize, /// Transaction addresses cache size. pub transaction_addresses: usize, - /// Blooms cache size. - pub blocks_blooms: usize, /// Block receipts size. pub block_receipts: usize, } @@ -32,6 +30,6 @@ pub struct CacheSize { impl CacheSize { /// Total amount used by the cache. pub fn total(&self) -> usize { - self.blocks + self.block_details + self.transaction_addresses + self.blocks_blooms + self.block_receipts + self.blocks + self.block_details + self.transaction_addresses + self.block_receipts } } diff --git a/ethcore/src/blockchain/config.rs b/ethcore/src/blockchain/config.rs index 312289b060abdaf5b5ee738cd3a489b43283269a..632f978ac53c09f08544b12ba9914972fdc9a25e 100644 --- a/ethcore/src/blockchain/config.rs +++ b/ethcore/src/blockchain/config.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/blockchain/extras.rs b/ethcore/src/blockchain/extras.rs index 3fb25e7b1b1c7c7d54422ac73a82644910487c8d..1dd51b7c7539755898c77875af9bbb89c211ad0d 100644 --- a/ethcore/src/blockchain/extras.rs +++ b/ethcore/src/blockchain/extras.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -16,18 +16,17 @@ //! Blockchain DB extras. -use std::ops; use std::io::Write; -use blooms::{GroupPosition, BloomGroup}; +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)] @@ -38,8 +37,6 @@ pub enum ExtrasIndex { BlockHash = 1, /// Transaction address index TransactionAddress = 2, - /// Block blooms index - BlocksBlooms = 3, /// Block receipts index BlockReceipts = 4, /// Epoch transition data index. @@ -87,31 +84,6 @@ impl Key for H256 { } } -pub struct LogGroupKey([u8; 6]); - -impl ops::Deref for LogGroupKey { - type Target = [u8]; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Key for GroupPosition { - type Target = LogGroupKey; - - fn key(&self) -> Self::Target { - let mut result = [0u8; 6]; - result[0] = ExtrasIndex::BlocksBlooms as u8; - result[1] = self.level; - result[2] = (self.index >> 24) as u8; - result[3] = (self.index >> 16) as u8; - result[4] = (self.index >> 8) as u8; - result[5] = self.index as u8; - LogGroupKey(result) - } -} - impl Key for H256 { type Target = H264; @@ -180,17 +152,15 @@ pub struct BlockDetails { pub children: Vec, /// Whether the block is considered finalized pub is_finalized: bool, - /// Additional block metadata - pub metadata: Option>, } impl rlp::Encodable for BlockDetails { fn rlp_append(&self, stream: &mut rlp::RlpStream) { - let use_short_version = self.metadata.is_none() && !self.is_finalized; + let use_short_version = !self.is_finalized; match use_short_version { true => { stream.begin_list(4); }, - false => { stream.begin_list(6); }, + false => { stream.begin_list(5); }, } stream.append(&self.number); @@ -199,7 +169,6 @@ impl rlp::Encodable for BlockDetails { stream.append_list(&self.children); if !use_short_version { stream.append(&self.is_finalized); - stream.append(&self.metadata); } } } @@ -208,7 +177,7 @@ impl rlp::Decodable for BlockDetails { fn decode(rlp: &rlp::Rlp) -> Result { let use_short_version = match rlp.item_count()? { 4 => true, - 6 => false, + 5 => false, _ => return Err(rlp::DecoderError::RlpIncorrectListLen), }; @@ -222,11 +191,6 @@ impl rlp::Decodable for BlockDetails { } else { rlp.val_at(4)? }, - metadata: if use_short_version { - None - } else { - rlp.val_at(5)? - }, }) } } @@ -280,6 +244,7 @@ pub struct EpochTransitions { #[cfg(test)] mod tests { use rlp::*; + use super::BlockReceipts; #[test] diff --git a/ethcore/src/blockchain/generator.rs b/ethcore/src/blockchain/generator.rs index e767f2211c32c872a4f49e4272525476e19b0d08..44d4e038c5c41e4657685b3b29df7187b9a31e09 100644 --- a/ethcore/src/blockchain/generator.rs +++ b/ethcore/src/blockchain/generator.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -19,11 +19,11 @@ use std::collections::VecDeque; use ethereum_types::{U256, H256, Bloom}; -use bytes::Bytes; use header::Header; use rlp::encode; use transaction::SignedTransaction; use views::BlockView; +use encoded; /// Helper structure, used for encoding blocks. #[derive(Default, Clone, RlpEncodable)] @@ -41,7 +41,7 @@ impl Block { #[inline] pub fn hash(&self) -> H256 { - view!(BlockView, &self.encoded()).header_view().hash() + view!(BlockView, &self.encoded().raw()).header_view().hash() } #[inline] @@ -50,8 +50,8 @@ impl Block { } #[inline] - pub fn encoded(&self) -> Bytes { - encode(self).into_vec() + pub fn encoded(&self) -> encoded::Block { + encoded::Block::new(encode(self).into_vec()) } #[inline] diff --git a/ethcore/src/blockchain/import_route.rs b/ethcore/src/blockchain/import_route.rs index 080d3b068247cda60507382b05de8a8bb6b7c88b..d8b38e6335ed7a728916cfd50f0a12f58865e5f0 100644 --- a/ethcore/src/blockchain/import_route.rs +++ b/ethcore/src/blockchain/import_route.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/blockchain/mod.rs b/ethcore/src/blockchain/mod.rs index f991692dedfceca5271a9ce2b22b497bb028407a..3a4504051e348a09bf5f0ddce834268f2edc63ab 100644 --- a/ethcore/src/blockchain/mod.rs +++ b/ethcore/src/blockchain/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -28,7 +28,7 @@ mod update; #[cfg(test)] pub mod generator; -pub use self::blockchain::{BlockProvider, BlockChain}; +pub use self::blockchain::{BlockProvider, BlockChain, BlockChainDB, BlockChainDBHandler}; pub use self::cache::CacheSize; pub use self::config::Config; pub use self::extras::{BlockReceipts, BlockDetails, TransactionAddress}; diff --git a/ethcore/src/blockchain/update.rs b/ethcore/src/blockchain/update.rs index b695b9236b0610ff599ab0a14280f93d6292c804..897abb59bc34d41a689311f4d057786e1cea3d1e 100644 --- a/ethcore/src/blockchain/update.rs +++ b/ethcore/src/blockchain/update.rs @@ -1,16 +1,32 @@ +// 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 . + use std::collections::HashMap; -use ethereum_types::H256; +use ethereum_types::{H256, Bloom}; use header::BlockNumber; use blockchain::block_info::BlockInfo; use blockchain::extras::{BlockDetails, BlockReceipts, TransactionAddress}; -use blooms::{BloomGroup, GroupPosition}; +use encoded::Block; /// Block extras update info. -pub struct ExtrasUpdate<'a> { +pub struct ExtrasUpdate { /// Block info. pub info: BlockInfo, /// Current block uncompressed rlp bytes - pub block: &'a [u8], + pub block: Block, /// Modified block hashes. pub block_hashes: HashMap, /// Modified block details. @@ -18,7 +34,7 @@ pub struct ExtrasUpdate<'a> { /// Modified block receipts. pub block_receipts: HashMap, /// Modified blocks blooms. - pub blocks_blooms: HashMap, + pub blocks_blooms: Option<(u64, Vec)>, /// Modified transaction addresses (None signifies removed transactions). pub transactions_addresses: HashMap>, } @@ -29,6 +45,4 @@ pub struct ExtrasInsert { pub fork_choice: ::engines::ForkChoice, /// Is the inserted block considered finalized. pub is_finalized: bool, - /// New block local metadata. - pub metadata: Option>, } diff --git a/ethcore/src/blooms/bloom_group.rs b/ethcore/src/blooms/bloom_group.rs deleted file mode 100644 index 4b47b1ad9473b9ff55068d34d4720c7e854e668d..0000000000000000000000000000000000000000 --- a/ethcore/src/blooms/bloom_group.rs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2015-2017 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 . - -use bloomchain::group as bc; -use heapsize::HeapSizeOf; -use ethereum_types::Bloom; - -/// Represents group of X consecutive blooms. -#[derive(Debug, Clone, RlpEncodableWrapper, RlpDecodableWrapper)] -pub struct BloomGroup { - blooms: Vec, -} - -impl BloomGroup { - pub fn accrue_bloom_group(&mut self, group: &BloomGroup) { - for (bloom, other) in self.blooms.iter_mut().zip(group.blooms.iter()) { - bloom.accrue_bloom(other); - } - } -} - -impl From for BloomGroup { - fn from(group: bc::BloomGroup) -> Self { - BloomGroup { - blooms: group.blooms - } - } -} - -impl Into for BloomGroup { - fn into(self) -> bc::BloomGroup { - bc::BloomGroup { - blooms: self.blooms - } - } -} - -impl HeapSizeOf for BloomGroup { - fn heap_size_of_children(&self) -> usize { - self.blooms.heap_size_of_children() - } -} diff --git a/ethcore/src/blooms/group_position.rs b/ethcore/src/blooms/group_position.rs deleted file mode 100644 index b1ea82792618d500052285929ad1fde41f12d647..0000000000000000000000000000000000000000 --- a/ethcore/src/blooms/group_position.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2015-2017 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 . - -use bloomchain::group as bc; -use heapsize::HeapSizeOf; - -/// Represents `BloomGroup` position in database. -#[derive(PartialEq, Eq, Hash, Clone, Debug)] -pub struct GroupPosition { - /// Bloom level. - pub level: u8, - /// Group index. - pub index: u32, -} - -impl From for GroupPosition { - fn from(p: bc::GroupPosition) -> Self { - GroupPosition { - level: p.level as u8, - index: p.index as u32, - } - } -} - -impl HeapSizeOf for GroupPosition { - fn heap_size_of_children(&self) -> usize { - 0 - } -} diff --git a/ethcore/src/blooms/mod.rs b/ethcore/src/blooms/mod.rs deleted file mode 100644 index a66485782b31f3373062ad636f307a737395ed30..0000000000000000000000000000000000000000 --- a/ethcore/src/blooms/mod.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Bridge between bloomchain crate types and ethcore. - -mod bloom_group; -mod group_position; - -pub use self::bloom_group::BloomGroup; -pub use self::group_position::GroupPosition; diff --git a/ethcore/src/builtin.rs b/ethcore/src/builtin.rs index a0833cfb5e64c198fe3d26f743f55a462fb0c41f..ab02fbbcf0cf2789c933cafea4d0a9eea590a13f 100644 --- a/ethcore/src/builtin.rs +++ b/ethcore/src/builtin.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,11 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Standard built-in contracts. + use std::cmp::{max, min}; use std::io::{self, Read}; use byteorder::{ByteOrder, BigEndian}; -use ethcore_crypto::digest; +use parity_crypto::digest; use num::{BigUint, Zero, One}; use hash::keccak; @@ -27,6 +29,7 @@ use bytes::BytesRef; use ethkey::{Signature, recover as ec_recover}; use ethjson; +/// Execution error. #[derive(Debug)] pub struct Error(pub &'static str); @@ -207,8 +210,8 @@ impl From for Builtin { } } -// Ethereum builtin creator. -fn ethereum_builtin(name: &str) -> Box { +/// Ethereum built-in factory. +pub fn ethereum_builtin(name: &str) -> Box { match name { "identity" => Box::new(Identity) as Box, "ecrecover" => Box::new(EcRecover) as Box, @@ -703,7 +706,6 @@ mod tests { assert_eq!(f.cost(&input[..]), expected_cost.into()); } - // test for potential exp len overflow { let input = FromHex::from_hex("\ @@ -827,7 +829,6 @@ mod tests { assert_eq!(output, expected); } - // no input, should not fail { let mut empty = [0u8; 0]; @@ -859,7 +860,6 @@ mod tests { } } - #[test] fn bn128_mul() { diff --git a/ethcore/src/cache_manager.rs b/ethcore/src/cache_manager.rs index 7d91dcc0d005c6a2b3ed5d445940f6e35bb40a65..07a9750a0eee1bc3fecad0a987daa187a63d950b 100644 --- a/ethcore/src/cache_manager.rs +++ b/ethcore/src/cache_manager.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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/ancient_import.rs b/ethcore/src/client/ancient_import.rs index c2523a13a56030bbca924b392157023f45e1b6a9..4586a04eed2b4849f824d10616de13827050b34b 100644 --- a/ethcore/src/client/ancient_import.rs +++ b/ethcore/src/client/ancient_import.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/client/chain_notify.rs b/ethcore/src/client/chain_notify.rs index 8330fb40d9edd490cab99d21e97d03976784c576..62de03591dfb88c9b53d5ffaeaf3b8dc265bdf04 100644 --- a/ethcore/src/client/chain_notify.rs +++ b/ethcore/src/client/chain_notify.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index b469cf45180993985cd0bfb220c0212d04200f76..3a7fd0d0c7460d22c07b198b8b7aff35df63e251 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,10 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::collections::{HashSet, BTreeMap, BTreeSet, VecDeque}; +use std::collections::{HashSet, BTreeMap, VecDeque}; +use std::cmp; use std::fmt; use std::str::FromStr; -use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; +use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; use std::sync::{Arc, Weak}; use std::time::{Instant, Duration}; @@ -28,14 +29,12 @@ 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}; use block::{IsBlock, LockedBlock, Drain, ClosedBlock, OpenBlock, enact_verified, SealedBlock}; -use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute, TransactionAddress, ExtrasInsert}; +use blockchain::{BlockChain, BlockChainDB, BlockProvider, TreeRoute, ImportRoute, TransactionAddress, ExtrasInsert}; use client::ancient_import::AncientVerifier; -use client::Error as ClientError; use client::{ Nonce, Balance, ChainInfo, BlockInfo, CallContract, TransactionInfo, RegistryInfo, ReopenBlock, PrepareOpenBlock, ScheduleInfo, ImportSealedBlock, @@ -72,24 +71,23 @@ use trace; use trace::{TraceDB, ImportRequest as TraceImportRequest, LocalizedTrace, Database as TraceDatabase}; use transaction::{self, LocalizedTransaction, UnverifiedTransaction, SignedTransaction, Transaction, Action}; use types::filter::Filter; -use types::mode::Mode as IpcMode; use types::ancestry_action::AncestryAction; use verification; -use verification::{PreverifiedBlock, Verifier}; -use verification::queue::BlockQueue; -use views::BlockView; -use parity_machine::{Finalizable, WithMetadata}; +use verification::{PreverifiedBlock, Verifier, BlockQueue}; +use verification::queue::kind::blocks::Unverified; +use verification::queue::kind::BlockLike; // re-export pub use types::blockchain_info::BlockChainInfo; pub use types::block_status::BlockStatus; pub use blockchain::CacheSize as BlockChainCacheSize; -pub use verification::queue::QueueInfo as BlockQueueInfo; +pub use verification::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; const MAX_QUEUE_SIZE_TO_SLEEP_ON: usize = 2; const MIN_HISTORY_SIZE: u64 = 8; @@ -190,7 +188,7 @@ pub struct Client { pruning: journaldb::Algorithm, /// Client uses this to store blocks, traces, etc. - db: RwLock>, + db: RwLock>, state_db: RwLock, @@ -201,7 +199,7 @@ pub struct Client { /// Flag changed by `sleep` and `wake_up` methods. Not to be confused with `enabled`. liveness: AtomicBool, - io_channel: Mutex>, + io_channel: RwLock>, /// List of actors to be notified on certain chain events notify: RwLock>>, @@ -210,8 +208,12 @@ pub struct Client { queue_transactions: IoChannelQueue, /// Ancient blocks import queue queue_ancient_blocks: IoChannelQueue, - /// Hashes of pending ancient block wainting to be included - pending_ancient_blocks: RwLock>, + /// Queued ancient blocks, make sure they are imported in order. + queued_ancient_blocks: Arc, + VecDeque<(Unverified, Bytes)> + )>>, + ancient_blocks_import_lock: Arc>, /// Consensus messages import queue queue_consensus_message: IoChannelQueue, @@ -287,7 +289,7 @@ impl Importer { continue; } - if let Ok(closed_block) = self.check_and_close_block(block, client) { + if let Ok(closed_block) = self.check_and_lock_block(block, client) { if self.engine.is_proposal(&header) { self.block_queue.mark_as_good(&[hash]); proposed_blocks.push(bytes); @@ -296,7 +298,7 @@ impl Importer { let transactions_len = closed_block.transactions().len(); - let route = self.commit_block(closed_block, &header, &bytes, client); + let route = self.commit_block(closed_block, &header, encoded::Block::new(bytes), client); import_results.push(route); client.report.write().accrue_block(&header, transactions_len); @@ -337,11 +339,12 @@ impl Importer { } } - client.db.read().flush().expect("DB flush failed."); + let db = client.db.read(); + db.key_value().flush().expect("DB flush failed."); imported } - fn check_and_close_block(&self, block: PreverifiedBlock, client: &Client) -> Result { + fn check_and_lock_block(&self, block: PreverifiedBlock, client: &Client) -> Result { let engine = &*self.engine; let header = block.header.clone(); @@ -368,8 +371,7 @@ impl Importer { &parent, engine, Some(verification::FullFamilyParams { - block_bytes: &block.bytes, - transactions: &block.transactions, + block: &block, block_provider: &**chain, client }), @@ -425,64 +427,57 @@ impl Importer { Ok(locked_block) } - /// Import a block with transaction receipts. /// /// The block is guaranteed to be the next best blocks in the /// first block sequence. Does no sealing or transaction validation. - fn import_old_block(&self, header: &Header, block_bytes: &[u8], receipts_bytes: &[u8], db: &KeyValueDB, chain: &BlockChain) -> Result { + fn import_old_block(&self, unverified: Unverified, receipts_bytes: &[u8], db: &KeyValueDB, chain: &BlockChain) -> Result<(), ::error::Error> { let receipts = ::rlp::decode_list(receipts_bytes); - let hash = header.hash(); let _import_lock = self.import_lock.lock(); - trace!(target: "client", "Trying to import old block #{}", header.number()); { 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)?; - self.ancient_verifier.verify(&mut rng, &header, &chain)?; + let mut rng = OsRng::new()?; + self.ancient_verifier.verify(&mut rng, &unverified.header, &chain)?; // Commit results let mut batch = DBTransaction::new(); - chain.insert_unordered_block(&mut batch, block_bytes, receipts, None, false, true); + chain.insert_unordered_block(&mut batch, encoded::Block::new(unverified.bytes), receipts, None, false, true); // Final commit to the DB db.write_buffered(batch); chain.commit(); } db.flush().expect("DB flush failed."); - Ok(hash) + Ok(()) } // NOTE: the header of the block passed here is not necessarily sealed, as // it is for reconstructing the state transition. // // The header passed is from the original block data and is sealed. - fn commit_block(&self, block: B, header: &Header, block_data: &[u8], client: &Client) -> ImportRoute where B: IsBlock + Drain { + fn commit_block(&self, block: B, header: &Header, block_data: encoded::Block, client: &Client) -> ImportRoute where B: Drain { let hash = &header.hash(); let number = header.number(); let parent = header.parent_hash(); let chain = client.chain.read(); + let is_finalized = false; // Commit results - let receipts = block.receipts().to_owned(); - let traces = block.traces().clone().drain(); - - assert_eq!(header.hash(), view!(BlockView, block_data).header_view().hash()); - - //let traces = From::from(block.traces().clone().unwrap_or_else(Vec::new)); + let block = block.drain(); + debug_assert_eq!(header.hash(), block_data.header_view().hash()); let mut batch = DBTransaction::new(); - let ancestry_actions = self.engine.ancestry_actions(block.block(), &mut chain.ancestry_with_metadata_iter(*parent)); + let ancestry_actions = self.engine.ancestry_actions(&block, &mut chain.ancestry_with_metadata_iter(*parent)); + let receipts = block.receipts; + let traces = block.traces.drain(); let best_hash = chain.best_block_hash(); - let metadata = block.block().metadata().map(Into::into); - let is_finalized = block.block().is_finalized(); let new = ExtendedHeader { header: header.clone(), - is_finalized: is_finalized, - metadata: metadata, + is_finalized, parent_total_difficulty: chain.block_details(&parent).expect("Parent block is in the database; qed").total_difficulty }; @@ -498,8 +493,6 @@ impl Importer { ExtendedHeader { parent_total_difficulty: details.total_difficulty - *header.difficulty(), is_finalized: details.is_finalized, - metadata: details.metadata, - header: header, } }; @@ -514,13 +507,13 @@ impl Importer { // CHECK! I *think* this is fine, even if the state_root is equal to another // already-imported block of the same number. // TODO: Prove it with a test. - let mut state = block.drain(); + let mut state = block.state.drop().1; // check epoch end signal, potentially generating a proof on the current // state. self.check_epoch_end_signal( &header, - block_data, + block_data.raw(), &receipts, &state, &chain, @@ -537,8 +530,7 @@ impl Importer { let route = chain.insert_block(&mut batch, block_data, receipts.clone(), ExtrasInsert { fork_choice: fork_choice, - is_finalized: is_finalized, - metadata: new.metadata, + is_finalized, }); client.tracedb.read().import(&mut batch, TraceImportRequest { @@ -552,7 +544,7 @@ impl Importer { let is_canon = route.enacted.last().map_or(false, |h| h == hash); state.sync_cache(&route.enacted, &route.retracted, is_canon); // Final commit to the DB - client.db.read().write_buffered(batch); + client.db.read().key_value().write_buffered(batch); chain.commit(); self.check_epoch_end(&header, &chain, client); @@ -619,7 +611,9 @@ impl Importer { ).expect("state known to be available for just-imported block; qed"); let options = TransactOptions::with_no_tracing().dont_check_nonce(); - let res = Executive::new(&mut state, &env_info, self.engine.machine()) + let machine = self.engine.machine(); + let schedule = machine.schedule(env_info.number); + let res = Executive::new(&mut state, &env_info, &machine, &schedule) .transact(&transaction, options); let res = match res { @@ -680,7 +674,7 @@ impl Importer { // always write the batch directly since epoch transition proofs are // fetched from a DB iterator and DB iterators are only available on // flushed data. - client.db.read().write(batch).expect("DB flush failed"); + client.db.read().key_value().write(batch).expect("DB flush failed"); } } } @@ -691,7 +685,7 @@ impl Client { pub fn new( config: ClientConfig, spec: &Spec, - db: Arc, + db: Arc, miner: Arc, message_channel: IoChannel, ) -> Result, ::error::Error> { @@ -707,14 +701,14 @@ impl Client { accountdb: Default::default(), }; - let journal_db = journaldb::new(db.clone(), config.pruning, ::db::COL_STATE); + let journal_db = journaldb::new(db.key_value().clone(), config.pruning, ::db::COL_STATE); let mut state_db = StateDB::new(journal_db, config.state_cache_size); if state_db.journal_db().is_empty() { // Sets the correct state root. state_db = spec.ensure_db_good(state_db, &factories)?; let mut batch = DBTransaction::new(); state_db.journal_under(&mut batch, 0, &spec.genesis_header().hash())?; - db.write(batch).map_err(ClientError::Database)?; + db.key_value().write(batch)?; } let gb = spec.genesis_block(); @@ -756,15 +750,15 @@ impl Client { tracedb: tracedb, engine: engine, pruning: config.pruning.clone(), - config: config, - db: RwLock::new(db), + db: RwLock::new(db.clone()), state_db: RwLock::new(state_db), report: RwLock::new(Default::default()), - io_channel: Mutex::new(message_channel), + io_channel: RwLock::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), - pending_ancient_blocks: RwLock::new(HashSet::new()), + queued_ancient_blocks: Default::default(), + ancient_blocks_import_lock: Default::default(), queue_consensus_message: IoChannelQueue::new(usize::max_value()), last_hashes: RwLock::new(VecDeque::new()), factories: factories, @@ -774,6 +768,7 @@ impl Client { registrar_address, exit_handler: Mutex::new(None), importer, + config, }); // prune old states. @@ -811,12 +806,12 @@ impl Client { proof: proof, }); - client.db.read().write_buffered(batch); + client.db.read().key_value().write_buffered(batch); } } // ensure buffered changes are flushed. - client.db.read().flush().map_err(ClientError::Database)?; + client.db.read().key_value().flush()?; Ok(client) } @@ -918,7 +913,6 @@ impl Client { Arc::new(last_hashes) } - /// This is triggered by a message coming from a block queue when the block is ready for insertion pub fn import_verified_blocks(&self) -> usize { self.importer.import_verified_blocks(self) @@ -941,7 +935,7 @@ impl Client { } // prune ancient states until below the memory limit or only the minimum amount remain. - fn prune_ancient(&self, mut state_db: StateDB, chain: &BlockChain) -> Result<(), ClientError> { + fn prune_ancient(&self, mut state_db: StateDB, chain: &BlockChain) -> Result<(), ::error::Error> { let number = match state_db.journal_db().latest_era() { Some(n) => n, None => return Ok(()), @@ -961,7 +955,7 @@ impl Client { Some(ancient_hash) => { let mut batch = DBTransaction::new(); state_db.mark_canonical(&mut batch, era, &ancient_hash)?; - self.db.read().write_buffered(batch); + self.db.read().key_value().write_buffered(batch); state_db.journal_db().flush(); } None => @@ -993,7 +987,7 @@ impl Client { /// Replace io channel. Useful for testing. pub fn set_io_channel(&self, io_channel: IoChannel) { - *self.io_channel.lock() = io_channel; + *self.io_channel.write() = io_channel; } /// Get a copy of the best block's state. @@ -1044,7 +1038,8 @@ impl Client { /// Otherwise, this can fail (but may not) if the DB prunes state. pub fn state_at_beginning(&self, id: BlockId) -> Option> { match self.block_number(id) { - None | Some(0) => None, + None => None, + Some(0) => self.state_at(id), Some(n) => self.state_at(BlockId::Number(n - 1)), } } @@ -1234,8 +1229,9 @@ impl Client { .dont_check_nonce() .save_output_from_contract(); let original_state = if state_diff { Some(state.clone()) } else { None }; + let schedule = machine.schedule(env_info.number); - let mut ret = Executive::new(state, env_info, machine).transact_virtual(transaction, options)?; + let mut ret = Executive::new(state, env_info, &machine, &schedule).transact_virtual(transaction, options)?; if let Some(original) = original_state { ret.state_diff = Some(state.diff_from(original).map_err(ExecutionError::from)?); @@ -1290,10 +1286,12 @@ impl snapshot::DatabaseRestore for Client { let mut tracedb = self.tracedb.write(); self.importer.miner.clear(); let db = self.db.write(); - db.restore(new_db)?; + db.key_value().restore(new_db)?; + db.blooms().reopen()?; + db.trace_blooms().reopen()?; let cache_size = state_db.cache_size(); - *state_db = StateDB::new(journaldb::new(db.clone(), self.pruning, ::db::COL_STATE), cache_size); + *state_db = StateDB::new(journaldb::new(db.key_value().clone(), self.pruning, ::db::COL_STATE), cache_size); *chain = Arc::new(BlockChain::new(self.config.blockchain.clone(), &[], db.clone())); *tracedb = TraceDB::new(self.config.tracing.clone(), db.clone(), chain.clone()); Ok(()) @@ -1326,7 +1324,7 @@ impl ChainInfo for Client { } impl BlockInfo for Client { - fn block_header(&self, id: BlockId) -> Option<::encoded::Header> { + fn block_header(&self, id: BlockId) -> Option { let chain = self.chain.read(); Self::block_hash(&chain, id).and_then(|hash| chain.block_header_data(&hash)) @@ -1343,7 +1341,7 @@ impl BlockInfo for Client { } fn code_hash(&self, address: &Address, id: BlockId) -> Option { - self.state_at(id).and_then(|s| s.code_hash(address).ok()) + self.state_at(id).and_then(|s| s.code_hash(address).unwrap_or(None)) } } @@ -1386,22 +1384,15 @@ impl CallContract for Client { } impl ImportBlock for Client { - fn import_block(&self, bytes: Bytes) -> Result { - use verification::queue::kind::BlockLike; - use verification::queue::kind::blocks::Unverified; - - // create unverified block here so the `keccak` calculation can be cached. - let unverified = Unverified::from_rlp(bytes)?; - - { - if self.chain.read().is_known(&unverified.hash()) { - bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain)); - } - let status = self.block_status(BlockId::Hash(unverified.parent_hash())); - if status == BlockStatus::Unknown || status == BlockStatus::Pending { - bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(unverified.parent_hash()))); - } + fn import_block(&self, unverified: Unverified) -> Result { + if self.chain.read().is_known(&unverified.hash()) { + bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain)); + } + let status = self.block_status(BlockId::Hash(unverified.parent_hash())); + if status == BlockStatus::Unknown || status == BlockStatus::Pending { + bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(unverified.parent_hash()))); } + Ok(self.importer.block_queue.import(unverified)?) } } @@ -1486,7 +1477,9 @@ impl Call for Client { let tx = tx.fake_sign(sender); let mut clone = state.clone(); - Ok(Executive::new(&mut clone, &env_info, self.engine.machine()) + let machine = self.engine.machine(); + let schedule = machine.schedule(env_info.number); + Ok(Executive::new(&mut clone, &env_info, &machine, &schedule) .transact_virtual(&tx, options()) .map(|r| r.exception.is_none()) .unwrap_or(false)) @@ -1543,10 +1536,10 @@ impl BlockChainClient for Client { let block = BlockId::Hash(address.block_hash); const PROOF: &'static str = "The transaction address contains a valid index within block; qed"; - Ok(self.replay_block_transactions(block, analytics)?.nth(address.index).expect(PROOF)) + Ok(self.replay_block_transactions(block, analytics)?.nth(address.index).expect(PROOF).1) } - fn replay_block_transactions(&self, block: BlockId, analytics: CallAnalytics) -> Result>, CallError> { + fn replay_block_transactions(&self, block: BlockId, analytics: CallAnalytics) -> Result>, CallError> { let mut env_info = self.env_info(block).ok_or(CallError::StatePruned)?; let body = self.block_body(block).ok_or(CallError::StatePruned)?; let mut state = self.state_at_beginning(block).ok_or(CallError::StatePruned)?; @@ -1558,28 +1551,28 @@ impl BlockChainClient for Client { Ok(Box::new(txs.into_iter() .map(move |t| { + let transaction_hash = t.hash(); let t = SignedTransaction::new(t).expect(PROOF); let machine = engine.machine(); let x = Self::do_virtual_call(machine, &env_info, &mut state, &t, analytics).expect(EXECUTE_PROOF); env_info.gas_used = env_info.gas_used + x.gas_used; - x + (transaction_hash, x) }))) } - - fn mode(&self) -> IpcMode { + fn mode(&self) -> Mode { let r = self.mode.lock().clone().into(); trace!(target: "mode", "Asked for mode = {:?}. returning {:?}", &*self.mode.lock(), r); r } fn disable(&self) { - self.set_mode(IpcMode::Off); + self.set_mode(Mode::Off); self.enabled.store(false, AtomicOrdering::Relaxed); self.clear_queue(); } - fn set_mode(&self, new_mode: IpcMode) { + fn set_mode(&self, new_mode: Mode) { trace!(target: "mode", "Client::set_mode({:?})", new_mode); if !self.enabled.load(AtomicOrdering::Relaxed) { return; @@ -1594,8 +1587,8 @@ impl BlockChainClient for Client { } } match new_mode { - IpcMode::Active => self.wake_up(), - IpcMode::Off => self.sleep(), + Mode::Active => self.wake_up(), + Mode::Off => self.sleep(), _ => {(*self.sleep_state.lock()).last_activity = Some(Instant::now()); } } } @@ -1695,6 +1688,9 @@ impl BlockChainClient for Client { if let Some(after) = after { if let Err(e) = iter.seek(after) { trace!(target: "fatdb", "list_accounts: Couldn't seek the DB: {:?}", e); + } else { + // Position the iterator after the `after` element + iter.next(); } } @@ -1707,7 +1703,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; } @@ -1738,7 +1734,10 @@ impl BlockChainClient for Client { if let Some(after) = after { if let Err(e) = iter.seek(after) { - trace!(target: "fatdb", "list_accounts: Couldn't seek the DB: {:?}", e); + trace!(target: "fatdb", "list_storage: Couldn't seek the DB: {:?}", e); + } else { + // Position the iterator after the `after` element + iter.next(); } } @@ -1836,17 +1835,10 @@ impl BlockChainClient for Client { let from = self.block_number_ref(&filter.from_block)?; let to = self.block_number_ref(&filter.to_block)?; - filter.bloom_possibilities().iter() - .map(|bloom| { - chain.blocks_with_bloom(bloom, from, to) - }) - .flat_map(|m| m) - // remove duplicate elements - .collect::>() + chain.blocks_with_bloom(&filter.bloom_possibilities(), from, to) .into_iter() .filter_map(|n| chain.block_hash(n)) .collect::>() - } else { // Otherwise, we use a slower version that finds a link between from_block and to_block. let from_hash = Self::block_hash(&chain, filter.from_block)?; @@ -1954,8 +1946,26 @@ impl BlockChainClient for Client { (*self.build_last_hashes(&self.chain.read().best_block_hash())).clone() } - fn ready_transactions(&self) -> Vec> { - self.importer.miner.ready_transactions(self) + fn transactions_to_propagate(&self) -> Vec> { + const PROPAGATE_FOR_BLOCKS: u32 = 4; + const MIN_TX_TO_PROPAGATE: usize = 256; + + let block_gas_limit = *self.best_block_header().gas_limit(); + let min_tx_gas: U256 = self.latest_schedule().tx_gas.into(); + + let max_len = if min_tx_gas.is_zero() { + usize::max_value() + } else { + cmp::max( + MIN_TX_TO_PROPAGATE, + cmp::min( + (block_gas_limit / min_tx_gas) * PROPAGATE_FOR_BLOCKS, + // never more than usize + usize::max_value().into() + ).as_u64() as usize + ) + }; + self.importer.miner.ready_transactions(self, max_len, ::miner::PendingOrdering::Priority) } fn signing_chain_id(&self) -> Option { @@ -2011,8 +2021,9 @@ impl BlockChainClient for Client { impl IoClient for Client { fn queue_transactions(&self, transactions: Vec, peer_id: usize) { + trace_time!("queue_transactions"); let len = transactions.len(); - self.queue_transactions.queue(&mut self.io_channel.lock(), move |client| { + self.queue_transactions.queue(&self.io_channel.read(), len, move |client| { trace_time!("import_queued_transactions"); let txs: Vec = transactions @@ -2030,40 +2041,60 @@ impl IoClient for Client { }); } - fn queue_ancient_block(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result { - let header: Header = ::rlp::Rlp::new(&block_bytes).val_at(0)?; - let hash = header.hash(); + fn queue_ancient_block(&self, unverified: Unverified, receipts_bytes: Bytes) -> Result { + trace_time!("queue_ancient_block"); + let hash = unverified.hash(); { // check block order if self.chain.read().is_known(&hash) { bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain)); } - - let parent_hash = *header.parent_hash(); - let parent_pending = self.pending_ancient_blocks.read().contains(&parent_hash); - let status = self.block_status(BlockId::Hash(parent_hash)); - if !parent_pending && (status == BlockStatus::Unknown || status == BlockStatus::Pending) { - bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(parent_hash))); + let parent_hash = unverified.parent_hash(); + // NOTE To prevent race condition with import, make sure to check queued blocks first + // (and attempt to acquire lock) + let is_parent_pending = self.queued_ancient_blocks.read().0.contains(&parent_hash); + if !is_parent_pending { + let status = self.block_status(BlockId::Hash(parent_hash)); + if status == BlockStatus::Unknown || status == BlockStatus::Pending { + bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(parent_hash))); + } } } - self.pending_ancient_blocks.write().insert(hash); - - trace!(target: "client", "Queuing old block #{}", header.number()); - match self.queue_ancient_blocks.queue(&mut self.io_channel.lock(), move |client| { - let result = client.importer.import_old_block( - &header, - &block_bytes, - &receipts_bytes, - &**client.db.read(), - &*client.chain.read() - ); - - client.pending_ancient_blocks.write().remove(&hash); - result.map(|_| ()).unwrap_or_else(|e| { - error!(target: "client", "Error importing ancient block: {}", e); - }); + // we queue blocks here and trigger an IO message. + { + let mut queued = self.queued_ancient_blocks.write(); + queued.0.insert(hash); + queued.1.push_back((unverified, receipts_bytes)); + } + + let queued = self.queued_ancient_blocks.clone(); + let lock = self.ancient_blocks_import_lock.clone(); + match self.queue_ancient_blocks.queue(&self.io_channel.read(), 1, move |client| { + trace_time!("import_ancient_block"); + // Make sure to hold the lock here to prevent importing out of order. + // We use separate lock, cause we don't want to block queueing. + let _lock = lock.lock(); + for _i in 0..MAX_ANCIENT_BLOCKS_TO_IMPORT { + let first = queued.write().1.pop_front(); + if let Some((unverified, receipts_bytes)) = first { + let hash = unverified.hash(); + let result = client.importer.import_old_block( + unverified, + &receipts_bytes, + &**client.db.read().key_value(), + &*client.chain.read(), + ); + if let Err(e) = result { + error!(target: "client", "Error importing ancient block: {}", e); + } + // remove from pending + queued.write().0.remove(&hash); + } else { + break; + } + } }) { Ok(_) => Ok(hash), Err(e) => bail!(BlockImportErrorKind::Other(format!("{}", e))), @@ -2071,7 +2102,7 @@ impl IoClient for Client { } fn queue_consensus_message(&self, message: Bytes) { - match self.queue_consensus_message.queue(&mut self.io_channel.lock(), move |client| { + match self.queue_consensus_message.queue(&self.io_channel.read(), 1, move |client| { if let Err(e) = client.engine().handle_message(&message) { debug!(target: "poa", "Invalid message received: {}", e); } @@ -2115,7 +2146,7 @@ impl ReopenBlock for Client { } impl PrepareOpenBlock for Client { - fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock { + fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> Result { let engine = &*self.engine; let chain = self.chain.read(); let best_header = chain.best_block_header(); @@ -2134,7 +2165,7 @@ impl PrepareOpenBlock for Client { extra_data, is_epoch_begin, &mut chain.ancestry_with_metadata_iter(best_header.hash()), - ).expect("OpenBlock::new only fails if parent state root invalid; state root of best block's header is never invalid; qed"); + )?; // Add uncles chain @@ -2150,7 +2181,7 @@ impl PrepareOpenBlock for Client { qed"); }); - open_block + Ok(open_block) } } @@ -2175,13 +2206,20 @@ impl ImportSealedBlock for Client { let block_data = block.rlp_bytes(); let header = block.header().clone(); - let route = self.importer.commit_block(block, &header, &block_data, self); + let route = self.importer.commit_block(block, &header, encoded::Block::new(block_data), self); trace!(target: "client", "Imported sealed block #{} ({})", number, h); self.state_db.write().sync_cache(&route.enacted, &route.retracted, false); route }; let route = ChainRoute::from([route].as_ref()); - self.importer.miner.chain_new_blocks(self, &[h.clone()], &[], route.enacted(), route.retracted(), self.engine.seals_internally().is_some()); + self.importer.miner.chain_new_blocks( + self, + &[h.clone()], + &[], + route.enacted(), + route.retracted(), + self.engine.seals_internally().is_some(), + ); self.notify(|notify| { notify.new_blocks( vec![h.clone()], @@ -2192,7 +2230,7 @@ impl ImportSealedBlock for Client { start.elapsed(), ); }); - self.db.read().flush().expect("DB flush failed."); + self.db.read().key_value().flush().expect("DB flush failed."); Ok(h) } } @@ -2280,7 +2318,6 @@ impl ProvingBlockChainClient for Client { ) } - fn epoch_signal(&self, hash: H256) -> Option> { // pending transitions are never deleted, and do not contain // finality proofs by definition. @@ -2312,6 +2349,11 @@ fn transaction_receipt(machine: &::machine::EthereumMachine, mut tx: LocalizedTr let transaction_index = tx.transaction_index; LocalizedReceipt { + from: sender, + to: match tx.action { + Action::Create => None, + Action::Call(ref address) => Some(address.clone().into()) + }, transaction_hash: transaction_hash, transaction_index: transaction_index, block_hash: block_hash, @@ -2350,22 +2392,22 @@ mod tests { use std::sync::atomic::{AtomicBool, Ordering}; use kvdb::DBTransaction; use blockchain::ExtrasInsert; + use encoded; let client = generate_dummy_client(0); let genesis = client.chain_info().best_block_hash; let (new_hash, new_block) = get_good_dummy_block_hash(); let go = { - // Separate thread uncommited transaction + // Separate thread uncommitted transaction let go = Arc::new(AtomicBool::new(false)); let go_thread = go.clone(); let another_client = client.clone(); thread::spawn(move || { let mut batch = DBTransaction::new(); - another_client.chain.read().insert_block(&mut batch, &new_block, Vec::new(), ExtrasInsert { + another_client.chain.read().insert_block(&mut batch, encoded::Block::new(new_block), Vec::new(), ExtrasInsert { fork_choice: ::engines::ForkChoice::New, is_finalized: false, - metadata: None, }); go_thread.store(true, Ordering::SeqCst); }); @@ -2437,6 +2479,11 @@ mod tests { // then assert_eq!(receipt, LocalizedReceipt { + from: tx1.sender().into(), + to: match tx1.action { + Action::Create => None, + Action::Call(ref address) => Some(address.clone().into()) + }, transaction_hash: tx1.hash(), transaction_index: 1, block_hash: block_hash, @@ -2484,38 +2531,35 @@ impl fmt::Display for QueueError { /// Queue some items to be processed by IO client. struct IoChannelQueue { - queue: Arc>>>, + currently_queued: Arc, limit: usize, } impl IoChannelQueue { pub fn new(limit: usize) -> Self { IoChannelQueue { - queue: Default::default(), + currently_queued: Default::default(), limit, } } - pub fn queue(&self, channel: &mut IoChannel, fun: F) -> Result<(), QueueError> - where F: Fn(&Client) + Send + Sync + 'static + pub fn queue(&self, channel: &IoChannel, count: usize, fun: F) -> Result<(), QueueError> where + F: Fn(&Client) + Send + Sync + 'static, { - { - let mut queue = self.queue.lock(); - let queue_size = queue.len(); - ensure!(queue_size < self.limit, QueueError::Full(self.limit)); - - queue.push_back(Box::new(fun)); - } + let queue_size = self.currently_queued.load(AtomicOrdering::Relaxed); + ensure!(queue_size < self.limit, QueueError::Full(self.limit)); - let queue = self.queue.clone(); + let currently_queued = self.currently_queued.clone(); let result = channel.send(ClientIoMessage::execute(move |client| { - while let Some(fun) = queue.lock().pop_front() { - fun(client); - } + currently_queued.fetch_sub(count, AtomicOrdering::SeqCst); + fun(client); })); match result { - Ok(_) => Ok(()), + Ok(_) => { + self.currently_queued.fetch_add(count, AtomicOrdering::SeqCst); + Ok(()) + }, Err(e) => Err(QueueError::Channel(e)), } } diff --git a/ethcore/src/client/config.rs b/ethcore/src/client/config.rs index 9787f822a4d090aef29c5dec22fecc9cc8f3bac0..40d2c4990f11a43f1c1c9c248700994a288d2138 100644 --- a/ethcore/src/client/config.rs +++ b/ethcore/src/client/config.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -17,7 +17,6 @@ use std::str::FromStr; use std::fmt::{Display, Formatter, Error as FmtError}; -use mode::Mode as IpcMode; use verification::{VerifierType, QueueConfig}; use journaldb; @@ -71,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,31 +81,8 @@ impl Display for Mode { } } -impl Into for Mode { - fn into(self) -> IpcMode { - match self { - Mode::Off => IpcMode::Off, - Mode::Dark(timeout) => IpcMode::Dark(timeout.as_secs()), - Mode::Passive(timeout, alarm) => IpcMode::Passive(timeout.as_secs(), alarm.as_secs()), - Mode::Active => IpcMode::Active, - } - } -} - -impl From for Mode { - fn from(mode: IpcMode) -> Self { - match mode { - IpcMode::Off => Mode::Off, - IpcMode::Dark(timeout) => Mode::Dark(Duration::from_secs(timeout)), - IpcMode::Passive(timeout, alarm) => Mode::Passive(Duration::from_secs(timeout), Duration::from_secs(alarm)), - IpcMode::Active => Mode::Active, - } - } -} - - /// Client configuration. Includes configs for all sub-systems. -#[derive(Debug, PartialEq, Default)] +#[derive(Debug, PartialEq, Clone)] pub struct ClientConfig { /// Block queue configuration. pub queue: QueueConfig, @@ -132,8 +102,6 @@ pub struct ClientConfig { pub db_cache_size: Option, /// State db compaction profile pub db_compaction: DatabaseCompactionProfile, - /// Should db have WAL enabled? - pub db_wal: bool, /// Operating mode pub mode: Mode, /// The chain spec name @@ -150,11 +118,38 @@ 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(), + 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() { @@ -167,9 +162,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 deleted file mode 100644 index d2af13a3b27f8da862c0431c7add05e4083f51f3..0000000000000000000000000000000000000000 --- a/ethcore/src/client/error.rs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2015-2017 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 . - -use std::fmt::{Display, Formatter, Error as FmtError}; -use util_error::UtilError; -use kvdb; -use trie::TrieError; - -/// Client configuration errors. -#[derive(Debug)] -pub enum Error { - /// TrieDB-related error. - Trie(TrieError), - /// Database error - Database(kvdb::Error), - /// Util error - Util(UtilError), -} - -impl From for Error { - fn from(err: TrieError) -> Self { - Error::Trie(err) - } -} - -impl From for Error { - fn from(err: UtilError) -> Self { - Error::Util(err) - } -} - -impl From> for Error where Error: From { - fn from(err: Box) -> Self { - Error::from(*err) - } -} - -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::Database(ref s) => write!(f, "Database error: {}", s), - } - } -} diff --git a/ethcore/src/client/evm_test_client.rs b/ethcore/src/client/evm_test_client.rs index b91414ca8fa69ce85072908abece3bc300ffa07a..ace7617235a8659fa99223bb882381665d9d0923 100644 --- a/ethcore/src/client/evm_test_client.rs +++ b/ethcore/src/client/evm_test_client.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -25,18 +25,17 @@ 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. ClientError(::error::Error), - /// Low-level database error. - Database(kvdb::Error), /// Post-condition failure, PostCondition(String), } @@ -55,7 +54,6 @@ impl fmt::Display for EvmTestError { Trie(ref err) => write!(fmt, "Trie: {}", err), Evm(ref err) => write!(fmt, "EVM: {}", err), ClientError(ref err) => write!(fmt, "{}", err), - Database(ref err) => write!(fmt, "DB: {}", err), PostCondition(ref err) => write!(fmt, "{}", err), } } @@ -64,15 +62,6 @@ impl fmt::Display for EvmTestError { use ethereum; use ethjson::state::test::ForkSpec; -lazy_static! { - pub static ref FRONTIER: spec::Spec = ethereum::new_frontier_test(); - pub static ref HOMESTEAD: spec::Spec = ethereum::new_homestead_test(); - pub static ref EIP150: spec::Spec = ethereum::new_eip150_test(); - pub static ref EIP161: spec::Spec = ethereum::new_eip161_test(); - pub static ref BYZANTIUM: spec::Spec = ethereum::new_byzantium_test(); - pub static ref BYZANTIUM_TRANSITION: spec::Spec = ethereum::new_transition_test(); -} - /// Simplified, single-block EVM test client. pub struct EvmTestClient<'a> { state: state::State, @@ -90,14 +79,14 @@ impl<'a> fmt::Debug for EvmTestClient<'a> { impl<'a> EvmTestClient<'a> { /// Converts a json spec definition into spec. - pub fn spec_from_json(spec: &ForkSpec) -> Option<&'static spec::Spec> { + pub fn spec_from_json(spec: &ForkSpec) -> Option { match *spec { - ForkSpec::Frontier => Some(&*FRONTIER), - ForkSpec::Homestead => Some(&*HOMESTEAD), - ForkSpec::EIP150 => Some(&*EIP150), - ForkSpec::EIP158 => Some(&*EIP161), - ForkSpec::Byzantium => Some(&*BYZANTIUM), - ForkSpec::EIP158ToByzantiumAt5 => Some(&BYZANTIUM_TRANSITION), + ForkSpec::Frontier => Some(ethereum::new_frontier_test()), + ForkSpec::Homestead => Some(ethereum::new_homestead_test()), + ForkSpec::EIP150 => Some(ethereum::new_eip150_test()), + ForkSpec::EIP158 => Some(ethereum::new_eip161_test()), + ForkSpec::Byzantium => Some(ethereum::new_byzantium_test()), + ForkSpec::EIP158ToByzantiumAt5 => Some(ethereum::new_transition_test()), ForkSpec::FrontierToHomesteadAt5 | ForkSpec::HomesteadToDaoAt5 | ForkSpec::HomesteadToEIP150At5 => None, _ => None, } @@ -144,7 +133,7 @@ impl<'a> EvmTestClient<'a> { { let mut batch = kvdb::DBTransaction::new(); state_db.journal_under(&mut batch, 0, &genesis.hash())?; - db.write(batch).map_err(EvmTestError::Database)?; + db.write(batch)?; } state::State::from_existing( @@ -195,7 +184,9 @@ impl<'a> EvmTestClient<'a> { }; let mut substate = state::Substate::new(); let mut output = vec![]; - let mut executive = executive::Executive::new(&mut self.state, &info, self.spec.engine.machine()); + let machine = self.spec.engine.machine(); + let schedule = machine.schedule(info.number); + let mut executive = executive::Executive::new(&mut self.state, &info, &machine, &schedule); executive.call( params, &mut substate, diff --git a/ethcore/src/client/io_message.rs b/ethcore/src/client/io_message.rs index 817c72602052c2c27f228c511e020ae2b267a037..d388f5ed44c3f2b9c7dd3da1f867e797048273b8 100644 --- a/ethcore/src/client/io_message.rs +++ b/ethcore/src/client/io_message.rs @@ -54,4 +54,3 @@ impl fmt::Debug for Callback { write!(fmt, "") } } - diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 4c410d301179a9a9f3bfc14c0a852d1eb65f85dd..ffd303c1277aa57e7526a85e3580d45d63aef27c 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -19,17 +19,19 @@ mod ancient_import; mod client; mod config; -mod error; +#[cfg(any(test, feature = "test-helpers"))] mod evm_test_client; mod io_message; +#[cfg(any(test, feature = "test-helpers"))] mod test_client; mod trace; pub use self::client::*; pub use self::config::{Mode, ClientConfig, DatabaseCompactionProfile, BlockChainConfig, VMType}; -pub use self::error::Error; +#[cfg(any(test, feature = "test-helpers"))] pub use self::evm_test_client::{EvmTestClient, EvmTestError, TransactResult}; pub use self::io_message::ClientIoMessage; +#[cfg(any(test, feature = "test-helpers"))] pub use self::test_client::{TestBlockChainClient, EachBlockWith}; pub use self::chain_notify::{ChainNotify, ChainRoute, ChainRouteType, ChainMessageType}; pub use self::traits::{ diff --git a/ethcore/src/client/private_notify.rs b/ethcore/src/client/private_notify.rs index 2b865a9e2c7d51596d006df7c9bb22d720ed19b2..d1fde555c98be7ce6990ed69491e3613612c4c9b 100644 --- a/ethcore/src/client/private_notify.rs +++ b/ethcore/src/client/private_notify.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index fab32346572e1fcf2e75c197317e46adad3fe245..f729b15b7fb2d8f5081236d25147785b18371e66 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -36,7 +36,7 @@ use transaction::{self, Transaction, LocalizedTransaction, SignedTransaction, Ac use blockchain::{TreeRoute, BlockReceipts}; use client::{ Nonce, Balance, ChainInfo, BlockInfo, ReopenBlock, CallContract, TransactionInfo, RegistryInfo, - PrepareOpenBlock, BlockChainClient, BlockChainInfo, BlockStatus, BlockId, + PrepareOpenBlock, BlockChainClient, BlockChainInfo, BlockStatus, BlockId, Mode, TransactionId, UncleId, TraceId, TraceFilter, LastHashes, CallAnalytics, BlockImportError, ProvingBlockChainClient, ScheduleInfo, ImportSealedBlock, BroadcastProposalBlock, ImportBlock, StateOrBlock, Call, StateClient, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter, IoClient @@ -46,15 +46,14 @@ use header::{Header as BlockHeader, BlockNumber}; use filter::Filter; use log_entry::LocalizedLogEntry; use receipt::{Receipt, LocalizedReceipt, TransactionOutcome}; -use error::ImportResult; +use error::{Error, ImportResult}; use vm::Schedule; -use miner::{Miner, MinerService}; +use miner::{self, Miner, MinerService}; use spec::Spec; use types::basic_account::BasicAccount; -use types::mode::Mode; use types::pruning_info::PruningInfo; - use verification::queue::QueueInfo; +use verification::queue::kind::blocks::Unverified; use block::{OpenBlock, SealedBlock, ClosedBlock}; use executive::Executed; use error::CallError; @@ -63,7 +62,7 @@ use state_db::StateDB; use header::Header; use encoded; use engines::EthEngine; -use trie; +use ethtrie; use state::StateInfo; use views::BlockView; @@ -282,7 +281,8 @@ impl TestBlockChainClient { rlp.append(&header); rlp.append_raw(&txs, 1); rlp.append_raw(uncles.as_raw(), 1); - self.import_block(rlp.as_raw().to_vec()).unwrap(); + let unverified = Unverified::from_rlp(rlp.out()).unwrap(); + self.import_block(unverified).unwrap(); } } @@ -375,7 +375,7 @@ impl ReopenBlock for TestBlockChainClient { } impl PrepareOpenBlock for TestBlockChainClient { - fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock { + fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> Result { let engine = &*self.spec.engine; let genesis_header = self.spec.genesis_header(); let db = self.spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); @@ -393,10 +393,10 @@ impl PrepareOpenBlock for TestBlockChainClient { extra_data, false, &mut Vec::new().into_iter(), - ).expect("Opening block for tests will not fail."); + )?; // TODO [todr] Override timestamp for predictability open_block.set_timestamp(*self.latest_block_timestamp.read()); - open_block + Ok(open_block) } } @@ -514,8 +514,8 @@ impl RegistryInfo for TestBlockChainClient { } impl ImportBlock for TestBlockChainClient { - fn import_block(&self, b: Bytes) -> Result { - let header = view!(BlockView, &b).header(); + fn import_block(&self, unverified: Unverified) -> Result { + let header = unverified.header; let h = header.hash(); let number: usize = header.number() as usize; if number > self.blocks.read().len() { @@ -541,7 +541,7 @@ impl ImportBlock for TestBlockChainClient { *difficulty = *difficulty + header.difficulty().clone(); } mem::replace(&mut *self.last_hash.write(), h.clone()); - self.blocks.write().insert(h.clone(), b); + self.blocks.write().insert(h.clone(), unverified.bytes); self.numbers.write().insert(number, h.clone()); let mut parent_hash = header.parent_hash().clone(); if number > 0 { @@ -554,7 +554,7 @@ impl ImportBlock for TestBlockChainClient { } } else { - self.blocks.write().insert(h.clone(), b.to_vec()); + self.blocks.write().insert(h.clone(), unverified.bytes); } Ok(h) } @@ -582,10 +582,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 { @@ -612,8 +612,8 @@ impl BlockChainClient for TestBlockChainClient { self.execution_result.read().clone().unwrap() } - fn replay_block_transactions(&self, _block: BlockId, _analytics: CallAnalytics) -> Result>, CallError> { - Ok(Box::new(self.execution_result.read().clone().unwrap().into_iter())) + fn replay_block_transactions(&self, _block: BlockId, _analytics: CallAnalytics) -> Result>, CallError> { + Ok(Box::new(self.traces.read().clone().unwrap().into_iter().map(|t| t.transaction_hash.unwrap_or(H256::new())).zip(self.execution_result.read().clone().unwrap().into_iter()))) } fn block_total_difficulty(&self, _id: BlockId) -> Option { @@ -704,7 +704,6 @@ impl BlockChainClient for TestBlockChainClient { .map(|header| self.spec.engine.extra_info(&header)) } - fn block_status(&self, id: BlockId) -> BlockStatus { match id { BlockId::Number(number) if (number as usize) < self.blocks.read().len() => BlockStatus::InChain, @@ -808,8 +807,8 @@ impl BlockChainClient for TestBlockChainClient { self.traces.read().clone() } - fn ready_transactions(&self) -> Vec> { - self.miner.ready_transactions(self) + fn transactions_to_propagate(&self) -> Vec> { + self.miner.ready_transactions(self, 4096, miner::PendingOrdering::Priority) } fn signing_chain_id(&self) -> Option { None } @@ -859,8 +858,8 @@ impl IoClient for TestBlockChainClient { self.miner.import_external_transactions(self, txs); } - fn queue_ancient_block(&self, b: Bytes, _r: Bytes) -> Result { - self.import_block(b) + fn queue_ancient_block(&self, unverified: Unverified, _r: Bytes) -> Result { + self.import_block(unverified) } fn queue_consensus_message(&self, message: Bytes) { diff --git a/ethcore/src/client/trace.rs b/ethcore/src/client/trace.rs index 75e0fe34a1e383342e0cb344610df0f6a225792f..5f1b6c4f4de61ce65feabe909d08afb7c2b61c01 100644 --- a/ethcore/src/client/trace.rs +++ b/ethcore/src/client/trace.rs @@ -1,3 +1,18 @@ +// 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 . //! Bridge between Tracedb and Blockchain. diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index 358e24fa9058b84e52788887bef5fbebc481d628..6ccba5e0f81edb28bb8ccb4c5f6a423b695c474c 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -21,9 +21,10 @@ use itertools::Itertools; use block::{OpenBlock, SealedBlock, ClosedBlock}; use blockchain::TreeRoute; +use client::Mode; use encoded; use vm::LastHashes; -use error::{ImportResult, CallError, BlockImportError}; +use error::{Error, ImportResult, CallError, BlockImportError}; use evm::Schedule; use executive::Executed; use filter::Filter; @@ -33,6 +34,7 @@ use receipt::LocalizedReceipt; use trace::LocalizedTrace; use transaction::{self, LocalizedTransaction, SignedTransaction}; use verification::queue::QueueInfo as BlockQueueInfo; +use verification::queue::kind::blocks::Unverified; use state::StateInfo; use header::Header; use engines::EthEngine; @@ -48,7 +50,6 @@ use types::trace_filter::Filter as TraceFilter; use types::call_analytics::CallAnalytics; use types::blockchain_info::BlockChainInfo; use types::block_status::BlockStatus; -use types::mode::Mode; use types::pruning_info::PruningInfo; /// State information to be used during client query @@ -167,7 +168,7 @@ pub trait RegistryInfo { /// Provides methods to import block into blockchain pub trait ImportBlock { /// Import a block into the blockchain. - fn import_block(&self, bytes: Bytes) -> Result; + fn import_block(&self, block: Unverified) -> Result; } /// Provides `call_contract` method @@ -204,7 +205,7 @@ pub trait IoClient: Sync + Send { fn queue_transactions(&self, transactions: Vec, peer_id: usize); /// Queue block import with transaction receipts. Does no sealing and transaction validation. - fn queue_ancient_block(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result; + fn queue_ancient_block(&self, block_bytes: Unverified, receipts_bytes: Bytes) -> Result; /// Queue conensus engine message. fn queue_consensus_message(&self, message: Bytes); @@ -303,7 +304,7 @@ pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContra fn replay(&self, t: TransactionId, analytics: CallAnalytics) -> Result; /// Replays all the transactions in a given block for inspection. - fn replay_block_transactions(&self, block: BlockId, analytics: CallAnalytics) -> Result>, CallError>; + fn replay_block_transactions(&self, block: BlockId, analytics: CallAnalytics) -> Result>, CallError>; /// Returns traces matching given filter. fn filter_traces(&self, filter: TraceFilter) -> Option>; @@ -320,8 +321,8 @@ pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContra /// Get last hashes starting from best block. fn last_hashes(&self) -> LastHashes; - /// List all transactions that are allowed into the next block. - fn ready_transactions(&self) -> Vec>; + /// List all ready transactions that should be propagated to other peers. + fn transactions_to_propagate(&self) -> Vec>; /// Sorted list of transaction gas prices from at least last sample_size blocks. fn gas_price_corpus(&self, sample_size: usize) -> ::stats::Corpus { @@ -395,7 +396,7 @@ pub trait PrepareOpenBlock { author: Address, gas_range_target: (U256, U256), extra_data: Bytes - ) -> OpenBlock; + ) -> Result; } /// Provides methods used for sealing new state diff --git a/ethcore/src/db.rs b/ethcore/src/db.rs index a1c7d6b0f5e47914060a05dcd79bd0ba2475cf7a..39c30e9637601064bc8609a8b55e1c99a9eef4f3 100644 --- a/ethcore/src/db.rs +++ b/ethcore/src/db.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/encoded.rs b/ethcore/src/encoded.rs index 5a2d376a2a3b0f90daa818d1e8a5cc50fe83775f..9573bb5d16c447feee1a3389dfc6ef6f1a715298 100644 --- a/ethcore/src/encoded.rs +++ b/ethcore/src/encoded.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -222,6 +222,11 @@ impl Block { /// Consume the view and return the raw bytes. pub fn into_inner(self) -> Vec { self.0 } + + /// Returns the reference to slice of bytes + pub fn raw(&self) -> &[u8] { + &self.0 + } } // forwarders to borrowed header view. diff --git a/ethcore/src/engines/authority_round/finality.rs b/ethcore/src/engines/authority_round/finality.rs index 61f1c182294d4e36f411d976657691df10ea3011..3745cde96c2f330a48040d1e393966dc75b8bf28 100644 --- a/ethcore/src/engines/authority_round/finality.rs +++ b/ethcore/src/engines/authority_round/finality.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index 02bb88c51f2208b6a1b0ec0f7e660e7e9446825f..0c4906be565f0140203fffdc3dd12cdaa879f1b5 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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,18 +30,15 @@ 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, Signature}; +use ethkey::{self, Password, Signature}; use io::{IoContext, IoHandler, TimerToken, IoService}; use itertools::{self, Itertools}; use rlp::{encode, Decodable, DecoderError, Encodable, RlpStream, Rlp}; @@ -382,12 +380,16 @@ impl Decodable for SealedEmptyStep { } } +struct PermissionedStep { + inner: Step, + can_propose: AtomicBool, +} + /// Engine using `AuthorityRound` proof-of-authority BFT consensus. pub struct AuthorityRound { transition_service: IoService<()>, - step: Arc, - can_propose: AtomicBool, - client: RwLock>>, + step: Arc, + client: Arc>>>, signer: RwLock, validators: Box, validate_score_transition: u64, @@ -407,7 +409,7 @@ pub struct AuthorityRound { // header-chain validator. struct EpochVerifier { - step: Arc, + step: Arc, subchain_validators: SimpleList, empty_steps_transition: u64, } @@ -415,7 +417,7 @@ struct EpochVerifier { impl super::EpochVerifier for EpochVerifier { fn verify_light(&self, header: &Header) -> Result<(), Error> { // Validate the timestamp - verify_timestamp(&*self.step, header_step(header, self.empty_steps_transition)?)?; + verify_timestamp(&self.step.inner, header_step(header, self.empty_steps_transition)?)?; // always check the seal since it's fast. // nothing heavier to do. verify_external(header, &self.subchain_validators, self.empty_steps_transition) @@ -571,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(()) @@ -603,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> { @@ -615,13 +633,15 @@ impl AuthorityRound { let engine = Arc::new( AuthorityRound { transition_service: IoService::<()>::start()?, - step: Arc::new(Step { - inner: AtomicUsize::new(initial_step), - calibrate: our_params.start_step.is_none(), - duration: our_params.step_duration, + step: Arc::new(PermissionedStep { + inner: Step { + inner: AtomicUsize::new(initial_step), + calibrate: our_params.start_step.is_none(), + duration: our_params.step_duration, + }, + can_propose: AtomicBool::new(true), }), - can_propose: AtomicBool::new(true), - client: RwLock::new(None), + client: Arc::new(RwLock::new(None)), signer: Default::default(), validators: our_params.validators, validate_score_transition: our_params.validate_score_transition, @@ -641,12 +661,39 @@ impl AuthorityRound { // Do not initialize timeouts for tests. if should_timeout { - let handler = TransitionHandler { engine: Arc::downgrade(&engine) }; + let handler = TransitionHandler { + step: engine.step.clone(), + client: engine.client.clone(), + }; engine.transition_service.register_handler(Arc::new(handler))?; } 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 && @@ -655,7 +702,6 @@ impl AuthorityRound { }).cloned().collect() } - fn clear_empty_steps(&self, step: U256) { // clear old `empty_steps` messages self.empty_steps.lock().retain(|e| U256::from(e.step) > step); @@ -667,7 +713,7 @@ impl AuthorityRound { } fn generate_empty_step(&self, parent_hash: &H256) { - let step = self.step.load(); + let step = self.step.inner.load(); let empty_step_rlp = empty_step_rlp(step, parent_hash); if let Ok(signature) = self.sign(keccak(&empty_step_rlp)).map(Into::into) { @@ -692,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 { @@ -699,34 +767,37 @@ fn unix_now() -> Duration { } struct TransitionHandler { - engine: Weak, + step: Arc, + client: Arc>>>, } const ENGINE_TIMEOUT_TOKEN: TimerToken = 23; impl IoHandler<()> for TransitionHandler { fn initialize(&self, io: &IoContext<()>) { - if let Some(engine) = self.engine.upgrade() { - let remaining = engine.step.duration_remaining().as_millis(); - io.register_timer_once(ENGINE_TIMEOUT_TOKEN, Duration::from_millis(remaining)) - .unwrap_or_else(|e| warn!(target: "engine", "Failed to start consensus step timer: {}.", e)) - } + let remaining = AsMillis::as_millis(&self.step.inner.duration_remaining()); + io.register_timer_once(ENGINE_TIMEOUT_TOKEN, Duration::from_millis(remaining)) + .unwrap_or_else(|e| warn!(target: "engine", "Failed to start consensus step timer: {}.", e)) } fn timeout(&self, io: &IoContext<()>, timer: TimerToken) { if timer == ENGINE_TIMEOUT_TOKEN { - if let Some(engine) = self.engine.upgrade() { - // NOTE we might be lagging by couple of steps in case the timeout - // has not been called fast enough. - // Make sure to advance up to the actual step. - while engine.step.duration_remaining().as_millis() == 0 { - engine.step(); + // NOTE we might be lagging by couple of steps in case the timeout + // has not been called fast enough. + // Make sure to advance up to the actual step. + while AsMillis::as_millis(&self.step.inner.duration_remaining()) == 0 { + self.step.inner.increment(); + self.step.can_propose.store(true, AtomicOrdering::SeqCst); + if let Some(ref weak) = *self.client.read() { + if let Some(c) = weak.upgrade() { + c.update_sealing(); + } } - - let next_run_at = engine.step.duration_remaining().as_millis() >> 2; - io.register_timer_once(ENGINE_TIMEOUT_TOKEN, Duration::from_millis(next_run_at)) - .unwrap_or_else(|e| warn!(target: "engine", "Failed to restart consensus step timer: {}.", e)) } + + let next_run_at = AsMillis::as_millis(&self.step.inner.duration_remaining()) >> 2; + io.register_timer_once(ENGINE_TIMEOUT_TOKEN, Duration::from_millis(next_run_at)) + .unwrap_or_else(|e| warn!(target: "engine", "Failed to restart consensus step timer: {}.", e)) } } } @@ -743,8 +814,8 @@ impl Engine for AuthorityRound { } fn step(&self) { - self.step.increment(); - self.can_propose.store(true, AtomicOrdering::SeqCst); + self.step.inner.increment(); + self.step.can_propose.store(true, AtomicOrdering::SeqCst); if let Some(ref weak) = *self.client.read() { if let Some(c) = weak.upgrade() { c.update_sealing(); @@ -791,7 +862,7 @@ impl Engine for AuthorityRound { fn populate_from_parent(&self, header: &mut Header, parent: &Header) { let parent_step = header_step(parent, self.empty_steps_transition).expect("Header has been verified; qed"); - let current_step = self.step.load(); + let current_step = self.step.inner.load(); let current_empty_steps_len = if header.number() >= self.empty_steps_transition { self.empty_steps(parent_step.into(), current_step.into(), parent.hash()).len() @@ -817,7 +888,7 @@ impl Engine for AuthorityRound { let empty_step: EmptyStep = rlp.as_val().map_err(fmt_err)?;; if empty_step.verify(&*self.validators).unwrap_or(false) { - if self.step.check_future(empty_step.step).is_ok() { + if self.step.inner.check_future(empty_step.step).is_ok() { trace!(target: "engine", "handle_message: received empty step message {:?}", empty_step); self.handle_empty_step_message(empty_step); } else { @@ -837,7 +908,7 @@ impl Engine for AuthorityRound { fn generate_seal(&self, block: &ExecutedBlock, parent: &Header) -> Seal { // first check to avoid generating signature most of the time // (but there's still a race to the `compare_and_swap`) - if !self.can_propose.load(AtomicOrdering::SeqCst) { + if !self.step.can_propose.load(AtomicOrdering::SeqCst) { trace!(target: "engine", "Aborting seal generation. Can't propose."); return Seal::None; } @@ -846,7 +917,7 @@ impl Engine for AuthorityRound { let parent_step: U256 = header_step(parent, self.empty_steps_transition) .expect("Header has been verified; qed").into(); - let step = self.step.load(); + let step = self.step.inner.load(); // filter messages from old and future steps and different parents let empty_steps = if header.number() >= self.empty_steps_transition { @@ -868,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() { @@ -923,10 +977,16 @@ impl Engine for AuthorityRound { trace!(target: "engine", "generate_seal: Issuing a block for step {}.", step); // only issue the seal if we were the first to reach the compare_and_swap. - if self.can_propose.compare_and_swap(true, false, AtomicOrdering::SeqCst) { - + 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(), @@ -1000,7 +1060,7 @@ impl Engine for AuthorityRound { .decode()?; let parent_step = header_step(&parent, self.empty_steps_transition)?; - let current_step = self.step.load(); + let current_step = self.step.inner.load(); self.empty_steps(parent_step.into(), current_step.into(), parent.hash()) } else { // we're verifying a block, extract empty steps from the seal @@ -1049,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, header_step(header, self.empty_steps_transition)?) { + 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()), @@ -1067,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 @@ -1081,9 +1149,10 @@ impl Engine for AuthorityRound { // If empty step messages are enabled we will validate the messages in the seal, missing messages are not // reported as there's no way to tell whether the empty step message was never sent or simply not included. - if header.number() >= self.empty_steps_transition { - let validate_empty_steps = || -> Result<(), Error> { + let empty_steps_len = if header.number() >= self.empty_steps_transition { + let validate_empty_steps = || -> Result { let empty_steps = header_empty_steps(header)?; + let empty_steps_len = empty_steps.len(); for empty_step in empty_steps { if empty_step.step <= parent_step || empty_step.step >= step { Err(EngineError::InsufficientProof( @@ -1095,34 +1164,31 @@ 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)))?; } } - Ok(()) + Ok(empty_steps_len) }; - if let err @ Err(_) = validate_empty_steps() { - self.validators.report_benign(header.author(), set_number, header.number()); - return err; + match validate_empty_steps() { + Ok(len) => len, + Err(err) => { + self.validators.report_benign(header.author(), set_number, header.number()); + return Err(err); + }, } - } 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); + + 0 + }; + + if header.number() >= self.validate_score_transition { + let expected_difficulty = calculate_score(parent_step.into(), step.into(), empty_steps_len.into()); + if header.difficulty() != &expected_difficulty { + return Err(From::from(BlockError::InvalidDifficulty(Mismatch { expected: expected_difficulty, found: header.difficulty().clone() }))); } } @@ -1131,37 +1197,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 } @@ -1295,7 +1345,7 @@ impl Engine for AuthorityRound { // This way, upon encountering an epoch change, the proposer from the // new set will be forced to wait until the next step to avoid sealing a // block that breaks the invariant that the parent's step < the block's step. - self.can_propose.store(false, AtomicOrdering::SeqCst); + self.step.can_propose.store(false, AtomicOrdering::SeqCst); return Some(combine_proofs(signal_number, &pending.proof, &*finality_proof)); } } @@ -1334,7 +1384,7 @@ impl Engine for AuthorityRound { self.validators.register_client(client); } - fn set_signer(&self, ap: Arc, address: Address, password: String) { + fn set_signer(&self, ap: Arc, address: Address, password: Password) { self.signer.write().set(ap, address, password); } @@ -1365,7 +1415,7 @@ mod tests { use rlp::encode; use block::*; use test_helpers::{ - generate_dummy_client_with_spec_and_accounts, get_temp_state_db, generate_dummy_client, + generate_dummy_client_with_spec_and_accounts, get_temp_state_db, TestNotify }; use account_provider::AccountProvider; @@ -1374,7 +1424,7 @@ mod tests { use engines::{Seal, Engine, EngineError, EthEngine}; use engines::validator_set::TestSet; use error::{Error, ErrorKind}; - use super::{AuthorityRoundParams, AuthorityRound, EmptyStep, SealedEmptyStep}; + use super::{AuthorityRoundParams, AuthorityRound, EmptyStep, SealedEmptyStep, calculate_score}; #[test] fn has_valid_metadata() { @@ -1403,8 +1453,8 @@ mod tests { #[test] fn generates_seal_and_does_not_double_propose() { let tap = Arc::new(AccountProvider::transient_provider()); - let addr1 = tap.insert_account(keccak("1").into(), "1").unwrap(); - let addr2 = tap.insert_account(keccak("2").into(), "2").unwrap(); + let addr1 = tap.insert_account(keccak("1").into(), &"1".into()).unwrap(); + let addr2 = tap.insert_account(keccak("2").into(), &"2".into()).unwrap(); let spec = Spec::new_test_round(); let engine = &*spec.engine; @@ -1413,9 +1463,9 @@ mod tests { let db2 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); - let b1 = b1.close_and_lock(); + let b1 = b1.close_and_lock().unwrap(); let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); - let b2 = b2.close_and_lock(); + let b2 = b2.close_and_lock().unwrap(); engine.set_signer(tap.clone(), addr1, "1".into()); if let Seal::Regular(seal) = engine.generate_seal(b1.block(), &genesis_header) { @@ -1435,8 +1485,8 @@ mod tests { #[test] fn checks_difficulty_in_generate_seal() { let tap = Arc::new(AccountProvider::transient_provider()); - let addr1 = tap.insert_account(keccak("1").into(), "1").unwrap(); - let addr2 = tap.insert_account(keccak("0").into(), "0").unwrap(); + let addr1 = tap.insert_account(keccak("1").into(), &"1".into()).unwrap(); + let addr2 = tap.insert_account(keccak("0").into(), &"0".into()).unwrap(); let spec = Spec::new_test_round(); let engine = &*spec.engine; @@ -1447,9 +1497,9 @@ mod tests { let last_hashes = Arc::new(vec![genesis_header.hash()]); let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); - let b1 = b1.close_and_lock(); + let b1 = b1.close_and_lock().unwrap(); let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); - let b2 = b2.close_and_lock(); + let b2 = b2.close_and_lock().unwrap(); engine.set_signer(tap.clone(), addr1, "1".into()); match engine.generate_seal(b1.block(), &genesis_header) { @@ -1469,7 +1519,7 @@ mod tests { #[test] fn proposer_switching() { let tap = AccountProvider::transient_provider(); - let addr = tap.insert_account(keccak("0").into(), "0").unwrap(); + let addr = tap.insert_account(keccak("0").into(), &"0".into()).unwrap(); let mut parent_header: Header = Header::default(); parent_header.set_seal(vec![encode(&0usize).into_vec()]); parent_header.set_gas_limit("222222".parse::().unwrap()); @@ -1480,12 +1530,15 @@ mod tests { let engine = Spec::new_test_round().engine; - let signature = tap.sign(addr, Some("0".into()), header.bare_hash()).unwrap(); // Two validators. // Spec starts with step 2. + header.set_difficulty(calculate_score(U256::from(0), U256::from(2), U256::zero())); + let signature = tap.sign(addr, Some("0".into()), header.bare_hash()).unwrap(); header.set_seal(vec![encode(&2usize).into_vec(), encode(&(&*signature as &[u8])).into_vec()]); assert!(engine.verify_block_family(&header, &parent_header).is_ok()); assert!(engine.verify_block_external(&header).is_err()); + header.set_difficulty(calculate_score(U256::from(0), U256::from(1), U256::zero())); + let signature = tap.sign(addr, Some("0".into()), header.bare_hash()).unwrap(); header.set_seal(vec![encode(&1usize).into_vec(), encode(&(&*signature as &[u8])).into_vec()]); assert!(engine.verify_block_family(&header, &parent_header).is_ok()); assert!(engine.verify_block_external(&header).is_ok()); @@ -1494,7 +1547,7 @@ mod tests { #[test] fn rejects_future_block() { let tap = AccountProvider::transient_provider(); - let addr = tap.insert_account(keccak("0").into(), "0").unwrap(); + let addr = tap.insert_account(keccak("0").into(), &"0".into()).unwrap(); let mut parent_header: Header = Header::default(); parent_header.set_seal(vec![encode(&0usize).into_vec()]); @@ -1506,9 +1559,10 @@ mod tests { let engine = Spec::new_test_round().engine; - let signature = tap.sign(addr, Some("0".into()), header.bare_hash()).unwrap(); // Two validators. // Spec starts with step 2. + header.set_difficulty(calculate_score(U256::from(0), U256::from(1), U256::zero())); + let signature = tap.sign(addr, Some("0".into()), header.bare_hash()).unwrap(); header.set_seal(vec![encode(&1usize).into_vec(), encode(&(&*signature as &[u8])).into_vec()]); assert!(engine.verify_block_family(&header, &parent_header).is_ok()); assert!(engine.verify_block_external(&header).is_ok()); @@ -1519,7 +1573,7 @@ mod tests { #[test] fn rejects_step_backwards() { let tap = AccountProvider::transient_provider(); - let addr = tap.insert_account(keccak("0").into(), "0").unwrap(); + let addr = tap.insert_account(keccak("0").into(), &"0".into()).unwrap(); let mut parent_header: Header = Header::default(); parent_header.set_seal(vec![encode(&4usize).into_vec()]); @@ -1535,8 +1589,10 @@ mod tests { // Two validators. // Spec starts with step 2. header.set_seal(vec![encode(&5usize).into_vec(), encode(&(&*signature as &[u8])).into_vec()]); + header.set_difficulty(calculate_score(U256::from(4), U256::from(5), U256::zero())); assert!(engine.verify_block_family(&header, &parent_header).is_ok()); header.set_seal(vec![encode(&3usize).into_vec(), encode(&(&*signature as &[u8])).into_vec()]); + header.set_difficulty(calculate_score(U256::from(4), U256::from(3), U256::zero())); assert!(engine.verify_block_family(&header, &parent_header).is_err()); } @@ -1570,7 +1626,7 @@ 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_difficulty(calculate_score(U256::from(1), U256::from(3), U256::zero())); header.set_gas_limit("222222".parse::().unwrap()); header.set_seal(vec![encode(&3usize).into_vec()]); @@ -1578,10 +1634,17 @@ mod tests { assert!(aura.verify_block_family(&header, &parent_header).is_ok()); assert_eq!(last_benign.load(AtomicOrdering::SeqCst), 0); - aura.set_signer(Arc::new(AccountProvider::transient_provider()), Default::default(), Default::default()); + 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] @@ -1669,8 +1732,8 @@ mod tests { let spec = Spec::new_test_round_empty_steps(); let tap = Arc::new(AccountProvider::transient_provider()); - let addr1 = tap.insert_account(keccak("1").into(), "1").unwrap(); - let addr2 = tap.insert_account(keccak("0").into(), "0").unwrap(); + let addr1 = tap.insert_account(keccak("1").into(), &"1".into()).unwrap(); + let addr2 = tap.insert_account(keccak("0").into(), &"0".into()).unwrap(); let accounts = vec![addr1, addr2]; @@ -1701,16 +1764,17 @@ mod tests { let db1 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); - let b1 = b1.close_and_lock(); - let client = generate_dummy_client(0); + let client = generate_dummy_client_with_spec_and_accounts(Spec::new_test_round_empty_steps, None); let notify = Arc::new(TestNotify::default()); client.add_notify(notify.clone()); engine.register_client(Arc::downgrade(&client) as _); engine.set_signer(tap.clone(), addr1, "1".into()); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); + let b1 = b1.close_and_lock().unwrap(); + // the block is empty so we don't seal and instead broadcast an empty step message assert_eq!(engine.generate_seal(b1.block(), &genesis_header), Seal::None); @@ -1735,9 +1799,14 @@ mod tests { let last_hashes = Arc::new(vec![genesis_header.hash()]); + let client = generate_dummy_client_with_spec_and_accounts(Spec::new_test_round_empty_steps, None); + let notify = Arc::new(TestNotify::default()); + client.add_notify(notify.clone()); + engine.register_client(Arc::downgrade(&client) as _); + // step 2 let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); - let b1 = b1.close_and_lock(); + let b1 = b1.close_and_lock().unwrap(); // since the block is empty it isn't sealed and we generate empty steps engine.set_signer(tap.clone(), addr1, "1".into()); @@ -1754,7 +1823,7 @@ mod tests { value: U256::from(1), data: vec![], }.fake_sign(addr2), None).unwrap(); - let b2 = b2.close_and_lock(); + let b2 = b2.close_and_lock().unwrap(); // we will now seal a block with 1tx and include the accumulated empty step message engine.set_signer(tap.clone(), addr2, "0".into()); @@ -1783,9 +1852,14 @@ mod tests { let last_hashes = Arc::new(vec![genesis_header.hash()]); + let client = generate_dummy_client_with_spec_and_accounts(Spec::new_test_round_empty_steps, None); + let notify = Arc::new(TestNotify::default()); + client.add_notify(notify.clone()); + engine.register_client(Arc::downgrade(&client) as _); + // step 2 let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); - let b1 = b1.close_and_lock(); + let b1 = b1.close_and_lock().unwrap(); // since the block is empty it isn't sealed and we generate empty steps engine.set_signer(tap.clone(), addr1, "1".into()); @@ -1794,7 +1868,7 @@ mod tests { // step 3 let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); - let b2 = b2.close_and_lock(); + let b2 = b2.close_and_lock().unwrap(); engine.set_signer(tap.clone(), addr2, "0".into()); assert_eq!(engine.generate_seal(b2.block(), &genesis_header), Seal::None); engine.step(); @@ -1802,7 +1876,7 @@ mod tests { // step 4 // the spec sets the maximum_empty_steps to 2 so we will now seal an empty block and include the empty step messages let b3 = OpenBlock::new(engine, Default::default(), false, db3, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); - let b3 = b3.close_and_lock(); + let b3 = b3.close_and_lock().unwrap(); engine.set_signer(tap.clone(), addr1, "1".into()); if let Seal::Regular(seal) = engine.generate_seal(b3.block(), &genesis_header) { @@ -1835,7 +1909,7 @@ mod tests { // step 2 let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); - let b1 = b1.close_and_lock(); + let b1 = b1.close_and_lock().unwrap(); // since the block is empty it isn't sealed and we generate empty steps engine.set_signer(tap.clone(), addr1, "1".into()); @@ -1848,7 +1922,7 @@ mod tests { let addr1_balance = b2.block().state().balance(&addr1).unwrap(); // after closing the block `addr1` should be reward twice, one for the included empty step message and another for block creation - let b2 = b2.close_and_lock(); + let b2 = b2.close_and_lock().unwrap(); // the spec sets the block reward to 10 assert_eq!(b2.block().state().balance(&addr1).unwrap(), addr1_balance + (10 * 2).into()) @@ -1923,16 +1997,15 @@ mod tests { let empty_step3 = sealed_empty_step(engine, 3, &parent_header.hash()); let empty_steps = vec![empty_step2, empty_step3]; + header.set_difficulty(calculate_score(U256::from(0), U256::from(4), U256::from(2))); + let signature = tap.sign(addr1, Some("1".into()), header.bare_hash()).unwrap(); header.set_seal(vec![ encode(&4usize).into_vec(), encode(&(&*signature as &[u8])).into_vec(), ::rlp::encode_list(&empty_steps).into_vec(), ]); - assert!(match engine.verify_block_family(&header, &parent_header) { - Ok(_) => true, - _ => false, - }); + assert!(engine.verify_block_family(&header, &parent_header).is_ok()); } #[test] @@ -1940,7 +2013,7 @@ mod tests { let spec = Spec::new_test_round_block_reward_contract(); let tap = Arc::new(AccountProvider::transient_provider()); - let addr1 = tap.insert_account(keccak("1").into(), "1").unwrap(); + let addr1 = tap.insert_account(keccak("1").into(), &"1".into()).unwrap(); let engine = &*spec.engine; let genesis_header = spec.genesis_header(); @@ -1969,7 +2042,7 @@ mod tests { false, &mut Vec::new().into_iter(), ).unwrap(); - let b1 = b1.close_and_lock(); + let b1 = b1.close_and_lock().unwrap(); // since the block is empty it isn't sealed and we generate empty steps engine.set_signer(tap.clone(), addr1, "1".into()); @@ -1995,7 +2068,7 @@ mod tests { // after closing the block `addr1` should be reward twice, one for the included empty step // message and another for block creation - let b2 = b2.close_and_lock(); + let b2 = b2.close_and_lock().unwrap(); // the contract rewards (1000 + kind) for each benefactor/reward kind assert_eq!( diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index e99fd88dcbcf80edd717e66e613b73eca3f02f67..e73b10461928a6523855ee8198717f20bdc9ef84 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -19,7 +19,7 @@ use std::sync::{Weak, Arc}; use ethereum_types::{H256, H520, Address}; use parking_lot::RwLock; -use ethkey::{self, Signature}; +use ethkey::{self, Password, Signature}; use account_provider::AccountProvider; use block::*; use engines::{Engine, Seal, ConstructedVerifier, EngineError}; @@ -180,7 +180,7 @@ impl Engine for BasicAuthority { self.validators.register_client(client); } - fn set_signer(&self, ap: Arc, address: Address, password: String) { + fn set_signer(&self, ap: Arc, address: Address, password: Password) { self.signer.write().set(ap, address, password); } @@ -243,7 +243,7 @@ mod tests { #[test] fn can_generate_seal() { let tap = AccountProvider::transient_provider(); - let addr = tap.insert_account(keccak("").into(), "").unwrap(); + let addr = tap.insert_account(keccak("").into(), &"".into()).unwrap(); let spec = new_test_authority(); let engine = &*spec.engine; @@ -252,7 +252,7 @@ mod tests { let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); - let b = b.close_and_lock(); + let b = b.close_and_lock().unwrap(); if let Seal::Regular(seal) = engine.generate_seal(b.block(), &genesis_header) { assert!(b.try_seal(engine, seal).is_ok()); } @@ -261,7 +261,7 @@ mod tests { #[test] fn seals_internally() { let tap = AccountProvider::transient_provider(); - let authority = tap.insert_account(keccak("").into(), "").unwrap(); + let authority = tap.insert_account(keccak("").into(), &"".into()).unwrap(); let engine = new_test_authority().engine; assert!(!engine.seals_internally().unwrap()); diff --git a/ethcore/src/engines/block_reward.rs b/ethcore/src/engines/block_reward.rs index 9a9d54e4af150318b22ae4082fe47bfb1d8044fd..7144ed78d64a2cca54dd20daddf6c680fc36be76 100644 --- a/ethcore/src/engines/block_reward.rs +++ b/ethcore/src/engines/block_reward.rs @@ -170,7 +170,7 @@ mod test { "0000000000000000000000000000000000000001".into(), (3141562.into(), 31415620.into()), vec![], - ); + ).unwrap(); let result = machine.execute_as_system( block.block_mut(), diff --git a/ethcore/src/engines/epoch.rs b/ethcore/src/engines/epoch.rs index 6975e8898b1e9a7873d9f7d834b6b7ef6766971a..53b540cabd1cec8bbdf6d3b47192d2db3565e1a7 100644 --- a/ethcore/src/engines/epoch.rs +++ b/ethcore/src/engines/epoch.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index c16203f10538610846bbf84e2d2732630b2e2222..5719e11b1264b15f3713d4138fe2692dbd555c92 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -87,7 +87,7 @@ mod tests { let genesis_header = spec.genesis_header(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::default(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); - let b = b.close_and_lock(); + let b = b.close_and_lock().unwrap(); if let Seal::Regular(seal) = engine.generate_seal(b.block(), &genesis_header) { assert!(b.try_seal(engine, seal).is_ok()); } diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 0878b4595f1d7b306fd7789274ea5d680bdf6740..8f67a039f56c9f8f48a6a1c2923cb8a69445a501 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -51,7 +51,7 @@ use snapshot::SnapshotComponents; use spec::CommonParams; use transaction::{self, UnverifiedTransaction, SignedTransaction}; -use ethkey::Signature; +use ethkey::{Password, Signature}; use parity_machine::{Machine, LocalizedMachine as Localized, TotalScoredHeader}; use ethereum_types::{H256, U256, Address}; use unexpected::{Mismatch, OutOfBounds}; @@ -322,7 +322,7 @@ pub trait Engine: Sync + Send { fn is_proposal(&self, _verified_header: &M::Header) -> bool { false } /// Register an account which signs consensus messages. - fn set_signer(&self, _account_provider: Arc, _address: Address, _password: String) {} + fn set_signer(&self, _account_provider: Arc, _address: Address, _password: Password) {} /// Sign using the EngineSigner, to be used for consensus tx signing. fn sign(&self, _hash: H256) -> Result { unimplemented!() } diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index c6025e62471f459719ea3c94383fd278b7cda0bc..f9e698307d5123e0f7c7f0d5753d990da2ef5120 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/engines/signer.rs b/ethcore/src/engines/signer.rs index d9e97fee06ecc6ebe8e6538356fff252d6df2b16..670c0959c8123e2a07da2ef517aad17f425395a8 100644 --- a/ethcore/src/engines/signer.rs +++ b/ethcore/src/engines/signer.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -18,14 +18,14 @@ use std::sync::Arc; use ethereum_types::{H256, Address}; -use ethkey::Signature; +use ethkey::{Password, Signature}; use account_provider::{self, AccountProvider}; /// Everything that an Engine needs to sign messages. pub struct EngineSigner { account_provider: Arc, address: Option
, - password: Option, + password: Option, } impl Default for EngineSigner { @@ -40,7 +40,7 @@ impl Default for EngineSigner { impl EngineSigner { /// Set up the signer to sign with given address and password. - pub fn set(&mut self, ap: Arc, address: Address, password: String) { + pub fn set(&mut self, ap: Arc, address: Address, password: Password) { self.account_provider = ap; self.address = Some(address); self.password = Some(password); diff --git a/ethcore/src/engines/tendermint/message.rs b/ethcore/src/engines/tendermint/message.rs index 17b79a80b8ca926c80fcb40b6f456beddaff567c..7d76c32a27578672f0428961df64b6f29e69d457 100644 --- a/ethcore/src/engines/tendermint/message.rs +++ b/ethcore/src/engines/tendermint/message.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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. @@ -43,7 +43,6 @@ pub struct VoteStep { pub step: Step, } - impl VoteStep { pub fn new(height: Height, view: View, step: Step) -> Self { VoteStep { height: height, view: view, step: step } @@ -253,7 +252,7 @@ mod tests { #[test] fn generate_and_verify() { let tap = Arc::new(AccountProvider::transient_provider()); - let addr = tap.insert_account(keccak("0").into(), "0").unwrap(); + let addr = tap.insert_account(keccak("0").into(), &"0".into()).unwrap(); tap.unlock_account_permanently(addr, "0".into()).unwrap(); let mi = message_info_rlp(&VoteStep::new(123, 2, Step::Precommit), Some(H256::default())); diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 52bf5ff67b8290163c858d62eba946a85b9b29f3..cc2325bed499fb0b751c9d3a5c230812609e54c1 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -37,7 +37,7 @@ use bytes::Bytes; use error::{Error, BlockError}; use header::{Header, BlockNumber, ExtendedHeader}; use rlp::Rlp; -use ethkey::{self, Message, Signature}; +use ethkey::{self, Password, Message, Signature}; use account_provider::AccountProvider; use block::*; use engines::{Engine, Seal, EngineError, ConstructedVerifier}; @@ -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 } } } @@ -359,7 +359,6 @@ impl Tendermint { && lock_change_view < self.view.load(AtomicOrdering::SeqCst) } - fn has_enough_any_votes(&self) -> bool { let step_votes = self.votes.count_round_votes(&VoteStep::new(self.height.load(AtomicOrdering::SeqCst), self.view.load(AtomicOrdering::SeqCst), *self.step.read())); self.check_above_threshold(step_votes).is_ok() @@ -678,7 +677,7 @@ impl Engine for Tendermint { } } - fn set_signer(&self, ap: Arc, address: Address, password: String) { + fn set_signer(&self, ap: Arc, address: Address, password: Password) { { self.signer.write().set(ap, address, password); } @@ -805,7 +804,7 @@ mod tests { let genesis_header = spec.genesis_header(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(spec.engine.as_ref(), Default::default(), false, db.boxed_clone(), &genesis_header, last_hashes, proposer, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); - let b = b.close(); + let b = b.close().unwrap(); if let Seal::Proposal(seal) = spec.engine.generate_seal(b.block(), &genesis_header) { (b, seal) } else { @@ -832,7 +831,7 @@ mod tests { } fn insert_and_unlock(tap: &Arc, acc: &str) -> Address { - let addr = tap.insert_account(keccak(acc).into(), acc).unwrap(); + let addr = tap.insert_account(keccak(acc).into(), &acc.into()).unwrap(); tap.unlock_account_permanently(addr, acc.into()).unwrap(); addr } diff --git a/ethcore/src/engines/tendermint/params.rs b/ethcore/src/engines/tendermint/params.rs index c1fd39eb1ca53bbb942a6ff281cae5e08f9933dc..fbd3839caddd6936a4f693ccd5040038bb6bd936 100644 --- a/ethcore/src/engines/tendermint/params.rs +++ b/ethcore/src/engines/tendermint/params.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/engines/transition.rs b/ethcore/src/engines/transition.rs index a0469b624989df492a46b7b335f32db0909c2fb2..ddc9a70628f880f3e1f1ee14516799677ed6b032 100644 --- a/ethcore/src/engines/transition.rs +++ b/ethcore/src/engines/transition.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/engines/validator_set/contract.rs b/ethcore/src/engines/validator_set/contract.rs index 00f74fd2eb4c8c6de718d7752d5428b8cc3d4e2c..e4fcc83cb80d6aab87063e299343e101ced88395 100644 --- a/ethcore/src/engines/validator_set/contract.rs +++ b/ethcore/src/engines/validator_set/contract.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -163,7 +163,7 @@ mod tests { #[test] fn reports_validators() { let tap = Arc::new(AccountProvider::transient_provider()); - let v1 = tap.insert_account(keccak("1").into(), "").unwrap(); + let v1 = tap.insert_account(keccak("1").into(), &"".into()).unwrap(); let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_contract, Some(tap.clone())); client.engine().register_client(Arc::downgrade(&client) as _); let validator_contract = "0000000000000000000000000000000000000005".parse::
().unwrap(); diff --git a/ethcore/src/engines/validator_set/mod.rs b/ethcore/src/engines/validator_set/mod.rs index d439c69c2e5c03e090443bfdb45f9a9ede98bec1..d7018d14e9a99c00be1cb4e5f2ee952010c39dea 100644 --- a/ethcore/src/engines/validator_set/mod.rs +++ b/ethcore/src/engines/validator_set/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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/multi.rs b/ethcore/src/engines/validator_set/multi.rs index 89a33abc74a6a9639a9cb489b2e2d3e634fd116e..24fb2d890bde904e89a9ae2e76f4aeefb6704e2c 100644 --- a/ethcore/src/engines/validator_set/multi.rs +++ b/ethcore/src/engines/validator_set/multi.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -158,6 +158,7 @@ mod tests { use test_helpers::{generate_dummy_client_with_spec_and_accounts, generate_dummy_client_with_spec_and_data}; use types::ids::BlockId; use ethereum_types::Address; + use verification::queue::kind::blocks::Unverified; use super::Multi; @@ -165,8 +166,8 @@ mod tests { fn uses_current_set() { let tap = Arc::new(AccountProvider::transient_provider()); let s0: Secret = keccak("0").into(); - let v0 = tap.insert_account(s0.clone(), "").unwrap(); - let v1 = tap.insert_account(keccak("1").into(), "").unwrap(); + let v0 = tap.insert_account(s0.clone(), &"".into()).unwrap(); + let v1 = tap.insert_account(keccak("1").into(), &"".into()).unwrap(); let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_multi, Some(tap)); client.engine().register_client(Arc::downgrade(&client) as _); @@ -198,7 +199,7 @@ mod tests { let sync_client = generate_dummy_client_with_spec_and_data(Spec::new_validator_multi, 0, 0, &[]); sync_client.engine().register_client(Arc::downgrade(&sync_client) as _); for i in 1..4 { - sync_client.import_block(client.block(BlockId::Number(i)).unwrap().into_inner()).unwrap(); + sync_client.import_block(Unverified::from_rlp(client.block(BlockId::Number(i)).unwrap().into_inner()).unwrap()).unwrap(); } sync_client.flush_queue(); assert_eq!(sync_client.chain_info().best_block_number, 3); diff --git a/ethcore/src/engines/validator_set/safe_contract.rs b/ethcore/src/engines/validator_set/safe_contract.rs index f132a0bf9d1e2387d068858271e9096890f7151c..adaa63f0b42d4ce7591d4b9ee22a42b5923e7e26 100644 --- a/ethcore/src/engines/validator_set/safe_contract.rs +++ b/ethcore/src/engines/validator_set/safe_contract.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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"); @@ -462,6 +458,7 @@ mod tests { use test_helpers::{generate_dummy_client_with_spec_and_accounts, generate_dummy_client_with_spec_and_data}; use super::super::ValidatorSet; use super::{ValidatorSafeContract, EVENT_NAME_HASH}; + use verification::queue::kind::blocks::Unverified; #[test] fn fetches_validators() { @@ -477,8 +474,8 @@ mod tests { fn knows_validators() { let tap = Arc::new(AccountProvider::transient_provider()); let s0: Secret = keccak("1").into(); - let v0 = tap.insert_account(s0.clone(), "").unwrap(); - let v1 = tap.insert_account(keccak("0").into(), "").unwrap(); + let v0 = tap.insert_account(s0.clone(), &"".into()).unwrap(); + let v1 = tap.insert_account(keccak("0").into(), &"".into()).unwrap(); let chain_id = Spec::new_validator_safe_contract().chain_id(); let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_safe_contract, Some(tap)); client.engine().register_client(Arc::downgrade(&client) as _); @@ -534,7 +531,7 @@ mod tests { let sync_client = generate_dummy_client_with_spec_and_data(Spec::new_validator_safe_contract, 0, 0, &[]); sync_client.engine().register_client(Arc::downgrade(&sync_client) as _); for i in 1..4 { - sync_client.import_block(client.block(BlockId::Number(i)).unwrap().into_inner()).unwrap(); + sync_client.import_block(Unverified::from_rlp(client.block(BlockId::Number(i)).unwrap().into_inner()).unwrap()).unwrap(); } sync_client.flush_queue(); assert_eq!(sync_client.chain_info().best_block_number, 3); diff --git a/ethcore/src/engines/validator_set/simple_list.rs b/ethcore/src/engines/validator_set/simple_list.rs index bb67c9778bf2606fefa3daa8ce5ff4e48873d40b..dc269600d00e4f952758e5762c69654579a1f6b0 100644 --- a/ethcore/src/engines/validator_set/simple_list.rs +++ b/ethcore/src/engines/validator_set/simple_list.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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/engines/validator_set/test.rs b/ethcore/src/engines/validator_set/test.rs index a6b89304544f336e39d63720d73d1b5decb94f5e..6459803d191fd0c7ec3b6ec5f573f20134a6157f 100644 --- a/ethcore/src/engines/validator_set/test.rs +++ b/ethcore/src/engines/validator_set/test.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/engines/vote_collector.rs b/ethcore/src/engines/vote_collector.rs index 7af66b30c5d27e91d50b821401ae02e6e3757d63..f416d0c3f726bec007fa622547e6beab0b627a14 100644 --- a/ethcore/src/engines/vote_collector.rs +++ b/ethcore/src/engines/vote_collector.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index bec749297cb6fa4e970296042a17eedd7403529b..75b2b517503fda1809d5f9fafa39649887d6d0b9 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -18,15 +18,12 @@ use std::{fmt, error}; use std::time::SystemTime; -use kvdb; 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; use snapshot::Error as SnapshotError; use engines::EngineError; use ethkey::Error as EthkeyError; @@ -207,7 +204,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(), } } @@ -237,11 +233,9 @@ error_chain! { } links { - Database(kvdb::Error, kvdb::ErrorKind) #[doc = "Database error."]; - Util(UtilError, util_error::ErrorKind) #[doc = "Error concerning a utility"]; Import(ImportError, ImportErrorKind) #[doc = "Error concerning block import." ]; } - + foreign_links { Io(IoError) #[doc = "Io create error"]; StdIo(::std::io::Error) #[doc = "Error concerning the Rust standard library's IO subsystem."]; @@ -255,12 +249,6 @@ error_chain! { } errors { - #[doc = "Client configuration error."] - Client(err: ClientError) { - description("Client configuration error.") - display("Client configuration error {}", err) - } - #[doc = "Snapshot error."] Snapshot(err: SnapshotError) { description("Snapshot error.") @@ -271,14 +259,14 @@ error_chain! { AccountProvider(err: AccountsError) { description("Accounts Provider error") display("Accounts Provider error {}", err) - } + } #[doc = "PoW hash is invalid or out of date."] PowHashInvalid { description("PoW hash is invalid or out of date.") display("PoW hash is invalid or out of date.") } - + #[doc = "The value of the nonce or mishash is invalid."] PowInvalid { description("The value of the nonce or mishash is invalid.") @@ -299,23 +287,13 @@ error_chain! { } } - /// Result of import block operation. pub type ImportResult = EthcoreResult; -impl From for Error { - fn from(err: ClientError) -> Error { - match err { - ClientError::Trie(err) => ErrorKind::Trie(err).into(), - _ => ErrorKind::Client(err).into() - } - } -} - -impl From for Error { - fn from(err: AccountsError) -> Error { +impl From for Error { + fn from(err: AccountsError) -> Error { ErrorKind::AccountProvider(err).into() - } + } } impl From<::rlp::DecoderError> for Error { @@ -329,7 +307,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/ethereum/denominations.rs b/ethcore/src/ethereum/denominations.rs index 4892770df1e9dc3324e8a58485719810040888e5..4c51932543c3b4dc7da823c39a4800f12cbb38fc 100644 --- a/ethcore/src/ethereum/denominations.rs +++ b/ethcore/src/ethereum/denominations.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -35,4 +35,3 @@ pub fn shannon() -> U256 { U256::exp10(9) } #[inline] /// 1 Wei in Wei pub fn wei() -> U256 { U256::exp10(0) } - diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 9b3945e38b1217a9e8e347ca1bc12f494ccf5c01..ca19983d3e17fe3b8f16e290ff2c14de68d46539 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -280,11 +280,18 @@ impl Engine for Arc { block_reward::apply_block_rewards(&rewards, block, &self.machine) } + #[cfg(not(feature = "miner-debug"))] fn verify_local_seal(&self, header: &Header) -> Result<(), Error> { self.verify_block_basic(header) .and_then(|_| self.verify_block_unordered(header)) } + #[cfg(feature = "miner-debug")] + fn verify_local_seal(&self, _header: &Header) -> Result<(), Error> { + warn!("Skipping seal verification, running in miner testing mode."); + Ok(()) + } + fn verify_block_basic(&self, header: &Header) -> Result<(), Error> { // check the seal fields. let seal = Seal::parse_seal(header.seal())?; @@ -535,7 +542,7 @@ mod tests { let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); - let b = b.close(); + let b = b.close().unwrap(); assert_eq!(b.state().balance(&Address::zero()).unwrap(), U256::from_str("4563918244f40000").unwrap()); } @@ -589,7 +596,7 @@ mod tests { uncle.set_author(uncle_author); b.push_uncle(uncle).unwrap(); - let b = b.close(); + let b = b.close().unwrap(); assert_eq!(b.state().balance(&Address::zero()).unwrap(), "478eae0e571ba000".into()); assert_eq!(b.state().balance(&uncle_author).unwrap(), "3cb71f51fc558000".into()); } @@ -602,7 +609,7 @@ mod tests { let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); - let b = b.close(); + let b = b.close().unwrap(); let ubi_contract: Address = "00efdd5883ec628983e9063c7d969fe268bbf310".into(); let dev_contract: Address = "00756cf8159095948496617f5fb17ed95059f536".into(); diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index 5cf6462686887be9b4c1a77e6114861641e35c54..4aab4b71ffb5201c5fbcaa92bf51647bdbbc40db 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -61,6 +61,11 @@ pub fn new_expanse<'a, T: Into>>(params: T) -> Spec { load(params.into(), include_bytes!("../../res/ethereum/expanse.json")) } +/// Create a new Tobalaba chain spec. +pub fn new_tobalaba<'a, T: Into>>(params: T) -> Spec { + load(params.into(), include_bytes!("../../res/ethereum/tobalaba.json")) +} + /// Create a new Musicoin mainnet chain spec. pub fn new_musicoin<'a, T: Into>>(params: T) -> Spec { load(params.into(), include_bytes!("../../res/ethereum/musicoin.json")) @@ -76,7 +81,7 @@ pub fn new_easthub<'a, T: Into>>(params: T) -> Spec { load(params.into(), include_bytes!("../../res/ethereum/easthub.json")) } -/// Create a new Ethereum Social mainnet chain spec ¯\_(ツ)_/¯ . +/// Create a new Ethereum Social mainnet chain spec. pub fn new_social<'a, T: Into>>(params: T) -> Spec { load(params.into(), include_bytes!("../../res/ethereum/social.json")) } @@ -101,6 +106,9 @@ pub fn new_morden<'a, T: Into>>(params: T) -> Spec { /// Create a new Foundation Frontier-era chain spec as though it never changes to Homestead. pub fn new_frontier_test() -> Spec { load(None, include_bytes!("../../res/ethereum/frontier_test.json")) } +/// Create a new Ropsten chain spec. +pub fn new_ropsten_test() -> Spec { load(None, include_bytes!("../../res/ethereum/ropsten.json")) } + /// Create a new Foundation Homestead-era chain spec as though it never changed from Frontier. pub fn new_homestead_test() -> Spec { load(None, include_bytes!("../../res/ethereum/homestead_test.json")) } diff --git a/ethcore/src/executed.rs b/ethcore/src/executed.rs index 9ffd673154de8c5c8bb66fe4ad208323c7345f2e..2dc0c041be1fbb0de45a0c86b57d1eac47da5052 100644 --- a/ethcore/src/executed.rs +++ b/ethcore/src/executed.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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 e29da093c7d3cb0f68d2b5cd05c06bd15b210cb3..b77cb050e41e9a6caf52632b308c8d5c5db88efc 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -21,11 +21,11 @@ use hash::keccak; use ethereum_types::{H256, U256, U512, Address}; use bytes::{Bytes, BytesRef}; use state::{Backend as StateBackend, State, Substate, CleanupMode}; -use machine::EthereumMachine as Machine; use error::ExecutionError; +use machine::EthereumMachine as Machine; use evm::{CallType, Finalize, FinalizationResult}; use vm::{ - self, Ext, EnvInfo, CreateContractAddress, ReturnData, CleanDustMode, ActionParams, + self, EnvInfo, CreateContractAddress, ReturnData, CleanDustMode, ActionParams, ActionValue, Schedule, }; use externalities::*; @@ -61,10 +61,12 @@ pub fn contract_address(address_scheme: CreateContractAddress, sender: &Address, stream.append(nonce); (From::from(keccak(stream.as_raw())), None) }, - CreateContractAddress::FromCodeHash => { + CreateContractAddress::FromSenderSaltAndCodeHash(salt) => { let code_hash = keccak(code); - let mut buffer = [0xffu8; 20 + 32]; - &mut buffer[20..].copy_from_slice(&code_hash[..]); + let mut buffer = [0u8; 20 + 32 + 32]; + &mut buffer[0..20].copy_from_slice(&sender[..]); + &mut buffer[20..(20+32)].copy_from_slice(&salt[..]); + &mut buffer[(20+32)..].copy_from_slice(&code_hash[..]); (From::from(keccak(&buffer[..])), Some(code_hash)) }, CreateContractAddress::FromSenderAndCodeHash => { @@ -163,32 +165,35 @@ 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, + schedule: &'a Schedule, depth: usize, static_flag: bool, } impl<'a, B: 'a + StateBackend> Executive<'a, B> { /// Basic constructor. - pub fn new(state: &'a mut State, info: &'a EnvInfo, machine: &'a Machine) -> Self { + pub fn new(state: &'a mut State, info: &'a EnvInfo, machine: &'a Machine, schedule: &'a Schedule) -> Self { Executive { state: state, info: info, machine: machine, + schedule: schedule, depth: 0, static_flag: false, } } /// Populates executive from parent properties. Increments executive depth. - pub fn from_parent(state: &'a mut State, info: &'a EnvInfo, machine: &'a Machine, parent_depth: usize, static_flag: bool) -> Self { + pub fn from_parent(state: &'a mut State, info: &'a EnvInfo, machine: &'a Machine, schedule: &'a Schedule, parent_depth: usize, static_flag: bool) -> Self { Executive { state: state, info: info, machine: machine, + schedule: schedule, depth: parent_depth + 1, static_flag: static_flag, } @@ -205,7 +210,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { static_call: bool, ) -> Externalities<'any, T, V, B> where T: Tracer, V: VMTracer { let is_static = self.static_flag || static_call; - Externalities::new(self.state, self.info, self.machine, self.depth, origin_info, substate, output, tracer, vm_tracer, is_static) + Externalities::new(self.state, self.info, self.machine, self.schedule, self.depth, origin_info, substate, output, tracer, vm_tracer, is_static) } /// This function should be used to execute transaction. @@ -244,7 +249,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { let sender = t.sender(); let nonce = self.state.nonce(&sender)?; - let schedule = self.machine.schedule(self.info.number); + let schedule = self.schedule; let base_gas_required = U256::from(t.gas_required(&schedule)); if t.gas < base_gas_required { @@ -320,7 +325,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { gas_price: t.gas_price, value: ActionValue::Transfer(t.value), code: self.state.code(address)?, - code_hash: Some(self.state.code_hash(address)?), + code_hash: self.state.code_hash(address)?, data: Some(t.data.clone()), call_type: CallType::Call, params_type: vm::ParamsType::Separate, @@ -336,7 +341,6 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { fn exec_vm( &mut self, - schedule: Schedule, params: ActionParams, unconfirmed_substate: &mut Substate, output_policy: OutputPolicy, @@ -350,19 +354,22 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { // Ordinary execution - keep VM in same thread if self.depth != depth_threshold { let vm_factory = self.state.vm_factory(); + let wasm = self.schedule.wasm.is_some(); + trace!(target: "executive", "ext.schedule.have_delegate_call: {}", self.schedule.have_delegate_call); let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call); - trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call); - let mut vm = vm_factory.create(¶ms, &schedule); + let mut vm = vm_factory.create(¶ms, wasm); return vm.exec(params, &mut ext).finalize(ext); } // Start in new thread with stack size needed up to max depth crossbeam::scope(|scope| { let vm_factory = self.state.vm_factory(); + let max_depth = self.schedule.max_depth; + let wasm = self.schedule.wasm.is_some(); let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call); - scope.builder().stack_size(::std::cmp::max(schedule.max_depth.saturating_sub(depth_threshold) * STACK_SIZE_PER_DEPTH, local_stack_size)).spawn(move || { - let mut vm = vm_factory.create(¶ms, &schedule); + scope.builder().stack_size(::std::cmp::max(max_depth.saturating_sub(depth_threshold) * STACK_SIZE_PER_DEPTH, local_stack_size)).spawn(move || { + let mut vm = vm_factory.create(¶ms, wasm); vm.exec(params, &mut ext).finalize(ext) }).expect("Sub-thread creation cannot fail; the host might run out of resources; qed") }).join() @@ -392,7 +399,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { // backup used in case of running out of gas self.state.checkpoint(); - let schedule = self.machine.schedule(self.info.number); + let schedule = self.schedule; // at first, transfer value to destination if let ActionValue::Transfer(val) = params.value { @@ -479,7 +486,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { let mut subvmtracer = vm_tracer.prepare_subtrace(params.code.as_ref().expect("scope is conditional on params.code.is_some(); qed")); let res = { - self.exec_vm(schedule, params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()), &mut subtracer, &mut subvmtracer) + self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()), &mut subtracer, &mut subvmtracer) }; vm_tracer.done_subtrace(subvmtracer); @@ -552,7 +559,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { let mut unconfirmed_substate = Substate::new(); // create contract and transfer value to it if necessary - let schedule = self.machine.schedule(self.info.number); + let schedule = self.schedule; let nonce_offset = if schedule.no_empty {1} else {0}.into(); let prev_bal = self.state.balance(¶ms.address)?; if let ActionValue::Transfer(val) = params.value { @@ -571,7 +578,6 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { let mut subvmtracer = vm_tracer.prepare_subtrace(params.code.as_ref().expect("two ways into create (Externalities::create and Executive::transact_with_tracer); both place `Some(...)` `code` in `params`; qed")); let res = self.exec_vm( - schedule, params, &mut unconfirmed_substate, OutputPolicy::InitContract(output.as_mut().or(trace_output.as_mut())), @@ -607,7 +613,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { trace: Vec, vm_trace: Option ) -> Result, ExecutionError> { - let schedule = self.machine.schedule(self.info.number); + let schedule = self.schedule; // refunds from SSTORE nonzero -> zero let sstore_refunds = U256::from(schedule.sstore_refund_gas) * substate.sstore_clears_count; @@ -756,10 +762,11 @@ mod tests { state.add_balance(&sender, &U256::from(0x100u64), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let machine = make_frontier_machine(0); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); let FinalizationResult { gas_left, .. } = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap() }; @@ -813,10 +820,11 @@ mod tests { state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let machine = make_frontier_machine(0); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); let FinalizationResult { gas_left, .. } = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap() }; @@ -855,11 +863,12 @@ mod tests { state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let machine = make_byzantium_machine(5); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); let mut tracer = ExecutiveTracer::default(); let mut vm_tracer = ExecutiveVMTracer::toplevel(); - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let output = BytesRef::Fixed(&mut[0u8;0]); ex.call(params, &mut substate, output, &mut tracer, &mut vm_tracer).unwrap(); @@ -939,12 +948,13 @@ mod tests { state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let machine = make_frontier_machine(5); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); let mut tracer = ExecutiveTracer::default(); let mut vm_tracer = ExecutiveVMTracer::toplevel(); let FinalizationResult { gas_left, .. } = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let output = BytesRef::Fixed(&mut[0u8;0]); ex.call(params, &mut substate, output, &mut tracer, &mut vm_tracer).unwrap() }; @@ -1055,12 +1065,13 @@ mod tests { state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let machine = ::ethereum::new_byzantium_test_machine(); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); let mut tracer = ExecutiveTracer::default(); let mut vm_tracer = ExecutiveVMTracer::toplevel(); let FinalizationResult { gas_left, .. } = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let output = BytesRef::Fixed(&mut[0u8;0]); ex.call(params, &mut substate, output, &mut tracer, &mut vm_tracer).unwrap() }; @@ -1127,12 +1138,13 @@ mod tests { state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let machine = make_frontier_machine(5); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); let mut tracer = ExecutiveTracer::default(); let mut vm_tracer = ExecutiveVMTracer::toplevel(); let FinalizationResult { gas_left, .. } = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); ex.create(params.clone(), &mut substate, &mut None, &mut tracer, &mut vm_tracer).unwrap() }; @@ -1214,10 +1226,11 @@ mod tests { state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let machine = make_frontier_machine(0); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); let FinalizationResult { gas_left, .. } = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap() }; @@ -1265,10 +1278,11 @@ mod tests { state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let machine = make_frontier_machine(1024); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap(); } @@ -1325,10 +1339,11 @@ mod tests { let info = EnvInfo::default(); let machine = make_frontier_machine(0); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); let FinalizationResult { gas_left, .. } = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer, &mut NoopVMTracer).unwrap() }; @@ -1369,10 +1384,11 @@ mod tests { state.init_code(&address, code).unwrap(); let info = EnvInfo::default(); let machine = make_frontier_machine(0); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); let FinalizationResult { gas_left, .. } = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer, &mut NoopVMTracer).unwrap() }; @@ -1402,9 +1418,10 @@ mod tests { let mut info = EnvInfo::default(); info.gas_limit = U256::from(100_000); let machine = make_frontier_machine(0); + let schedule = machine.schedule(info.number); let executed = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let opts = TransactOptions::with_no_tracing(); ex.transact(&t, opts).unwrap() }; @@ -1439,9 +1456,10 @@ mod tests { let mut info = EnvInfo::default(); info.gas_limit = U256::from(100_000); let machine = make_frontier_machine(0); + let schedule = machine.schedule(info.number); let res = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let opts = TransactOptions::with_no_tracing(); ex.transact(&t, opts) }; @@ -1472,9 +1490,10 @@ mod tests { info.gas_used = U256::from(20_000); info.gas_limit = U256::from(100_000); let machine = make_frontier_machine(0); + let schedule = machine.schedule(info.number); let res = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let opts = TransactOptions::with_no_tracing(); ex.transact(&t, opts) }; @@ -1505,9 +1524,10 @@ mod tests { let mut info = EnvInfo::default(); info.gas_limit = U256::from(100_000); let machine = make_frontier_machine(0); + let schedule = machine.schedule(info.number); let res = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let opts = TransactOptions::with_no_tracing(); ex.transact(&t, opts) }; @@ -1538,10 +1558,11 @@ mod tests { state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap(), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let machine = make_frontier_machine(0); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); let result = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer) }; @@ -1571,11 +1592,12 @@ mod tests { params.value = ActionValue::Transfer(U256::zero()); let info = EnvInfo::default(); let machine = ::ethereum::new_byzantium_test_machine(); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); let mut output = [0u8; 14]; let FinalizationResult { gas_left: result, .. } = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer).unwrap() }; @@ -1618,7 +1640,8 @@ mod tests { let mut output = [0u8; 20]; let FinalizationResult { gas_left: result, .. } = { - let mut ex = Executive::new(&mut state, &info, &machine); + let schedule = machine.schedule(info.number); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); ex.call(params.clone(), &mut Substate::new(), BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer).unwrap() }; @@ -1631,7 +1654,8 @@ mod tests { let mut output = [0u8; 20]; let FinalizationResult { gas_left: result, .. } = { - let mut ex = Executive::new(&mut state, &info, &machine); + let schedule = machine.schedule(info.number); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); ex.call(params, &mut Substate::new(), BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer).unwrap() }; diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 5d35d1109ae184f9aa92cfebcbc80e1ab09bf26f..68d2c0817f0e34684b99b2527ccaa797c54ee047 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -63,16 +63,14 @@ 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, depth: usize, origin_info: OriginInfo, substate: &'a mut Substate, - schedule: Schedule, + machine: &'a Machine, + schedule: &'a Schedule, output: OutputPolicy<'a, 'a>, tracer: &'a mut T, vm_tracer: &'a mut V, @@ -83,9 +81,11 @@ impl<'a, T: 'a, V: 'a, B: 'a> Externalities<'a, T, V, B> where T: Tracer, V: VMTracer, B: StateBackend { /// Basic `Externalities` constructor. - pub fn new(state: &'a mut State, + pub fn new( + state: &'a mut State, env_info: &'a EnvInfo, machine: &'a Machine, + schedule: &'a Schedule, depth: usize, origin_info: OriginInfo, substate: &'a mut Substate, @@ -97,11 +97,11 @@ impl<'a, T: 'a, V: 'a, B: 'a> Externalities<'a, T, V, B> Externalities { state: state, env_info: env_info, - machine: machine, depth: depth, origin_info: origin_info, substate: substate, - schedule: machine.schedule(env_info.number), + machine: machine, + schedule: schedule, output: output, tracer: tracer, vm_tracer: vm_tracer, @@ -165,14 +165,14 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B> gas: self.machine.params().eip210_contract_gas, gas_price: 0.into(), code: code, - code_hash: Some(code_hash), + code_hash: code_hash, data: Some(H256::from(number).to_vec()), call_type: CallType::Call, params_type: vm::ParamsType::Separate, }; let mut output = H256::new(); - let mut ex = Executive::new(self.state, self.env_info, self.machine); + let mut ex = Executive::new(self.state, self.env_info, self.machine, self.schedule); let r = ex.call(params, self.substate, BytesRef::Fixed(&mut output), self.tracer, self.vm_tracer); trace!("ext: blockhash contract({}) -> {:?}({}) self.env_info.number={}\n", number, r, output, self.env_info.number); output @@ -228,7 +228,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B> } } } - let mut ex = Executive::from_parent(self.state, self.env_info, self.machine, self.depth, self.static_flag); + let mut ex = Executive::from_parent(self.state, self.env_info, self.machine, self.schedule, self.depth, self.static_flag); // TODO: handle internal error separately match ex.create(params, self.substate, &mut None, self.tracer, self.vm_tracer) { @@ -272,7 +272,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B> gas: *gas, gas_price: self.origin_info.gas_price, code: code, - code_hash: Some(code_hash), + code_hash: code_hash, data: Some(data.to_vec()), call_type: call_type, params_type: vm::ParamsType::Separate, @@ -282,7 +282,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B> params.value = ActionValue::Transfer(value); } - let mut ex = Executive::from_parent(self.state, self.env_info, self.machine, self.depth, self.static_flag); + let mut ex = Executive::from_parent(self.state, self.env_info, self.machine, self.schedule, self.depth, self.static_flag); match ex.call(params, self.substate, BytesRef::Fixed(output), self.tracer, self.vm_tracer) { Ok(FinalizationResult{ gas_left, return_data, apply_state: true }) => MessageCallResult::Success(gas_left, return_data), @@ -291,12 +291,16 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B> } } - fn extcode(&self, address: &Address) -> vm::Result> { - Ok(self.state.code(address)?.unwrap_or_else(|| Arc::new(vec![]))) + fn extcode(&self, address: &Address) -> vm::Result>> { + Ok(self.state.code(address)?) + } + + fn extcodehash(&self, address: &Address) -> vm::Result> { + Ok(self.state.code_hash(address)?) } - fn extcodesize(&self, address: &Address) -> vm::Result { - Ok(self.state.code_size(address)?.unwrap_or(0)) + fn extcodesize(&self, address: &Address) -> vm::Result> { + Ok(self.state.code_size(address)?) } fn ret(mut self, gas: &U256, data: &ReturnData, apply_state: bool) -> vm::Result @@ -442,6 +446,7 @@ mod tests { struct TestSetup { state: State<::state_db::StateDB>, machine: ::machine::EthereumMachine, + schedule: Schedule, sub_state: Substate, env_info: EnvInfo } @@ -454,11 +459,15 @@ mod tests { impl TestSetup { fn new() -> Self { + let machine = ::spec::Spec::new_test_machine(); + let env_info = get_test_env_info(); + let schedule = machine.schedule(env_info.number); TestSetup { state: get_temp_state(), - machine: ::spec::Spec::new_test_machine(), + schedule: schedule, + machine: machine, sub_state: Substate::new(), - env_info: get_test_env_info() + env_info: env_info, } } } @@ -470,7 +479,7 @@ mod tests { let mut tracer = NoopTracer; let mut vm_tracer = NoopVMTracer; - let ext = Externalities::new(state, &setup.env_info, &setup.machine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); + let ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); assert_eq!(ext.env_info().number, 100); } @@ -482,7 +491,7 @@ mod tests { let mut tracer = NoopTracer; let mut vm_tracer = NoopVMTracer; - let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); + let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); let hash = ext.blockhash(&"0000000000000000000000000000000000000000000000000000000000120000".parse::().unwrap()); @@ -506,7 +515,7 @@ mod tests { let mut tracer = NoopTracer; let mut vm_tracer = NoopVMTracer; - let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); + let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); let hash = ext.blockhash(&"0000000000000000000000000000000000000000000000000000000000120000".parse::().unwrap()); @@ -521,7 +530,7 @@ mod tests { let mut tracer = NoopTracer; let mut vm_tracer = NoopVMTracer; - let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); + let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); let mut output = vec![]; @@ -549,7 +558,7 @@ mod tests { let mut vm_tracer = NoopVMTracer; { - let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); + let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); ext.log(log_topics, &log_data).unwrap(); } @@ -566,10 +575,51 @@ mod tests { let mut vm_tracer = NoopVMTracer; { - let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); + let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); ext.suicide(refund_account).unwrap(); } assert_eq!(setup.sub_state.suicides.len(), 1); } + + #[test] + fn can_create() { + use std::str::FromStr; + + let mut setup = TestSetup::new(); + let state = &mut setup.state; + let mut tracer = NoopTracer; + let mut vm_tracer = NoopVMTracer; + + let address = { + let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); + match ext.create(&U256::max_value(), &U256::zero(), &[], CreateContractAddress::FromSenderAndNonce) { + ContractCreateResult::Created(address, _) => address, + _ => panic!("Test create failed; expected Created, got Failed/Reverted."), + } + }; + + assert_eq!(address, Address::from_str("bd770416a3345f91e4b34576cb804a576fa48eb1").unwrap()); + } + + #[test] + fn can_create2() { + use std::str::FromStr; + + let mut setup = TestSetup::new(); + let state = &mut setup.state; + let mut tracer = NoopTracer; + let mut vm_tracer = NoopVMTracer; + + let address = { + let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); + + match ext.create(&U256::max_value(), &U256::zero(), &[], CreateContractAddress::FromSenderSaltAndCodeHash(H256::default())) { + ContractCreateResult::Created(address, _) => address, + _ => panic!("Test create failed; expected Created, got Failed/Reverted."), + } + }; + + assert_eq!(address, Address::from_str("b7c227636666831278bacdb8d7f52933b8698ab9").unwrap()); + } } diff --git a/ethcore/src/factory.rs b/ethcore/src/factory.rs index 68a15f164a6eb718f75ae32062eccc70bef93712..c6b9b0f6dd7f2467262e74f77812d05d7da6d981 100644 --- a/ethcore/src/factory.rs +++ b/ethcore/src/factory.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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 vm::{Vm, ActionParams}; use wasm::WasmInterpreter; +use keccak_hasher::KeccakHasher; const WASM_MAGIC_NUMBER: &'static [u8; 4] = b"\0asm"; @@ -29,8 +31,8 @@ pub struct VmFactory { } impl VmFactory { - pub fn create(&self, params: &ActionParams, schedule: &Schedule) -> Box { - if schedule.wasm.is_some() && params.code.as_ref().map_or(false, |code| code.len() > 4 && &code[0..4] == WASM_MAGIC_NUMBER) { + pub fn create(&self, params: &ActionParams, wasm: bool) -> Box { + if wasm && params.code.as_ref().map_or(false, |code| code.len() > 4 && &code[0..4] == WASM_MAGIC_NUMBER) { Box::new(WasmInterpreter) } else { self.evm.create(¶ms.gas) @@ -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/header.rs b/ethcore/src/header.rs index 3e9675aa35b84629d76d00b7089cea63c0188c8e..7896282fc272effdf3ab1377883319394df60195 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -43,8 +43,6 @@ pub struct ExtendedHeader { pub is_finalized: bool, /// The parent block difficulty. pub parent_total_difficulty: U256, - /// The block metadata information. - pub metadata: Option>, } /// A block header. @@ -338,7 +336,6 @@ fn change_field(hash: &mut Option, field: &mut T, value: T) where T: Pa } } - impl Decodable for Header { fn decode(r: &Rlp) -> Result { let mut blockheader = Header { @@ -419,10 +416,6 @@ impl ::parity_machine::FinalizableHeader for ExtendedHeader { fn is_finalized(&self) -> bool { self.is_finalized } } -impl ::parity_machine::WithMetadataHeader for ExtendedHeader { - fn metadata(&self) -> Option<&[u8]> { self.metadata.as_ref().map(|v| v.as_ref()) } -} - #[cfg(test)] mod tests { use rustc_hex::FromHex; diff --git a/ethcore/src/json_tests/chain.rs b/ethcore/src/json_tests/chain.rs index 89b8df4a261839b6a95cf4f0e951be0d15d57b5c..83a940fcb643f3ea3091184ebeea70bb87c2d5c8 100644 --- a/ethcore/src/json_tests/chain.rs +++ b/ethcore/src/json_tests/chain.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,20 +14,36 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::path::Path; use std::sync::Arc; use client::{EvmTestClient, Client, ClientConfig, ChainInfo, ImportBlock}; -use block::Block; use spec::Genesis; use ethjson; use miner::Miner; use io::IoChannel; +use test_helpers; +use verification::queue::kind::blocks::Unverified; -pub fn json_chain_test(json_data: &[u8]) -> Vec { +use super::HookType; + +/// Run chain jsontests on a given folder. +pub fn run_test_path(p: &Path, skip: &[&'static str], h: &mut H) { + ::json_tests::test_common::run_test_path(p, skip, json_chain_test, h) +} + +/// Run chain jsontests on a given file. +pub fn run_test_file(p: &Path, h: &mut H) { + ::json_tests::test_common::run_test_file(p, json_chain_test, h) +} + +pub fn json_chain_test(json_data: &[u8], start_stop_hook: &mut H) -> Vec { ::ethcore_logger::init_log(); let tests = ethjson::blockchain::Test::load(json_data).unwrap(); let mut failed = Vec::new(); for (name, blockchain) in tests.into_iter() { + start_stop_hook(&name, HookType::OnStart); + let mut fail = false; { let mut fail_unless = |cond: bool| if !cond && !fail { @@ -41,7 +57,7 @@ pub fn json_chain_test(json_data: &[u8]) -> Vec { let spec = { let mut spec = match EvmTestClient::spec_from_json(&blockchain.network) { - Some(spec) => (*spec).clone(), + Some(spec) => spec, None => { println!(" - {} | {:?} Ignoring tests because of missing spec", name, blockchain.network); continue; @@ -57,7 +73,7 @@ pub fn json_chain_test(json_data: &[u8]) -> Vec { }; { - let db = Arc::new(::kvdb_memorydb::create(::db::NUM_COLUMNS.unwrap_or(0))); + let db = test_helpers::new_db(); let mut config = ClientConfig::default(); config.history = 8; let client = Client::new( @@ -67,9 +83,9 @@ pub fn json_chain_test(json_data: &[u8]) -> Vec { Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); - for b in &blockchain.blocks_rlp() { - if Block::is_good(&b) { - let _ = client.import_block(b.clone()); + for b in blockchain.blocks_rlp() { + if let Ok(block) = Unverified::from_rlp(b) { + let _ = client.import_block(block); client.flush_queue(); client.import_verified_blocks(); } @@ -81,17 +97,21 @@ pub fn json_chain_test(json_data: &[u8]) -> Vec { if !fail { flushln!("ok"); } + + start_stop_hook(&name, HookType::OnStop); } println!("!!! {:?} tests from failed.", failed.len()); failed } +#[cfg(test)] mod block_tests { use super::json_chain_test; + use json_tests::HookType; - fn do_json_test(json_data: &[u8]) -> Vec { - json_chain_test(json_data) + fn do_json_test(json_data: &[u8], h: &mut H) -> Vec { + json_chain_test(json_data, h) } declare_test!{BlockchainTests_bcBlockGasLimitTest, "BlockchainTests/bcBlockGasLimitTest"} @@ -152,4 +172,3 @@ mod block_tests { declare_test!{BlockchainTests_TransitionTests_bcHomesteadToDao, "BlockchainTests/TransitionTests/bcHomesteadToDao/"} declare_test!{BlockchainTests_TransitionTests_bcHomesteadToEIP150, "BlockchainTests/TransitionTests/bcHomesteadToEIP150/"} } - diff --git a/ethcore/src/json_tests/difficulty.rs b/ethcore/src/json_tests/difficulty.rs index c0d03c810b467ef3fcd696800787274042d899ee..2647e16595fb82176826059144901d180d89a6f5 100644 --- a/ethcore/src/json_tests/difficulty.rs +++ b/ethcore/src/json_tests/difficulty.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -19,12 +19,16 @@ use header::Header; use ethereum_types::U256; use spec::Spec; -pub fn json_difficulty_test(json_data: &[u8], spec: Spec) -> Vec { +use super::HookType; + +pub fn json_difficulty_test(json_data: &[u8], spec: Spec, start_stop_hook: &mut H) -> Vec { ::ethcore_logger::init_log(); let tests = ethjson::test::DifficultyTest::load(json_data).unwrap(); let engine = &spec.engine; for (name, test) in tests.into_iter() { + start_stop_hook(&name, HookType::OnStart); + flush!(" - {}...", name); println!(" - {}...", name); @@ -42,32 +46,32 @@ pub fn json_difficulty_test(json_data: &[u8], spec: Spec) -> Vec { let expected_difficulty: U256 = test.current_difficulty.into(); assert_eq!(header.difficulty(), &expected_difficulty); flushln!("ok"); + + start_stop_hook(&name, HookType::OnStop); } vec![] } mod difficulty_test_byzantium { use super::json_difficulty_test; + use json_tests::HookType; - fn do_json_test(json_data: &[u8]) -> Vec { - json_difficulty_test(json_data, ::ethereum::new_byzantium_test()) + fn do_json_test(json_data: &[u8], h: &mut H) -> Vec { + json_difficulty_test(json_data, ::ethereum::new_byzantium_test(), h) } declare_test!{DifficultyTests_difficultyByzantium, "BasicTests/difficultyByzantium.json"} } - mod difficulty_test_foundation { use super::json_difficulty_test; use tempdir::TempDir; + use json_tests::HookType; - fn do_json_test(json_data: &[u8]) -> Vec { + fn do_json_test(json_data: &[u8], h: &mut H) -> Vec { let tempdir = TempDir::new("").unwrap(); - json_difficulty_test(json_data, ::ethereum::new_foundation(&tempdir.path())) + json_difficulty_test(json_data, ::ethereum::new_foundation(&tempdir.path()), h) } declare_test!{DifficultyTests_difficultyMainNetwork, "BasicTests/difficultyMainNetwork.json"} } - - - diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index 404b1c25e694bf503883c4fee6f42719cd1a4e8a..a8fd4b45371fd8be6e9781796e4da509e0abe03d 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::path::Path; use std::sync::Arc; use super::test_common::*; use state::{Backend as StateBackend, State, Substate}; @@ -30,11 +31,23 @@ 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; +use super::HookType; + +/// Run executive jsontests on a given folder. +pub fn run_test_path(p: &Path, skip: &[&'static str], h: &mut H) { + ::json_tests::test_common::run_test_path(p, skip, do_json_test, h) +} + +/// Run executive jsontests on a given file. +pub fn run_test_file(p: &Path, h: &mut H) { + ::json_tests::test_common::run_test_file(p, do_json_test, h) +} + #[derive(Debug, PartialEq, Clone)] struct CallCreate { data: Bytes, @@ -73,6 +86,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> TestExt<'a, T, V, B> state: &'a mut State, info: &'a EnvInfo, machine: &'a Machine, + schedule: &'a Schedule, depth: usize, origin_info: OriginInfo, substate: &'a mut Substate, @@ -80,11 +94,11 @@ 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)?, - ext: Externalities::new(state, info, machine, depth, origin_info, substate, output, tracer, vm_tracer, static_call), + ext: Externalities::new(state, info, machine, schedule, depth, origin_info, substate, output, tracer, vm_tracer, static_call), callcreates: vec![], sender: address, }) @@ -152,14 +166,18 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for TestExt<'a, T, V, B> MessageCallResult::Success(*gas, ReturnData::empty()) } - fn extcode(&self, address: &Address) -> vm::Result> { + fn extcode(&self, address: &Address) -> vm::Result>> { self.ext.extcode(address) } - fn extcodesize(&self, address: &Address) -> vm::Result { + fn extcodesize(&self, address: &Address) -> vm::Result> { self.ext.extcodesize(address) } + fn extcodehash(&self, address: &Address) -> vm::Result> { + self.ext.extcodehash(address) + } + fn log(&mut self, topics: Vec, data: &[u8]) -> vm::Result<()> { self.ext.log(topics, data) } @@ -193,20 +211,22 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for TestExt<'a, T, V, B> } } -fn do_json_test(json_data: &[u8]) -> Vec { +fn do_json_test(json_data: &[u8], h: &mut H) -> Vec { let vms = VMType::all(); vms .iter() - .flat_map(|vm| do_json_test_for(vm, json_data)) + .flat_map(|vm| do_json_test_for(vm, json_data, h)) .collect() } -fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec { +fn do_json_test_for(vm_type: &VMType, json_data: &[u8], start_stop_hook: &mut H) -> Vec { let tests = ethjson::vm::Test::load(json_data).unwrap(); let mut failed = Vec::new(); for (name, vm) in tests.into_iter() { - println!("name: {:?}", name); + start_stop_hook(&format!("{}-{}", name, vm_type), HookType::OnStart); + + info!(target: "jsontests", "name: {:?}", name); let mut fail = false; let mut fail_unless = |cond: bool, s: &str | if !cond && !fail { @@ -230,7 +250,7 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec { let out_of_gas = vm.out_of_gas(); let mut state = get_temp_state(); state.populate_from(From::from(vm.pre_state.clone())); - let info = From::from(vm.env); + let info: EnvInfo = From::from(vm.env); let machine = { let mut machine = ::ethereum::new_frontier_test_machine(); machine.set_schedule_creation_rules(Box::new(move |s, _| s.max_depth = 1)); @@ -247,10 +267,12 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec { // execute let (res, callcreates) = { + let schedule = machine.schedule(info.number); let mut ex = try_fail!(TestExt::new( &mut state, &info, &machine, + &schedule, 0, OriginInfo::from(¶ms), &mut substate, @@ -259,7 +281,7 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec { &mut tracer, &mut vm_tracer, )); - let mut evm = vm_factory.create(¶ms, &machine.schedule(0u64.into())); + let mut evm = vm_factory.create(¶ms, schedule.wasm.is_some()); let res = evm.exec(params, &mut ex); // a return in finalize will not alter callcreates let callcreates = ex.callcreates.clone(); @@ -305,10 +327,12 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec { fail_unless(Some(callcreates) == calls, "callcreates does not match"); } }; + + start_stop_hook(&format!("{}-{}", name, vm_type), HookType::OnStop); } for f in &failed { - println!("FAILED: {:?}", f); + error!("FAILED: {:?}", f); } failed diff --git a/ethcore/src/json_tests/mod.rs b/ethcore/src/json_tests/mod.rs index a0966a2d29e8856196deb60a3d41332698d91e6b..fa1c822ce2aeae8d81968c3a153ff060833b56cd 100644 --- a/ethcore/src/json_tests/mod.rs +++ b/ethcore/src/json_tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Helpers and tests for operating on jsontests. + #[macro_use] mod test_common; @@ -22,4 +24,21 @@ mod executive; mod state; mod chain; mod trie; + +#[cfg(test)] mod difficulty; + +pub use self::test_common::HookType; + +pub use self::transaction::run_test_path as run_transaction_test_path; +pub use self::transaction::run_test_file as run_transaction_test_file; +pub use self::executive::run_test_path as run_executive_test_path; +pub use self::executive::run_test_file as run_executive_test_file; +pub use self::state::run_test_path as run_state_test_path; +pub use self::state::run_test_file as run_state_test_file; +pub use self::chain::run_test_path as run_chain_test_path; +pub use self::chain::run_test_file as run_chain_test_file; +pub use self::trie::run_generic_test_path as run_generic_trie_test_path; +pub use self::trie::run_generic_test_file as run_generic_trie_test_file; +pub use self::trie::run_secure_test_path as run_secure_trie_test_path; +pub use self::trie::run_secure_test_file as run_secure_trie_test_file; diff --git a/ethcore/src/json_tests/state.rs b/ethcore/src/json_tests/state.rs index a55ab18443dad30fe20d5c56d6c58fd7fee8d224..da171697216183eee4208045809cb5bf3a415212 100644 --- a/ethcore/src/json_tests/state.rs +++ b/ethcore/src/json_tests/state.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::path::Path; use super::test_common::*; use pod_state::PodState; use trace; @@ -22,12 +23,26 @@ use ethjson; use transaction::SignedTransaction; use vm::EnvInfo; -pub fn json_chain_test(json_data: &[u8]) -> Vec { +use super::HookType; + +/// Run state jsontests on a given folder. +pub fn run_test_path(p: &Path, skip: &[&'static str], h: &mut H) { + ::json_tests::test_common::run_test_path(p, skip, json_chain_test, h) +} + +/// Run state jsontests on a given file. +pub fn run_test_file(p: &Path, h: &mut H) { + ::json_tests::test_common::run_test_file(p, json_chain_test, h) +} + +pub fn json_chain_test(json_data: &[u8], start_stop_hook: &mut H) -> Vec { ::ethcore_logger::init_log(); let tests = ethjson::state::test::Test::load(json_data).unwrap(); let mut failed = Vec::new(); for (name, test) in tests.into_iter() { + start_stop_hook(&name, HookType::OnStart); + { let multitransaction = test.transaction; let env: EnvInfo = test.env.into(); @@ -50,7 +65,7 @@ pub fn json_chain_test(json_data: &[u8]) -> Vec { let transaction: SignedTransaction = multitransaction.select(&state.indexes).into(); let result = || -> Result<_, EvmTestError> { - Ok(EvmTestClient::from_pod_state(spec, pre.clone())? + Ok(EvmTestClient::from_pod_state(&spec, pre.clone())? .transact(&env, transaction, trace::NoopTracer, trace::NoopVMTracer)) }; match result() { @@ -81,6 +96,7 @@ pub fn json_chain_test(json_data: &[u8]) -> Vec { } } + start_stop_hook(&name, HookType::OnStop); } if !failed.is_empty() { @@ -89,11 +105,13 @@ pub fn json_chain_test(json_data: &[u8]) -> Vec { failed } +#[cfg(test)] mod state_tests { use super::json_chain_test; + use json_tests::HookType; - fn do_json_test(json_data: &[u8]) -> Vec { - json_chain_test(json_data) + fn do_json_test(json_data: &[u8], h: &mut H) -> Vec { + json_chain_test(json_data, h) } declare_test!{GeneralStateTest_stAttackTest, "GeneralStateTests/stAttackTest/"} @@ -135,4 +153,3 @@ mod state_tests { declare_test!{GeneralStateTest_stZeroCallsTest, "GeneralStateTests/stZeroCallsTest/"} declare_test!{GeneralStateTest_stZeroKnowledge, "GeneralStateTests/stZeroKnowledge/"} } - diff --git a/ethcore/src/json_tests/test_common.rs b/ethcore/src/json_tests/test_common.rs index 83f6b55272d5e87e2ca6afdff3dc56e500f735a2..39b7447c7e8110b3fce6c72d289f1c8c73d1ebc0 100644 --- a/ethcore/src/json_tests/test_common.rs +++ b/ethcore/src/json_tests/test_common.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -21,7 +21,20 @@ use std::path::Path; use std::ffi::OsString; pub use ethereum_types::{H256, U256, Address}; -pub fn run_test_path(p: &Path, skip: &[&'static str], runner: fn (json_data: &[u8]) -> Vec) { +/// Indicate when to run the hook passed to test functions. +#[derive(Copy, Clone, Eq, PartialEq)] +pub enum HookType { + /// Hook to code to run on test start. + OnStart, + /// Hook to code to run on test end. + OnStop +} + +pub fn run_test_path( + p: &Path, skip: &[&'static str], + runner: fn(json_data: &[u8], start_stop_hook: &mut H) -> Vec, + start_stop_hook: &mut H +) { let path = Path::new(p); let s: HashSet = skip.iter().map(|s| { let mut os: OsString = s.into(); @@ -36,33 +49,39 @@ pub fn run_test_path(p: &Path, skip: &[&'static str], runner: fn (json_data: &[u } else { Some(e.path()) }}) { - run_test_path(&p, skip, runner) + run_test_path(&p, skip, runner, start_stop_hook) } } else { let mut path = p.to_path_buf(); path.set_extension("json"); - run_test_file(&path, runner) + run_test_file(&path, runner, start_stop_hook) } } -pub fn run_test_file(path: &Path, runner: fn (json_data: &[u8]) -> Vec) { +pub fn run_test_file( + path: &Path, + runner: fn(json_data: &[u8], start_stop_hook: &mut H) -> Vec, + start_stop_hook: &mut H +) { let mut data = Vec::new(); let mut file = File::open(&path).expect("Error opening test file"); file.read_to_end(&mut data).expect("Error reading test file"); - let results = runner(&data); + let results = runner(&data, start_stop_hook); let empty: [String; 0] = []; assert_eq!(results, empty); } +#[cfg(test)] macro_rules! test { ($name: expr, $skip: expr) => { - ::json_tests::test_common::run_test_path(::std::path::Path::new(concat!("res/ethereum/tests/", $name)), &$skip, do_json_test); + ::json_tests::test_common::run_test_path(::std::path::Path::new(concat!("res/ethereum/tests/", $name)), &$skip, do_json_test, &mut |_, _| ()); } } #[macro_export] macro_rules! declare_test { (skip => $arr: expr, $id: ident, $name: expr) => { + #[cfg(test)] #[test] #[allow(non_snake_case)] fn $id() { @@ -70,6 +89,7 @@ macro_rules! declare_test { } }; (ignore => $id: ident, $name: expr) => { + #[cfg(test)] #[ignore] #[test] #[allow(non_snake_case)] @@ -78,6 +98,7 @@ macro_rules! declare_test { } }; (heavy => $id: ident, $name: expr) => { + #[cfg(test)] #[cfg(feature = "test-heavy")] #[test] #[allow(non_snake_case)] @@ -86,6 +107,7 @@ macro_rules! declare_test { } }; ($id: ident, $name: expr) => { + #[cfg(test)] #[test] #[allow(non_snake_case)] fn $id() { diff --git a/ethcore/src/json_tests/transaction.rs b/ethcore/src/json_tests/transaction.rs index 1be4900b12605b7b827d166fc9f9d23ebd5ecc4a..af16481f41f2dd51703f6cb7248ef219396c1e11 100644 --- a/ethcore/src/json_tests/transaction.rs +++ b/ethcore/src/json_tests/transaction.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,19 +14,32 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::path::Path; use super::test_common::*; use evm; use ethjson; use rlp::Rlp; use transaction::{Action, UnverifiedTransaction, SignedTransaction}; -fn do_json_test(json_data: &[u8]) -> Vec { +/// Run transaction jsontests on a given folder. +pub fn run_test_path(p: &Path, skip: &[&'static str], h: &mut H) { + ::json_tests::test_common::run_test_path(p, skip, do_json_test, h) +} + +/// Run transaction jsontests on a given file. +pub fn run_test_file(p: &Path, h: &mut H) { + ::json_tests::test_common::run_test_file(p, do_json_test, h) +} + +fn do_json_test(json_data: &[u8], start_stop_hook: &mut H) -> Vec { let tests = ethjson::transaction::Test::load(json_data).unwrap(); let mut failed = Vec::new(); let frontier_schedule = evm::Schedule::new_frontier(); let homestead_schedule = evm::Schedule::new_homestead(); let byzantium_schedule = evm::Schedule::new_byzantium(); for (name, test) in tests.into_iter() { + start_stop_hook(&name, HookType::OnStart); + let mut fail_unless = |cond: bool, title: &str| if !cond { failed.push(name.clone()); println!("Transaction failed: {:?}: {:?}", name, title); }; let number: Option = test.block_number.map(Into::into); @@ -69,6 +82,8 @@ fn do_json_test(json_data: &[u8]) -> Vec { Action::Create => fail_unless(None == to, "create mismatch"), } } + + start_stop_hook(&name, HookType::OnStop); } for f in &failed { diff --git a/ethcore/src/json_tests/trie.rs b/ethcore/src/json_tests/trie.rs index f5803d2d372e5274f0833c6bde0e6977ee8275a2..0466c4de1f19e7b2c43be61c9378c29c860a95f6 100644 --- a/ethcore/src/json_tests/trie.rs +++ b/ethcore/src/json_tests/trie.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -16,16 +16,27 @@ use ethjson; use trie::{TrieFactory, TrieSpec}; +use ethtrie::RlpCodec; use ethereum_types::H256; use memorydb::MemoryDB; +use keccak_hasher::KeccakHasher; -fn test_trie(json: &[u8], trie: TrieSpec) -> Vec { +use super::HookType; + +pub use self::generic::run_test_path as run_generic_test_path; +pub use self::generic::run_test_file as run_generic_test_file; +pub use self::secure::run_test_path as run_secure_test_path; +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() { - let mut memdb = MemoryDB::new(); + start_stop_hook(&name, HookType::OnStart); + + let mut memdb = MemoryDB::::new(); let mut root = H256::default(); let mut t = factory.create(&mut memdb, &mut root); @@ -39,6 +50,8 @@ fn test_trie(json: &[u8], trie: TrieSpec) -> Vec { if *t.root() != test.root.into() { result.push(format!("Trie test '{:?}' failed.", name)); } + + start_stop_hook(&name, HookType::OnStop); } for i in &result { @@ -49,10 +62,23 @@ fn test_trie(json: &[u8], trie: TrieSpec) -> Vec { } mod generic { + use std::path::Path; use trie::TrieSpec; - fn do_json_test(json: &[u8]) -> Vec { - super::test_trie(json, TrieSpec::Generic) + use super::HookType; + + /// Run generic trie jsontests on a given folder. + pub fn run_test_path(p: &Path, skip: &[&'static str], h: &mut H) { + ::json_tests::test_common::run_test_path(p, skip, do_json_test, h) + } + + /// Run generic trie jsontests on a given file. + pub fn run_test_file(p: &Path, h: &mut H) { + ::json_tests::test_common::run_test_file(p, do_json_test, h) + } + + fn do_json_test(json: &[u8], h: &mut H) -> Vec { + super::test_trie(json, TrieSpec::Generic, h) } declare_test!{TrieTests_trietest, "TrieTests/trietest"} @@ -60,10 +86,23 @@ mod generic { } mod secure { + use std::path::Path; use trie::TrieSpec; - fn do_json_test(json: &[u8]) -> Vec { - super::test_trie(json, TrieSpec::Secure) + use super::HookType; + + /// Run secure trie jsontests on a given folder. + pub fn run_test_path(p: &Path, skip: &[&'static str], h: &mut H) { + ::json_tests::test_common::run_test_path(p, skip, do_json_test, h) + } + + /// Run secure trie jsontests on a given file. + pub fn run_test_file(p: &Path, h: &mut H) { + ::json_tests::test_common::run_test_file(p, do_json_test, h) + } + + fn do_json_test(json: &[u8], h: &mut H) -> Vec { + super::test_trie(json, TrieSpec::Secure, h) } declare_test!{TrieTests_hex_encoded_secure, "TrieTests/hex_encoded_securetrie_test"} diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index b1782cb1d6c16e52cea885af0d569cf804bd7219..db0aee3bcd9b03ca8c778ee3bcad2af53d1fb010 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ // along with Parity. If not, see . #![warn(missing_docs)] -#![cfg_attr(feature="benches", feature(test))] +#![cfg_attr(feature = "benches", feature(test))] //! Ethcore library //! @@ -36,7 +36,7 @@ //! curl https://sh.rustup.rs -sSf | sh //! //! # download and build parity -//! git clone https://github.com/paritytech/parity +//! git clone https://github.com/paritytech/parity-ethereum //! cd parity //! cargo build --release //! ``` @@ -49,7 +49,7 @@ //! curl https://sh.rustup.rs -sSf | sh //! //! # download and build parity -//! git clone https://github.com/paritytech/parity +//! git clone https://github.com/paritytech/parity-ethereum //! cd parity //! cargo build --release //! ``` @@ -58,26 +58,30 @@ // error_chain foreign_links. #![recursion_limit="128"] -extern crate bloomchain; +extern crate blooms_db; extern crate bn; extern crate byteorder; extern crate crossbeam; extern crate common_types as types; extern crate ethash; extern crate ethcore_bloom_journal as bloom_journal; -extern crate ethcore_crypto; +extern crate parity_crypto; extern crate ethcore_io as io; -extern crate ethcore_bytes as bytes; +extern crate parity_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; extern crate ethjson; extern crate ethkey; -extern crate hardware_wallet; + extern crate hashdb; extern crate itertools; +extern crate kvdb; +extern crate kvdb_memorydb; +extern crate kvdb_rocksdb; extern crate lru_cache; extern crate num_cpus; extern crate num; @@ -88,17 +92,15 @@ 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 triehash; +extern crate patricia_trie_ethereum as ethtrie; +extern crate triehash_ethereum as triehash; extern crate ansi_term; extern crate unexpected; -extern crate kvdb; -extern crate kvdb_memorydb; -extern crate util_error; extern crate snappy; - extern crate ethabi; extern crate rustc_hex; extern crate stats; @@ -108,9 +110,15 @@ extern crate vm; extern crate wasm; extern crate memory_cache; extern crate journaldb; -#[cfg(test)] +#[cfg(any(test, feature = "json-tests", feature = "test-helpers"))] extern crate tempdir; +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] +extern crate hardware_wallet; + +#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] +extern crate fake_hardware_wallet as hardware_wallet; + #[macro_use] extern crate ethabi_derive; #[macro_use] @@ -136,11 +144,9 @@ pub extern crate ethstore; #[macro_use] pub mod views; -#[cfg(test)] -extern crate kvdb_rocksdb; - pub mod account_provider; pub mod block; +pub mod builtin; pub mod client; pub mod db; pub mod encoded; @@ -157,16 +163,12 @@ pub mod snapshot; pub mod spec; pub mod state; pub mod state_db; -// Test helpers made public for usage outside ethcore -pub mod test_helpers; pub mod trace; pub mod verification; mod cache_manager; -mod blooms; mod pod_account; mod account_db; -mod builtin; mod externalities; mod blockchain; mod factory; @@ -174,12 +176,12 @@ mod tx_filter; #[cfg(test)] mod tests; -#[cfg(test)] -#[cfg(feature="json-tests")] -mod json_tests; -#[cfg(test)] -mod test_helpers_internal; +#[cfg(feature = "json-tests")] +pub mod json_tests; +#[cfg(any(test, feature = "test-helpers"))] +pub mod test_helpers; pub use types::*; pub use executive::contract_address; pub use evm::CreateContractAddress; +pub use blockchain::{BlockChainDB, BlockChainDBHandler}; diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index 9c6db25cbcad0de813e03e5f2918b787f08ef151..5b2170609a30ae344cce51485382bed775300de1 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -140,12 +140,13 @@ impl EthereumMachine { gas_price: 0.into(), value: ActionValue::Transfer(0.into()), code: state.code(&contract_address)?, - code_hash: Some(state.code_hash(&contract_address)?), + code_hash: state.code_hash(&contract_address)?, data: data, call_type: CallType::Call, params_type: ParamsType::Separate, }; - let mut ex = Executive::new(&mut state, &env_info, self); + let schedule = self.schedule(env_info.number); + let mut ex = Executive::new(&mut state, &env_info, self, &schedule); let mut substate = Substate::new(); let mut output = Vec::new(); if let Err(e) = ex.call(params, &mut substate, BytesRef::Flexible(&mut output), &mut NoopTracer, &mut NoopVMTracer) { @@ -309,12 +310,8 @@ impl EthereumMachine { } /// Returns new contract address generation scheme at given block number. - pub fn create_address_scheme(&self, number: BlockNumber) -> CreateContractAddress { - if number >= self.params().eip86_transition { - CreateContractAddress::FromCodeHash - } else { - CreateContractAddress::FromSenderAndNonce - } + pub fn create_address_scheme(&self, _number: BlockNumber) -> CreateContractAddress { + CreateContractAddress::FromSenderAndNonce } /// Verify a particular transaction is valid, regardless of order. @@ -472,7 +469,6 @@ fn round_block_gas_limit(gas_limit: U256, lower_limit: U256, upper_limit: U256) } } - #[cfg(test)] mod tests { use super::*; @@ -486,6 +482,25 @@ mod tests { } } + #[test] + fn should_disallow_unsigned_transactions() { + let rlp = "ea80843b9aca0083015f90948921ebb5f79e9e3920abe571004d0b1d5119c154865af3107a400080038080".into(); + let transaction: UnverifiedTransaction = ::rlp::decode(&::rustc_hex::FromHex::from_hex(rlp).unwrap()).unwrap(); + let spec = ::ethereum::new_ropsten_test(); + let ethparams = get_default_ethash_extensions(); + + let machine = EthereumMachine::with_ethash_extensions( + spec.params().clone(), + Default::default(), + ethparams, + ); + let mut header = ::header::Header::new(); + header.set_number(15); + + let res = machine.verify_transaction_basic(&transaction, &header); + assert_eq!(res, Err(transaction::Error::InvalidSignature("Crypto error (Invalid EC signature)".into()))); + } + #[test] fn ethash_gas_limit_is_multiple_of_determinant() { use ethereum_types::U256; diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 4904535a89b9373119d74bebc771818df0e0acf1..38acf9e1e50a46469b56b59274faf9da985208c8 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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,8 +25,10 @@ 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 io::IoChannel; use parking_lot::{Mutex, RwLock}; use rayon::prelude::*; use transaction::{ @@ -42,14 +45,15 @@ use block::{ClosedBlock, IsBlock, Block, SealedBlock}; use client::{ BlockChain, ChainInfo, CallContract, BlockProducer, SealedBlockImporter, Nonce }; -use client::BlockId; +use client::{BlockId, ClientIoMessage}; 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; +use ethkey::Password; /// Different possible definitions for pending transaction set. #[derive(Debug, PartialEq)] @@ -78,6 +82,17 @@ pub enum Penalization { }, } +/// Pending block preparation status. +#[derive(Debug, PartialEq)] +pub enum BlockPreparationStatus { + /// We had to prepare new pending block and the preparation succeeded. + Succeeded, + /// We had to prepare new pending block but the preparation failed. + Failed, + /// We didn't have to prepare a new block. + NotPrepared, +} + /// Initial minimal gas price. /// /// Gas price should be later overwritten externally @@ -93,7 +108,7 @@ const DEFAULT_MINIMAL_GAS_PRICE: u64 = 20_000_000_000; /// before stopping attempts to push more transactions to the block. /// This is an optimization that prevents traversing the entire pool /// in case we have only a fraction of available block gas limit left. -const MAX_SKIPPED_TRANSACTIONS: usize = 8; +const MAX_SKIPPED_TRANSACTIONS: usize = 128; /// Configures the behaviour of the miner. #[derive(Debug, PartialEq)] @@ -121,11 +136,12 @@ pub struct MinerOptions { /// will be invalid if mined. pub infinite_pending_block: bool, - /// Strategy to use for prioritizing transactions in the queue. pub tx_queue_strategy: PrioritizationStrategy, /// Simple senders penalization. pub tx_queue_penalization: Penalization, + /// Do we want to mark transactions recieved locally (e.g. RPC) as local if we don't have the sending account? + pub tx_queue_no_unfamiliar_locals: bool, /// Do we refuse to accept service transactions even if sender is certified. pub refuse_service_transactions: bool, /// Transaction pool limits. @@ -149,6 +165,7 @@ impl Default for MinerOptions { infinite_pending_block: false, tx_queue_strategy: PrioritizationStrategy::GasPriceOnly, tx_queue_penalization: Penalization::Disabled, + tx_queue_no_unfamiliar_locals: false, refuse_service_transactions: false, pool_limits: pool::Options { max_count: 8_192, @@ -159,6 +176,7 @@ impl Default for MinerOptions { minimal_gas_price: DEFAULT_MINIMAL_GAS_PRICE.into(), block_gas_limit: U256::max_value(), tx_gas_limit: U256::max_value(), + no_early_reject: false, }, } } @@ -181,7 +199,7 @@ struct SealingWork { next_allowed_reseal: Instant, next_mandatory_reseal: Instant, // block number when sealing work was last requested - last_request: u64, + last_request: Option, } impl SealingWork { @@ -197,18 +215,21 @@ 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 transaction_queue: Arc, engine: Arc, accounts: Option>, + io_channel: RwLock>>, } 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; @@ -220,10 +241,16 @@ impl Miner { } /// Creates new instance of miner Arc. - pub fn new(options: MinerOptions, gas_pricer: GasPricer, spec: &Spec, accounts: Option>) -> Self { + pub fn new( + options: MinerOptions, + gas_pricer: GasPricer, + spec: &Spec, + accounts: Option>, + ) -> Self { 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 { @@ -232,16 +259,18 @@ impl Miner { || spec.engine.seals_internally().is_some(), next_allowed_reseal: Instant::now(), next_mandatory_reseal: Instant::now() + options.reseal_max_period, - last_request: 0, + 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, engine: spec.engine.clone(), + io_channel: RwLock::new(None), } } @@ -255,12 +284,18 @@ impl Miner { minimal_gas_price, block_gas_limit: U256::max_value(), tx_gas_limit: U256::max_value(), + no_early_reject: false, }, reseal_min_period: Duration::from_secs(0), ..Default::default() }, GasPricer::new_fixed(minimal_gas_price), spec, accounts) } + /// Sets `IoChannel` + pub fn set_io_channel(&self, io_channel: IoChannel) { + *self.io_channel.write() = Some(io_channel); + } + /// Clear all pending block states pub fn clear(&self) { self.sealing.lock().queue.reset(); @@ -312,7 +347,7 @@ impl Miner { } /// Prepares new block for sealing including top transactions from queue. - fn prepare_block(&self, chain: &C) -> (ClosedBlock, Option) where + fn prepare_block(&self, chain: &C) -> Option<(ClosedBlock, Option)> where C: BlockChain + CallContract + BlockProducer + Nonce + Sync, { trace_time!("prepare_block"); @@ -340,11 +375,18 @@ impl Miner { // block not found - create it. trace!(target: "miner", "prepare_block: No existing work - making new block"); let params = self.params.read().clone(); - chain.prepare_open_block( + + match chain.prepare_open_block( params.author, params.gas_range_target, params.extra_data, - ) + ) { + Ok(block) => block, + Err(err) => { + warn!(target: "miner", "Open new block failed with error {:?}. This is likely an error in chain specificiations or on-chain consensus smart contracts.", err); + return None; + } + } } }; @@ -365,18 +407,28 @@ impl Miner { let client = self.pool_client(chain); let engine_params = self.engine.params(); - let min_tx_gas = self.engine.schedule(chain_info.best_block_number).tx_gas.into(); + let min_tx_gas: U256 = self.engine.schedule(chain_info.best_block_number).tx_gas.into(); let nonce_cap: Option = if chain_info.best_block_number + 1 >= engine_params.dust_protection_transition { Some((engine_params.nonce_cap_increment * (chain_info.best_block_number + 1)).into()) } else { None }; + // we will never need more transactions than limit divided by min gas + let max_transactions = if min_tx_gas.is_zero() { + usize::max_value() + } else { + MAX_SKIPPED_TRANSACTIONS.saturating_add(cmp::min(*open_block.block().header().gas_limit() / min_tx_gas, u64::max_value().into()).as_u64() as usize) + }; let pending: Vec> = self.transaction_queue.pending( client.clone(), - chain_info.best_block_number, - chain_info.best_block_timestamp, - nonce_cap, + pool::PendingSettings { + block_number: chain_info.best_block_number, + current_timestamp: chain_info.best_block_timestamp, + nonce_cap, + max_len: max_transactions, + ordering: miner::PendingOrdering::Priority, + } ); let took_ms = |elapsed: &Duration| { @@ -461,7 +513,13 @@ impl Miner { let elapsed = block_start.elapsed(); debug!(target: "miner", "Pushed {} transactions in {} ms", tx_count, took_ms(&elapsed)); - let block = open_block.close(); + let block = match open_block.close() { + Ok(block) => block, + Err(err) => { + warn!(target: "miner", "Closing the block failed with error {:?}. This is likely an error in chain specificiations or on-chain consensus smart contracts.", err); + return None; + } + }; { self.transaction_queue.remove(invalid_transactions.iter(), true); @@ -469,7 +527,7 @@ impl Miner { self.transaction_queue.penalize(senders_to_penalize.iter()); } - (block, original_work_hash) + Some((block, original_work_hash)) } /// Returns `true` if we should create pending block even if some other conditions are not met. @@ -478,7 +536,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. @@ -497,8 +562,10 @@ impl Miner { trace!(target: "miner", "requires_reseal: sealing enabled"); // Disable sealing if there were no requests for SEALING_TIMEOUT_IN_BLOCKS - let had_requests = best_block > sealing.last_request - && best_block - sealing.last_request <= SEALING_TIMEOUT_IN_BLOCKS; + let had_requests = sealing.last_request.map(|last_request| { + best_block > last_request + && best_block - last_request <= SEALING_TIMEOUT_IN_BLOCKS + }).unwrap_or(false); // keep sealing enabled if any of the conditions is met let sealing_enabled = self.forced_sealing() @@ -506,7 +573,6 @@ impl Miner { || self.engine.seals_internally() == Some(true) || had_requests; - let should_disable_sealing = !sealing_enabled; trace!(target: "miner", "requires_reseal: should_disable_sealing={}; forced={:?}, has_local={:?}, internal={:?}, had_requests={:?}", @@ -518,7 +584,7 @@ impl Miner { ); if should_disable_sealing { - trace!(target: "miner", "Miner sleeping (current {}, last {})", best_block, sealing.last_request); + trace!(target: "miner", "Miner sleeping (current {}, last {})", best_block, sealing.last_request.unwrap_or(0)); sealing.enabled = false; sealing.queue.reset(); false @@ -625,9 +691,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) @@ -641,17 +711,28 @@ 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; } } - /// Returns true if we had to prepare new pending block. - fn prepare_pending_block(&self, client: &C) -> bool where + /// Prepare a pending block. Returns the preparation status. + fn prepare_pending_block(&self, client: &C) -> BlockPreparationStatus where C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync, { trace!(target: "miner", "prepare_pending_block: entering"); @@ -667,28 +748,48 @@ impl Miner { } }; - if prepare_new { + let preparation_status = if prepare_new { // -------------------------------------------------------------------------- // | NOTE Code below requires sealing locks. | // | Make sure to release the locks before calling that method. | // -------------------------------------------------------------------------- - let (block, original_work_hash) = self.prepare_block(client); - self.prepare_work(block, original_work_hash); - } + match self.prepare_block(client) { + Some((block, original_work_hash)) => { + self.prepare_work(block, original_work_hash); + BlockPreparationStatus::Succeeded + }, + None => BlockPreparationStatus::Failed, + } + } else { + BlockPreparationStatus::NotPrepared + }; let best_number = client.chain_info().best_block_number; let mut sealing = self.sealing.lock(); - if sealing.last_request != best_number { + if sealing.last_request != Some(best_number) { trace!( target: "miner", "prepare_pending_block: Miner received request (was {}, now {}) - waking up.", - sealing.last_request, best_number + sealing.last_request.unwrap_or(0), best_number ); - sealing.last_request = best_number; + sealing.last_request = Some(best_number); } - // Return if we restarted - prepare_new + preparation_status + } + + /// Prepare pending block, check whether sealing is needed, and then update sealing. + fn prepare_and_update_sealing(&self, chain: &C) { + use miner::MinerService; + + // Make sure to do it after transaction is imported and lock is dropped. + // We need to create pending block and enable sealing. + if self.engine.seals_internally().unwrap_or(false) || self.prepare_pending_block(chain) == BlockPreparationStatus::NotPrepared { + // If new block has not been prepared (means we already had one) + // or Engine might be able to seal internally, + // we need to update sealing. + self.update_sealing(chain); + } } } @@ -709,12 +810,12 @@ impl miner::MinerService for Miner { self.params.write().extra_data = extra_data; } - fn set_author(&self, address: Address, password: Option) -> Result<(), AccountError> { + fn set_author(&self, address: Address, password: Option) -> Result<(), AccountError> { self.params.write().author = address; if self.engine.seals_internally().is_some() && password.is_some() { if let Some(ref ap) = self.accounts { - let password = password.unwrap_or_default(); + let password = password.unwrap_or_else(|| Password::from(String::new())); // Sign test message ap.sign(address.clone(), Some(password.clone()), Default::default())?; // Enable sealing @@ -756,12 +857,12 @@ impl miner::MinerService for Miner { transactions.into_iter().map(pool::verifier::Transaction::Unverified).collect(), ); + // -------------------------------------------------------------------------- + // | NOTE Code below requires sealing locks. | + // | Make sure to release the locks before calling that method. | + // -------------------------------------------------------------------------- if !results.is_empty() && self.options.reseal_on_external_tx && self.sealing.lock().reseal_allowed() { - // -------------------------------------------------------------------------- - // | NOTE Code below requires sealing locks. | - // | Make sure to release the locks before calling that method. | - // -------------------------------------------------------------------------- - self.update_sealing(chain); + self.prepare_and_update_sealing(chain); } results @@ -770,8 +871,9 @@ impl miner::MinerService for Miner { fn import_own_transaction( &self, chain: &C, - pending: PendingTransaction, + pending: PendingTransaction ) -> Result<(), transaction::Error> { + // note: you may want to use `import_claimed_local_transaction` instead of this one. trace!(target: "own_tx", "Importing transaction: {:?}", pending); @@ -786,19 +888,34 @@ impl miner::MinerService for Miner { // | Make sure to release the locks before calling that method. | // -------------------------------------------------------------------------- if imported.is_ok() && self.options.reseal_on_own_tx && self.sealing.lock().reseal_allowed() { - // Make sure to do it after transaction is imported and lock is droped. - // We need to create pending block and enable sealing. - if self.engine.seals_internally().unwrap_or(false) || !self.prepare_pending_block(chain) { - // If new block has not been prepared (means we already had one) - // or Engine might be able to seal internally, - // we need to update sealing. - self.update_sealing(chain); - } + self.prepare_and_update_sealing(chain); } imported } + fn import_claimed_local_transaction( + &self, + chain: &C, + pending: PendingTransaction, + trusted: bool + ) -> Result<(), transaction::Error> { + // treat the tx as local if the option is enabled, or if we have the account + let sender = pending.sender(); + let treat_as_local = trusted + || !self.options.tx_queue_no_unfamiliar_locals + || self.accounts.as_ref().map(|accts| accts.has_account(sender)).unwrap_or(false); + + if treat_as_local { + self.import_own_transaction(chain, pending) + } else { + // We want to replicate behaviour for external transactions if we're not going to treat + // this as local. This is important with regards to sealing blocks + self.import_external_transactions(chain, vec![pending.transaction.into()]) + .pop().expect("one result per tx, as in `import_own_transaction`") + } + } + fn local_transactions(&self) -> BTreeMap { self.transaction_queue.local_transactions() } @@ -807,20 +924,59 @@ impl miner::MinerService for Miner { self.transaction_queue.all_transactions() } - fn ready_transactions(&self, chain: &C) -> Vec> where + 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 C: ChainInfo + Nonce + Sync, { let chain_info = chain.chain_info(); let from_queue = || { + // We propagate transactions over the nonce cap. + // The mechanism is only to limit number of transactions in pending block + // those transactions are valid and will just be ready to be included in next block. + let nonce_cap = None; + self.transaction_queue.pending( CachedNonceClient::new(chain, &self.nonce_cache), - chain_info.best_block_number, - chain_info.best_block_timestamp, - // We propagate transactions over the nonce cap. - // The mechanism is only to limit number of transactions in pending block - // those transactions are valid and will just be ready to be included in next block. - None, + pool::PendingSettings { + block_number: chain_info.best_block_number, + current_timestamp: chain_info.best_block_timestamp, + nonce_cap, + max_len, + ordering, + }, ) }; @@ -830,6 +986,7 @@ impl miner::MinerService for Miner { .iter() .map(|signed| pool::VerifiedTransaction::from_pending_block_transaction(signed.clone())) .map(Arc::new) + .take(max_len) .collect() }, chain_info.best_block_number) }; @@ -926,14 +1083,19 @@ impl miner::MinerService for Miner { // | Make sure to release the locks before calling that method. | // -------------------------------------------------------------------------- trace!(target: "miner", "update_sealing: preparing a block"); - let (block, original_work_hash) = self.prepare_block(chain); + let (block, original_work_hash) = match self.prepare_block(chain) { + Some((block, original_work_hash)) => (block, original_work_hash), + None => return, + }; // refuse to seal the first block of the chain if it contains hard forks // which should be on by default. - if block.block().header().number() == 1 && self.engine.params().contains_bugfix_hard_fork() { - warn!("Your chain specification contains one or more hard forks which are required to be \ - on by default. Please remove these forks and start your chain again."); - return; + if block.block().header().number() == 1 { + if let Some(name) = self.engine.params().nonzero_bugfix_hard_fork() { + warn!("Your chain specification contains one or more hard forks which are required to be \ + on by default. Please remove these forks and start your chain again: {}.", name); + return; + } } match self.engine.seals_internally() { @@ -956,7 +1118,7 @@ impl miner::MinerService for Miner { } fn is_currently_sealing(&self) -> bool { - self.sealing.lock().queue.is_in_use() + self.sealing.lock().enabled } fn work_package(&self, chain: &C) -> Option<(H256, BlockNumber, u64, U256)> where @@ -986,7 +1148,7 @@ impl miner::MinerService for Miner { |b| &b.hash() == &block_hash ) { trace!(target: "miner", "Submitted block {}={}={} with seal {:?}", block_hash, b.hash(), b.header().bare_hash(), seal); - b.lock().try_seal(&*self.engine, seal).or_else(|(e, _)| { + b.lock().try_seal(&*self.engine, seal).or_else(|e| { warn!(target: "miner", "Mined solution rejected: {}", e); Err(ErrorKind::PowInvalid.into()) }) @@ -1012,14 +1174,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 @@ -1038,10 +1205,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. @@ -1055,6 +1219,40 @@ 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. + // If the io_channel is available attempt to offload culling to a separate task + // to avoid blocking chain_new_blocks + if let Some(ref channel) = *self.io_channel.read() { + let queue = self.transaction_queue.clone(); + let nonce_cache = self.nonce_cache.clone(); + let engine = self.engine.clone(); + let accounts = self.accounts.clone(); + let refuse_service_transactions = self.options.refuse_service_transactions; + + let cull = move |chain: &::client::Client| { + let client = PoolClient::new( + chain, + &nonce_cache, + &*engine, + accounts.as_ref().map(|x| &**x), + refuse_service_transactions, + ); + queue.cull(client); + }; + + if let Err(e) = channel.send(ClientIoMessage::execute(cull)) { + warn!(target: "miner", "Error queueing cull: {:?}", e); + } + } else { + self.transaction_queue.cull(client); + } + } } fn pending_state(&self, latest_block_number: BlockNumber) -> Option { @@ -1083,7 +1281,7 @@ mod tests { use rustc_hex::FromHex; use client::{TestBlockChainClient, EachBlockWith, ChainInfo, ImportSealedBlock}; - use miner::MinerService; + use miner::{MinerService, PendingOrdering}; use test_helpers::{generate_dummy_client, generate_dummy_client_with_spec_and_accounts}; use transaction::{Transaction}; @@ -1135,12 +1333,14 @@ mod tests { infinite_pending_block: false, tx_queue_penalization: Penalization::Disabled, tx_queue_strategy: PrioritizationStrategy::GasPriceOnly, + tx_queue_no_unfamiliar_locals: false, refuse_service_transactions: false, pool_limits: Default::default(), pool_verification_options: pool::verifier::Options { minimal_gas_price: 0.into(), block_gas_limit: U256::max_value(), tx_gas_limit: U256::max_value(), + no_early_reject: false, }, }, GasPricer::new_fixed(0u64.into()), @@ -1149,8 +1349,10 @@ mod tests { ) } + const TEST_CHAIN_ID: u64 = 2; + fn transaction() -> SignedTransaction { - transaction_with_chain_id(2) + transaction_with_chain_id(TEST_CHAIN_ID) } fn transaction_with_chain_id(chain_id: u64) -> SignedTransaction { @@ -1179,9 +1381,9 @@ mod tests { assert_eq!(res.unwrap(), ()); assert_eq!(miner.pending_transactions(best_block).unwrap().len(), 1); assert_eq!(miner.pending_receipts(best_block).unwrap().len(), 1); - assert_eq!(miner.ready_transactions(&client).len(), 1); + assert_eq!(miner.ready_transactions(&client, 10, PendingOrdering::Priority).len(), 1); // This method will let us know if pending block was created (before calling that method) - assert!(!miner.prepare_pending_block(&client)); + assert_eq!(miner.prepare_pending_block(&client), BlockPreparationStatus::NotPrepared); } #[test] @@ -1198,7 +1400,7 @@ mod tests { assert_eq!(res.unwrap(), ()); assert_eq!(miner.pending_transactions(best_block), None); assert_eq!(miner.pending_receipts(best_block), None); - assert_eq!(miner.ready_transactions(&client).len(), 1); + assert_eq!(miner.ready_transactions(&client, 10, PendingOrdering::Priority).len(), 1); } #[test] @@ -1217,11 +1419,58 @@ mod tests { assert_eq!(miner.pending_transactions(best_block), None); assert_eq!(miner.pending_receipts(best_block), None); // By default we use PendingSet::AlwaysSealing, so no transactions yet. - assert_eq!(miner.ready_transactions(&client).len(), 0); + assert_eq!(miner.ready_transactions(&client, 10, PendingOrdering::Priority).len(), 0); // This method will let us know if pending block was created (before calling that method) - assert!(miner.prepare_pending_block(&client)); + assert_eq!(miner.prepare_pending_block(&client), BlockPreparationStatus::Succeeded); // After pending block is created we should see a transaction. - assert_eq!(miner.ready_transactions(&client).len(), 1); + assert_eq!(miner.ready_transactions(&client, 10, PendingOrdering::Priority).len(), 1); + } + + #[test] + fn should_treat_unfamiliar_locals_selectively() { + // given + let keypair = Random.generate().unwrap(); + let client = TestBlockChainClient::default(); + let account_provider = AccountProvider::transient_provider(); + account_provider.insert_account(keypair.secret().clone(), &"".into()).expect("can add accounts to the provider we just created"); + + let miner = Miner::new( + MinerOptions { + tx_queue_no_unfamiliar_locals: true, + ..miner().options + }, + GasPricer::new_fixed(0u64.into()), + &Spec::new_test(), + Some(Arc::new(account_provider)), + ); + let transaction = transaction(); + let best_block = 0; + // when + // This transaction should not be marked as local because our account_provider doesn't have the sender + let res = miner.import_claimed_local_transaction(&client, PendingTransaction::new(transaction.clone(), None), false); + + // then + // Check the same conditions as `should_import_external_transaction` first. Behaviour should be identical. + // That is: it's treated as though we added it through `import_external_transactions` + assert_eq!(res.unwrap(), ()); + assert_eq!(miner.pending_transactions(best_block), None); + assert_eq!(miner.pending_receipts(best_block), None); + assert_eq!(miner.ready_transactions(&client, 10, PendingOrdering::Priority).len(), 0); + assert_eq!(miner.prepare_pending_block(&client), BlockPreparationStatus::Succeeded); + assert_eq!(miner.ready_transactions(&client, 10, PendingOrdering::Priority).len(), 1); + + // when - 2nd part: create a local transaction from account_provider. + // Borrow the transaction used before & sign with our generated keypair. + let local_transaction = transaction.deconstruct().0.as_unsigned().clone().sign(keypair.secret(), Some(TEST_CHAIN_ID)); + let res2 = miner.import_claimed_local_transaction(&client, PendingTransaction::new(local_transaction, None), false); + + // then - 2nd part: we add on the results from the last pending block. + // This is borrowed from `should_make_pending_block_when_importing_own_transaction` and slightly modified. + assert_eq!(res2.unwrap(), ()); + assert_eq!(miner.pending_transactions(best_block).unwrap().len(), 2); + assert_eq!(miner.pending_receipts(best_block).unwrap().len(), 2); + assert_eq!(miner.ready_transactions(&client, 10, PendingOrdering::Priority).len(), 2); + assert_eq!(miner.prepare_pending_block(&client), BlockPreparationStatus::NotPrepared); } #[test] @@ -1232,7 +1481,7 @@ mod tests { assert!(!miner.requires_reseal(1u8.into())); miner.import_external_transactions(&client, vec![transaction().into()]).pop().unwrap().unwrap(); - assert!(miner.prepare_pending_block(&client)); + assert_eq!(miner.prepare_pending_block(&client), BlockPreparationStatus::Succeeded); // Unless asked to prepare work. assert!(miner.requires_reseal(1u8.into())); } @@ -1264,8 +1513,60 @@ mod tests { fn should_fail_setting_engine_signer_without_account_provider() { let spec = Spec::new_instant; let tap = Arc::new(AccountProvider::transient_provider()); - let addr = tap.insert_account(keccak("1").into(), "").unwrap(); + let addr = tap.insert_account(keccak("1").into(), &"".into()).unwrap(); let client = generate_dummy_client_with_spec_and_accounts(spec, None); assert!(match client.miner().set_author(addr, Some("".into())) { Err(AccountError::NotFound) => true, _ => false }); } + + #[test] + fn should_mine_if_internal_sealing_is_enabled() { + let spec = Spec::new_instant(); + let miner = Miner::new_for_tests(&spec, None); + + let client = generate_dummy_client(2); + miner.update_sealing(&*client); + + assert!(miner.is_currently_sealing()); + } + + #[test] + fn should_not_mine_if_internal_sealing_is_disabled() { + let spec = Spec::new_test_round(); + let miner = Miner::new_for_tests(&spec, None); + + let client = generate_dummy_client(2); + miner.update_sealing(&*client); + + assert!(!miner.is_currently_sealing()); + } + + #[test] + fn should_not_mine_if_no_fetch_work_request() { + let spec = Spec::new_test(); + let miner = Miner::new_for_tests(&spec, None); + + let client = generate_dummy_client(2); + miner.update_sealing(&*client); + + assert!(!miner.is_currently_sealing()); + } + + #[cfg(feature = "work-notify")] + #[test] + fn should_mine_if_fetch_work_request() { + struct DummyNotifyWork; + + impl NotifyWork for DummyNotifyWork { + fn notify(&self, _pow_hash: H256, _difficulty: U256, _number: u64) { } + } + + let spec = Spec::new_test(); + let miner = Miner::new_for_tests(&spec, None); + miner.add_work_listener(Box::new(DummyNotifyWork)); + + let client = generate_dummy_client(2); + miner.update_sealing(&*client); + + assert!(miner.is_currently_sealing()); + } } diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index fbf4f11b7ad26e1ac9f36fc8f5f645df3669c47e..cc56bf01f9492cefe28b415cec1bfb124fd41447 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -23,12 +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}; @@ -45,6 +47,7 @@ use header::{BlockNumber, Header}; use receipt::{RichReceipt, Receipt}; use transaction::{self, UnverifiedTransaction, SignedTransaction, PendingTransaction}; use state::StateInfo; +use ethkey::Password; /// Provides methods to verify incoming external transactions pub trait TransactionVerifierClient: Send + Sync @@ -81,7 +84,6 @@ pub trait MinerService : Send + Sync { fn update_sealing(&self, chain: &C) where C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync; - // Notifications /// Called when blocks are imported to chain, updates transactions queue. @@ -90,7 +92,6 @@ pub trait MinerService : Send + Sync { fn chain_new_blocks(&self, chain: &C, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256], is_internal_import: bool) where C: BlockChainClient; - // Pending block /// Get a list of all pending receipts from pending block. @@ -125,7 +126,7 @@ pub trait MinerService : Send + Sync { /// Set info necessary to sign consensus messages and block authoring. /// /// On PoW password is optional. - fn set_author(&self, address: Address, password: Option) -> Result<(), ::account_provider::SignError>; + fn set_author(&self, address: Address, password: Option) -> Result<(), ::account_provider::SignError>; // Transaction Pool @@ -139,6 +140,12 @@ pub trait MinerService : Send + Sync { -> Result<(), transaction::Error> where C: BlockChainClient; + /// Imports transactions from potentially external sources, with behaviour determined + /// by the config flag `tx_queue_allow_unfamiliar_locals` + fn import_claimed_local_transaction(&self, chain: &C, transaction: PendingTransaction, trusted: bool) + -> Result<(), transaction::Error> + where C: BlockChainClient; + /// Removes transaction from the pool. /// /// Attempts to "cancel" a transaction. If it was not propagated yet (or not accepted by other peers) @@ -158,10 +165,18 @@ pub trait MinerService : Send + Sync { fn next_nonce(&self, chain: &C, address: &Address) -> U256 where C: Nonce + Sync; - /// Get a list of all ready transactions. + /// 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. - fn ready_transactions(&self, chain: &C) -> Vec> + /// If you don't need a full set of transactions, you can add `max_len` and create only a limited set of + /// transactions. + fn ready_transactions(&self, chain: &C, max_len: usize, ordering: PendingOrdering) -> Vec> where C: ChainInfo + Nonce + Sync; /// Get a list of all transactions in the pool (some of them might not be ready for inclusion yet). diff --git a/ethcore/src/miner/pool_client.rs b/ethcore/src/miner/pool_client.rs index dfcdec684f8d23b2d92f08927fb7adcadabf6d13..25d9a809cdb3502b4e2310b8b41b4d4338d16c22 100644 --- a/ethcore/src/miner/pool_client.rs +++ b/ethcore/src/miner/pool_client.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -16,8 +16,11 @@ //! Blockchain access for transaction pool. -use std::fmt; -use std::collections::HashMap; +use std::{ + collections::HashMap, + fmt, + sync::Arc, +}; use ethereum_types::{H256, U256, Address}; use ethcore_miner::pool; @@ -36,10 +39,32 @@ use header::Header; use miner; use miner::service_transaction_checker::ServiceTransactionChecker; -type NoncesCache = RwLock>; +/// Cache for state nonces. +#[derive(Debug, Clone)] +pub struct NonceCache { + nonces: Arc>>, + limit: usize +} + +impl NonceCache { + /// Create new cache with a limit of `limit` entries. + pub fn new(limit: usize) -> Self { + NonceCache { + nonces: Arc::new(RwLock::new(HashMap::with_capacity(limit / 2))), + limit, + } + } -const MAX_NONCE_CACHE_SIZE: usize = 4096; -const EXPECTED_NONCE_CACHE_SIZE: usize = 2048; + /// Retrieve a cached nonce for given sender. + pub fn get(&self, sender: &Address) -> Option { + self.nonces.read().get(sender).cloned() + } + + /// 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 +95,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, @@ -124,7 +149,7 @@ impl<'a, C: 'a> pool::client::Client for PoolClient<'a, C> where pool::client::AccountDetails { nonce: self.cached_nonces.account_nonce(address), balance: self.chain.latest_balance(address), - is_local: self.accounts.map_or(false, |accounts| accounts.has_account(*address).unwrap_or(false)), + is_local: self.accounts.map_or(false, |accounts| accounts.has_account(*address)), } } @@ -161,7 +186,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 +201,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 +220,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/service_transaction_checker.rs b/ethcore/src/miner/service_transaction_checker.rs index f085564d222e008dbca67f50e42845e6dd7fd9c9..adae0c36ea8bd0352ae421dd59c5694af308f9d3 100644 --- a/ethcore/src/miner/service_transaction_checker.rs +++ b/ethcore/src/miner/service_transaction_checker.rs @@ -1,4 +1,4 @@ -// Copyright 2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -12,7 +12,7 @@ // 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 . +// along with Parity. If not, see . //! A service transactions contract checker. diff --git a/ethcore/src/miner/stratum.rs b/ethcore/src/miner/stratum.rs index c63124dcd08283b6507a01f7c9fab27e09d4005a..ca74432790fced07a17f40b74d1345abb08024ce 100644 --- a/ethcore/src/miner/stratum.rs +++ b/ethcore/src/miner/stratum.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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; @@ -111,7 +113,6 @@ pub struct StratumJobDispatcher { miner: Weak, } - impl JobDispatcher for StratumJobDispatcher { fn initial(&self) -> Option { // initial payload may contain additional data, not in this case @@ -157,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, } @@ -210,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"); @@ -243,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 027e2765fff2074f6c9412e86e3869af584a5334..f35f0517780c3af2e25aef9a0ccd9e8d2e81c8fd 100644 --- a/ethcore/src/pod_account.rs +++ b/ethcore/src/pod_account.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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); } _ => {} @@ -165,7 +167,6 @@ pub fn diff_pod(pre: Option<&PodAccount>, post: Option<&PodAccount>) -> Option 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 a47c504d8f5b9b3c8b592ce7041145c83915836c..3a18015e0c5972a453bad9dbdac64a695f37dd8d 100644 --- a/ethcore/src/snapshot/block.rs +++ b/ethcore/src/snapshot/block.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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 38d2c184ca1b7ce79c1fe6f93f0712f03d312213..72d828643dd63b0aeccf4c9f7d0b2d5d068c7211 100644 --- a/ethcore/src/snapshot/consensus/authority.rs +++ b/ethcore/src/snapshot/consensus/authority.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -24,7 +24,7 @@ use super::{SnapshotComponents, Rebuilder, ChunkSink}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; -use blockchain::{BlockChain, BlockProvider}; +use blockchain::{BlockChain, BlockChainDB, BlockProvider}; use engines::{EthEngine, EpochVerifier, EpochTransition}; use machine::EthereumMachine; use ids::BlockId; @@ -37,6 +37,8 @@ use rlp::{RlpStream, Rlp}; use ethereum_types::{H256, U256}; use kvdb::KeyValueDB; use bytes::Bytes; +use encoded; + /// Snapshot creation and restoration for PoA chains. /// Chunk format: @@ -125,14 +127,14 @@ impl SnapshotComponents for PoaSnapshot { fn rebuilder( &self, chain: BlockChain, - db: Arc, + db: Arc, manifest: &ManifestData, ) -> Result, ::error::Error> { Ok(Box::new(ChunkRebuilder { manifest: manifest.clone(), warp_target: None, chain: chain, - db: db, + db: db.key_value().clone(), had_genesis: false, unverified_firsts: Vec::new(), last_epochs: Vec::new(), @@ -338,7 +340,7 @@ impl Rebuilder for ChunkRebuilder { let parent_td: U256 = last_rlp.val_at(4)?; let mut batch = self.db.transaction(); - self.chain.insert_unordered_block(&mut batch, &block_data, receipts, Some(parent_td), true, false); + self.chain.insert_unordered_block(&mut batch, encoded::Block::new(block_data), receipts, Some(parent_td), true, false); self.db.write_buffered(batch); self.warp_target = Some(block.header); diff --git a/ethcore/src/snapshot/consensus/mod.rs b/ethcore/src/snapshot/consensus/mod.rs index 712c245ff37d1ca1cf4f763c3c1e971dc3dc24cb..7b6b03a3ee290aa83341b02ac50b50cc75d9c988 100644 --- a/ethcore/src/snapshot/consensus/mod.rs +++ b/ethcore/src/snapshot/consensus/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -20,12 +20,11 @@ use std::sync::atomic::AtomicBool; use std::sync::Arc; -use blockchain::BlockChain; +use blockchain::{BlockChain, BlockChainDB}; use engines::EthEngine; use snapshot::{Error, ManifestData}; use ethereum_types::H256; -use kvdb::KeyValueDB; mod authority; mod work; @@ -63,7 +62,7 @@ pub trait SnapshotComponents: Send { fn rebuilder( &self, chain: BlockChain, - db: Arc, + db: Arc, manifest: &ManifestData, ) -> Result, ::error::Error>; @@ -74,7 +73,6 @@ pub trait SnapshotComponents: Send { fn current_version(&self) -> u64; } - /// Restore from secondary snapshot chunks. pub trait Rebuilder: Send { /// Feed a chunk, potentially out of order. diff --git a/ethcore/src/snapshot/consensus/work.rs b/ethcore/src/snapshot/consensus/work.rs index b71f7b9d1da5ab6657c74b594bb6eff10e6e226f..ded004fe89f85d22acaea5d8b72b50eb4238c486 100644 --- a/ethcore/src/snapshot/consensus/work.rs +++ b/ethcore/src/snapshot/consensus/work.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -26,7 +26,7 @@ use std::collections::VecDeque; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; -use blockchain::{BlockChain, BlockProvider}; +use blockchain::{BlockChain, BlockChainDB, BlockProvider}; use engines::EthEngine; use snapshot::{Error, ManifestData}; use snapshot::block::AbridgedBlock; @@ -35,6 +35,7 @@ use kvdb::KeyValueDB; use bytes::Bytes; use rlp::{RlpStream, Rlp}; use rand::OsRng; +use encoded; /// Snapshot creation and restoration for PoW chains. /// This includes blocks from the head of the chain as a @@ -78,10 +79,10 @@ impl SnapshotComponents for PowSnapshot { fn rebuilder( &self, chain: BlockChain, - db: Arc, + db: Arc, manifest: &ManifestData, ) -> Result, ::error::Error> { - PowRebuilder::new(chain, db, manifest, self.max_restore_blocks).map(|r| Box::new(r) as Box<_>) + PowRebuilder::new(chain, db.key_value().clone(), manifest, self.max_restore_blocks).map(|r| Box::new(r) as Box<_>) } fn min_supported_version(&self) -> u64 { ::snapshot::MIN_SUPPORTED_STATE_CHUNK_VERSION } @@ -220,7 +221,6 @@ impl Rebuilder for PowRebuilder { /// Feed the rebuilder an uncompressed block chunk. /// Returns the number of blocks fed or any errors. fn feed(&mut self, chunk: &[u8], engine: &EthEngine, abort_flag: &AtomicBool) -> Result<(), ::error::Error> { - use views::BlockView; use snapshot::verify_old_block; use ethereum_types::U256; use triehash::ordered_trie_root; @@ -250,7 +250,7 @@ impl Rebuilder for PowRebuilder { let receipts_root = ordered_trie_root(pair.at(1)?.iter().map(|r| r.as_raw())); let block = abridged_block.to_block(parent_hash, cur_number, receipts_root)?; - let block_bytes = block.rlp_bytes(); + let block_bytes = encoded::Block::new(block.rlp_bytes()); let is_best = cur_number == self.best_number; if is_best { @@ -275,16 +275,16 @@ impl Rebuilder for PowRebuilder { // special-case the first block in each chunk. if idx == 3 { - if self.chain.insert_unordered_block(&mut batch, &block_bytes, receipts, Some(parent_total_difficulty), is_best, false) { + if self.chain.insert_unordered_block(&mut batch, block_bytes, receipts, Some(parent_total_difficulty), is_best, false) { self.disconnected.push((cur_number, block.header.hash())); } } else { - self.chain.insert_unordered_block(&mut batch, &block_bytes, receipts, None, is_best, false); + self.chain.insert_unordered_block(&mut batch, block_bytes, receipts, None, is_best, false); } self.db.write_buffered(batch); self.chain.commit(); - parent_hash = view!(BlockView, &block_bytes).hash(); + parent_hash = block.header.hash(); cur_number += 1; } diff --git a/ethcore/src/snapshot/error.rs b/ethcore/src/snapshot/error.rs index 2741f648a2b917f65ce602c7f53725d61c611fc4..527b4e2882c8a0001b6b9f1be1f67ef3696d97ab 100644 --- a/ethcore/src/snapshot/error.rs +++ b/ethcore/src/snapshot/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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/io.rs b/ethcore/src/snapshot/io.rs index 84faa19b4851405593513ba333e3162d1e9608c4..7d2cbcf92cf5d1a9def5b7082db038f3247aec27 100644 --- a/ethcore/src/snapshot/io.rs +++ b/ethcore/src/snapshot/io.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -214,7 +214,6 @@ impl PackedReader { return Ok(None); } - file.seek(SeekFrom::End(-8))?; let mut off_bytes = [0u8; 8]; diff --git a/ethcore/src/snapshot/mod.rs b/ethcore/src/snapshot/mod.rs index 8871ced26fae1f116a57fc916797ff57a79600b3..03f2eebfbf7a6a29835e224d30ffe35aa0cf4e50 100644 --- a/ethcore/src/snapshot/mod.rs +++ b/ethcore/src/snapshot/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Snapshot creation, restoration, and network service. //! //! Documentation of the format can be found at -//! https://github.com/paritytech/parity/wiki/Warp-Sync-Snapshot-Format +//! https://wiki.parity.io/Warp-Sync-Snapshot-Format use std::collections::{HashMap, HashSet}; use std::sync::Arc; @@ -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 942015d0f106ce157cc047549095d61448692ede..2e76153cff4fbf983c2b6a622f27366fe9508e29 100644 --- a/ethcore/src/snapshot/service.rs +++ b/ethcore/src/snapshot/service.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -26,7 +26,7 @@ use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use super::{ManifestData, StateRebuilder, Rebuilder, RestorationStatus, SnapshotService, MAX_CHUNK_SIZE}; use super::io::{SnapshotReader, LooseReader, SnapshotWriter, LooseWriter}; -use blockchain::BlockChain; +use blockchain::{BlockChain, BlockChainDB, BlockChainDBHandler}; use client::{Client, ChainInfo, ClientIoMessage}; use engines::EthEngine; use error::Error; @@ -37,10 +37,8 @@ use io::IoChannel; use ethereum_types::H256; use parking_lot::{Mutex, RwLock, RwLockReadGuard}; -use util_error::UtilError; use bytes::Bytes; use journaldb::Algorithm; -use kvdb::{KeyValueDB, KeyValueDBHandler}; use snappy; /// Helper for removing directories in case of error. @@ -80,13 +78,13 @@ struct Restoration { snappy_buffer: Bytes, final_state_root: H256, guard: Guard, - db: Arc, + db: Arc, } struct RestorationParams<'a> { manifest: ManifestData, // manifest to base restoration on. pruning: Algorithm, // pruning algorithm for the database. - db: Arc, // database + db: Arc, // database writer: Option, // writer for recovered snapshot. genesis: &'a [u8], // genesis block of the chain. guard: Guard, // guard for the restoration directory. @@ -115,7 +113,7 @@ impl Restoration { manifest: manifest, state_chunks_left: state_chunks, block_chunks_left: block_chunks, - state: StateRebuilder::new(raw_db.clone(), params.pruning), + state: StateRebuilder::new(raw_db.key_value().clone(), params.pruning), secondary: secondary, writer: params.writer, snappy_buffer: Vec::new(), @@ -213,7 +211,7 @@ pub struct ServiceParams { /// State pruning algorithm. pub pruning: Algorithm, /// Handler for opening a restoration DB. - pub restoration_db_handler: Box, + pub restoration_db_handler: Box, /// Async IO channel for sending messages. pub channel: Channel, /// The directory to put snapshots in. @@ -227,7 +225,7 @@ pub struct ServiceParams { /// This controls taking snapshots and restoring from them. pub struct Service { restoration: Mutex>, - restoration_db_handler: Box, + restoration_db_handler: Box, snapshot_root: PathBuf, io_channel: Mutex, pruning: Algorithm, @@ -622,7 +620,7 @@ impl Service { match is_done { true => { - db.flush().map_err(UtilError::from)?; + db.key_value().flush()?; drop(db); return self.finalize_restoration(&mut *restoration); }, @@ -635,7 +633,10 @@ impl Service { } } }; - result.and_then(|_| db.flush().map_err(|e| UtilError::from(e).into())) + + result?; + db.key_value().flush()?; + Ok(()) } /// Feed a state chunk to be processed synchronously. @@ -766,7 +767,7 @@ mod tests { use snapshot::{ManifestData, RestorationStatus, SnapshotService}; use super::*; use tempdir::TempDir; - use test_helpers_internal::restoration_db_handler; + use test_helpers::restoration_db_handler; struct NoopDBRestore; impl DatabaseRestore for NoopDBRestore { diff --git a/ethcore/src/snapshot/tests/helpers.rs b/ethcore/src/snapshot/tests/helpers.rs index 067a3abab07c6665e457ba928c63d8516f3545c1..19f50e94690fe80054a0d3933adb6a81e9e06f63 100644 --- a/ethcore/src/snapshot/tests/helpers.rs +++ b/ethcore/src/snapshot/tests/helpers.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -24,7 +24,7 @@ use hash::{KECCAK_NULL_RLP}; use account_db::AccountDBMut; use basic_account::BasicAccount; -use blockchain::BlockChain; +use blockchain::{BlockChain, BlockChainDB}; use client::{Client, ChainInfo}; use engines::EthEngine; use snapshot::{StateRebuilder}; @@ -33,11 +33,13 @@ use snapshot::io::{SnapshotReader, PackedWriter, PackedReader}; use tempdir::TempDir; use rand::Rng; -use kvdb::{KeyValueDB, DBValue}; +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() { @@ -158,7 +160,7 @@ pub fn snap(client: &Client) -> (Box, TempDir) { /// Restore a snapshot into a given database. This will read chunks from the given reader /// write into the given database. pub fn restore( - db: Arc, + db: Arc, engine: &EthEngine, reader: &SnapshotReader, genesis: &[u8], @@ -170,7 +172,7 @@ pub fn restore( let components = engine.snapshot_components().unwrap(); let manifest = reader.manifest(); - let mut state = StateRebuilder::new(db.clone(), journaldb::Algorithm::Archive); + let mut state = StateRebuilder::new(db.key_value().clone(), journaldb::Algorithm::Archive); let mut secondary = { let chain = BlockChain::new(Default::default(), genesis, db.clone()); components.rebuilder(chain, db, manifest).unwrap() diff --git a/ethcore/src/snapshot/tests/mod.rs b/ethcore/src/snapshot/tests/mod.rs index 6e9398356a02745ace4448072de4979996409bc2..c09f2b965c71ad9d7c3e9ea05f8df50ea2967b9f 100644 --- a/ethcore/src/snapshot/tests/mod.rs +++ b/ethcore/src/snapshot/tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/snapshot/tests/proof_of_authority.rs b/ethcore/src/snapshot/tests/proof_of_authority.rs index 4b1b3d6ad0e46a72c86c5fdb127bd7c35804e4a7..aefb3d2f992f0e21d770c0bc20ea7b0a001e657e 100644 --- a/ethcore/src/snapshot/tests/proof_of_authority.rs +++ b/ethcore/src/snapshot/tests/proof_of_authority.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -30,7 +30,7 @@ use transaction::{Transaction, Action, SignedTransaction}; use tempdir::TempDir; use ethereum_types::Address; -use kvdb_memorydb; +use test_helpers; use_contract!(test_validator_set, "ValidatorSet", "res/contracts/test_validator_set.json"); @@ -52,7 +52,6 @@ lazy_static! { static ref RICH_SECRET: Secret = secret!("1"); } - /// Contract code used here: https://gist.github.com/anonymous/2a43783647e0f0dfcc359bd6fd81d6d9 /// Account with secrets keccak("1") is initially the validator. /// Transitions to the contract at block 2, initially same validator set. @@ -72,7 +71,7 @@ fn make_accounts(secrets: &[Secret]) -> (Arc, Vec
) { let addrs = secrets.iter() .cloned() - .map(|s| provider.insert_account(s, PASS).unwrap()) + .map(|s| provider.insert_account(s, &PASS.into()).unwrap()) .collect(); (Arc::new(provider), addrs) @@ -215,7 +214,7 @@ fn fixed_to_contract_only() { secret!("dog42"), ]); - assert!(provider.has_account(*RICH_ADDR).unwrap()); + assert!(provider.has_account(*RICH_ADDR)); let client = make_chain(provider, 3, vec![ Transition::Manual(3, vec![addrs[2], addrs[3], addrs[5], addrs[7]]), @@ -227,12 +226,12 @@ fn fixed_to_contract_only() { assert_eq!(client.chain_info().best_block_number, 11); let (reader, _tempdir) = snapshot_helpers::snap(&*client); - let new_db = kvdb_memorydb::create(::db::NUM_COLUMNS.unwrap_or(0)); + let new_db = test_helpers::new_db(); let spec = spec_fixed_to_contract(); // ensure fresh engine's step matches. for _ in 0..11 { spec.engine.step() } - snapshot_helpers::restore(Arc::new(new_db), &*spec.engine, &*reader, &spec.genesis_block()).unwrap(); + snapshot_helpers::restore(new_db, &*spec.engine, &*reader, &spec.genesis_block()).unwrap(); } #[test] @@ -248,7 +247,7 @@ fn fixed_to_contract_to_contract() { secret!("dog42"), ]); - assert!(provider.has_account(*RICH_ADDR).unwrap()); + assert!(provider.has_account(*RICH_ADDR)); let client = make_chain(provider, 3, vec![ Transition::Manual(3, vec![addrs[2], addrs[3], addrs[5], addrs[7]]), @@ -259,9 +258,9 @@ fn fixed_to_contract_to_contract() { assert_eq!(client.chain_info().best_block_number, 16); let (reader, _tempdir) = snapshot_helpers::snap(&*client); - let new_db = kvdb_memorydb::create(::db::NUM_COLUMNS.unwrap_or(0)); + let new_db = test_helpers::new_db(); let spec = spec_fixed_to_contract(); for _ in 0..16 { spec.engine.step() } - snapshot_helpers::restore(Arc::new(new_db), &*spec.engine, &*reader, &spec.genesis_block()).unwrap(); + snapshot_helpers::restore(new_db, &*spec.engine, &*reader, &spec.genesis_block()).unwrap(); } diff --git a/ethcore/src/snapshot/tests/proof_of_work.rs b/ethcore/src/snapshot/tests/proof_of_work.rs index 3c3b47ce9c54e1e60833e6c7e1b7346de1665a9b..2572699682f0f5d3b63c782f48dfa2927b68f44f 100644 --- a/ethcore/src/snapshot/tests/proof_of_work.rs +++ b/ethcore/src/snapshot/tests/proof_of_work.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -16,7 +16,6 @@ //! PoW block chunker and rebuilder tests. -use std::sync::Arc; use std::sync::atomic::AtomicBool; use tempdir::TempDir; use error::{Error, ErrorKind}; @@ -28,8 +27,8 @@ use snapshot::io::{PackedReader, PackedWriter, SnapshotReader, SnapshotWriter}; use parking_lot::Mutex; use snappy; -use kvdb::{KeyValueDB, DBTransaction}; -use kvdb_memorydb; +use kvdb::DBTransaction; +use test_helpers; const SNAPSHOT_MODE: ::snapshot::PowSnapshot = ::snapshot::PowSnapshot { blocks: 30000, max_restore_blocks: 30000 }; @@ -43,21 +42,20 @@ fn chunk_and_restore(amount: u64) { let tempdir = TempDir::new("").unwrap(); let snapshot_path = tempdir.path().join("SNAP"); - let old_db = Arc::new(kvdb_memorydb::create(::db::NUM_COLUMNS.unwrap_or(0))); - let bc = BlockChain::new(Default::default(), &genesis.encoded(), old_db.clone()); + let old_db = test_helpers::new_db(); + let bc = BlockChain::new(Default::default(), genesis.encoded().raw(), old_db.clone()); // build the blockchain. let mut batch = DBTransaction::new(); for block in generator { - bc.insert_block(&mut batch, &block.encoded(), vec![], ExtrasInsert { + bc.insert_block(&mut batch, block.encoded(), vec![], ExtrasInsert { fork_choice: ::engines::ForkChoice::New, is_finalized: false, - metadata: None, }); bc.commit(); } - old_db.write(batch).unwrap(); + old_db.key_value().write(batch).unwrap(); let best_hash = bc.best_block_hash(); @@ -83,8 +81,8 @@ fn chunk_and_restore(amount: u64) { writer.into_inner().finish(manifest.clone()).unwrap(); // restore it. - let new_db = Arc::new(kvdb_memorydb::create(::db::NUM_COLUMNS.unwrap_or(0))); - let new_chain = BlockChain::new(Default::default(), &genesis.encoded(), new_db.clone()); + let new_db = test_helpers::new_db(); + let new_chain = BlockChain::new(Default::default(), genesis.encoded().raw(), new_db.clone()); let mut rebuilder = SNAPSHOT_MODE.rebuilder(new_chain, new_db.clone(), &manifest).unwrap(); let reader = PackedReader::new(&snapshot_path).unwrap().unwrap(); @@ -99,7 +97,7 @@ fn chunk_and_restore(amount: u64) { drop(rebuilder); // and test it. - let new_chain = BlockChain::new(Default::default(), &genesis.encoded(), new_db); + let new_chain = BlockChain::new(Default::default(), genesis.encoded().raw(), new_db); assert_eq!(new_chain.best_block_hash(), best_hash); } @@ -129,9 +127,9 @@ fn checks_flag() { let genesis = BlockBuilder::genesis(); let chunk = stream.out(); - let db = Arc::new(kvdb_memorydb::create(::db::NUM_COLUMNS.unwrap_or(0))); + let db = test_helpers::new_db(); let engine = ::spec::Spec::new_test().engine; - let chain = BlockChain::new(Default::default(), &genesis.last().encoded(), db.clone()); + let chain = BlockChain::new(Default::default(), genesis.last().encoded().raw(), db.clone()); let manifest = ::snapshot::ManifestData { version: 2, diff --git a/ethcore/src/snapshot/tests/service.rs b/ethcore/src/snapshot/tests/service.rs index 3fcb0addfab6186af118d2f0fb3f91548bea17ec..a5af63b01e23f16f22f4a93fc0e407ba86e81f83 100644 --- a/ethcore/src/snapshot/tests/service.rs +++ b/ethcore/src/snapshot/tests/service.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -24,11 +24,10 @@ use ids::BlockId; use snapshot::service::{Service, ServiceParams}; use snapshot::{self, ManifestData, SnapshotService}; use spec::Spec; -use test_helpers::generate_dummy_client_with_spec_and_data; -use test_helpers_internal::restoration_db_handler; +use test_helpers::{generate_dummy_client_with_spec_and_data, restoration_db_handler}; use io::IoChannel; -use kvdb_rocksdb::{Database, DatabaseConfig}; +use kvdb_rocksdb::DatabaseConfig; struct NoopDBRestore; @@ -40,6 +39,9 @@ impl snapshot::DatabaseRestore for NoopDBRestore { #[test] fn restored_is_equivalent() { + use ::ethcore_logger::init_log; + init_log(); + const NUM_BLOCKS: u32 = 400; const TX_PER: usize = 5; @@ -52,13 +54,14 @@ fn restored_is_equivalent() { let path = tempdir.path().join("snapshot"); let db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS); - let client_db = Database::open(&db_config, client_db.to_str().unwrap()).unwrap(); + let restoration = restoration_db_handler(db_config); + let blockchain_db = restoration.open(&client_db).unwrap(); let spec = Spec::new_null(); let client2 = Client::new( Default::default(), &spec, - Arc::new(client_db), + blockchain_db, Arc::new(::miner::Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); @@ -66,7 +69,7 @@ fn restored_is_equivalent() { let service_params = ServiceParams { engine: spec.engine.clone(), genesis_block: spec.genesis_block(), - restoration_db_handler: restoration_db_handler(db_config), + restoration_db_handler: restoration, pruning: ::journaldb::Algorithm::Archive, channel: IoChannel::disconnected(), snapshot_root: path, diff --git a/ethcore/src/snapshot/tests/state.rs b/ethcore/src/snapshot/tests/state.rs index 05926a7e6628a0622102f9c68d9c04e10dbc7f9f..12f19e8c27c1ef565bc15320d5f9d5a63e8239ce 100644 --- a/ethcore/src/snapshot/tests/state.rs +++ b/ethcore/src/snapshot/tests/state.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/snapshot/traits.rs b/ethcore/src/snapshot/traits.rs index d951f4c53413f9421613cdc3e94cbe0e3a8f6bea..eec629ba6e672134877a4c08d77fccc39432739c 100644 --- a/ethcore/src/snapshot/traits.rs +++ b/ethcore/src/snapshot/traits.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/snapshot/watcher.rs b/ethcore/src/snapshot/watcher.rs index 6e04fe6d16deb396e9c5df16f96bdd80e393cabd..680567962766ffefa4d430f576fb7ddacabf7dc8 100644 --- a/ethcore/src/snapshot/watcher.rs +++ b/ethcore/src/snapshot/watcher.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/spec/genesis.rs b/ethcore/src/spec/genesis.rs index 937d7ed8737460747973003794fa4f5f23de6c66..fbfd2cbc4275d9778f4efc48956e59db961b4d4f 100644 --- a/ethcore/src/spec/genesis.rs +++ b/ethcore/src/spec/genesis.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/spec/mod.rs b/ethcore/src/spec/mod.rs index fb60e1cc858efa28746b190b9f025befd95c5131..35705f4a8e5fecffee9623e50cb28e9e71cb3b60 100644 --- a/ethcore/src/spec/mod.rs +++ b/ethcore/src/spec/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/spec/seal.rs b/ethcore/src/spec/seal.rs index 2a07e69c43f37b6eb0ff7bef44a32a422bceb9cc..0ed41acc846e8f350613f0ca5e87fc71022fce60 100644 --- a/ethcore/src/spec/seal.rs +++ b/ethcore/src/spec/seal.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 98720647d8f931d941775722b947517cc397f45b..d79775f788a4404b59ff8a3524c239b64a542594 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -57,7 +57,7 @@ fn fmt_err(f: F) -> String { /// Parameters common to ethereum-like blockchains. /// NOTE: when adding bugfix hard-fork parameters, -/// add to `contains_bugfix_hard_fork` +/// add to `nonzero_bugfix_hard_fork` /// /// we define a "bugfix" hard fork as any hard fork which /// you would put on-by-default in a new chain. @@ -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. @@ -115,6 +115,8 @@ pub struct CommonParams { pub eip214_transition: BlockNumber, /// Number of first block where EIP-145 rules begin. pub eip145_transition: BlockNumber, + /// Number of first block where EIP-1052 rules begin. + pub eip1052_transition: BlockNumber, /// Number of first block where dust cleanup rules (EIP-168 and EIP169) begin. pub dust_protection_transition: BlockNumber, /// Nonce cap increase per block. Nonce cap is only checked if dust protection is enabled. @@ -174,6 +176,7 @@ impl CommonParams { schedule.have_static_call = block_number >= self.eip214_transition; schedule.have_return_data = block_number >= self.eip211_transition; schedule.have_bitwise_shifting = block_number >= self.eip145_transition; + schedule.have_extcodehash = block_number >= self.eip1052_transition; if block_number >= self.eip210_transition { schedule.blockhash_gas = 800; } @@ -188,13 +191,21 @@ impl CommonParams { } } - /// Whether these params contain any bug-fix hard forks. - pub fn contains_bugfix_hard_fork(&self) -> bool { - self.eip98_transition != 0 && self.eip155_transition != 0 && - self.validate_receipts_transition != 0 && self.eip86_transition != 0 && - self.eip140_transition != 0 && self.eip210_transition != 0 && - self.eip211_transition != 0 && self.eip214_transition != 0 && - self.validate_chain_id_transition != 0 && self.dust_protection_transition != 0 + /// Return Some if the current parameters contain a bugfix hard fork not on block 0. + pub fn nonzero_bugfix_hard_fork(&self) -> Option<&str> { + if self.eip155_transition != 0 { + return Some("eip155Transition"); + } + + if self.validate_receipts_transition != 0 { + return Some("validateReceiptsTransition"); + } + + if self.validate_chain_id_transition != 0 { + return Some("validateChainIdTransition"); + } + + None } } @@ -262,6 +273,10 @@ impl From for CommonParams { BlockNumber::max_value, Into::into, ), + eip1052_transition: p.eip1052_transition.map_or_else( + BlockNumber::max_value, + Into::into, + ), dust_protection_transition: p.dust_protection_transition.map_or_else( BlockNumber::max_value, Into::into, @@ -320,7 +335,6 @@ impl<'a, T: AsRef> From<&'a T> for SpecParams<'a> { } } - /// Parameters for a block chain; includes both those intrinsic to the design of the /// chain and those to be interpreted by the active chain engine. pub struct Spec { @@ -516,6 +530,7 @@ macro_rules! load_bundled { }; } +#[cfg(any(test, feature = "test-helpers"))] macro_rules! load_machine_bundled { ($e:expr) => { Spec::load_machine( @@ -623,7 +638,9 @@ impl Spec { let mut substate = Substate::new(); { - let mut exec = Executive::new(&mut state, &env_info, self.engine.machine()); + let machine = self.engine.machine(); + let schedule = machine.schedule(env_info.number); + let mut exec = Executive::new(&mut state, &env_info, &machine, &schedule); if let Err(e) = exec.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer) { warn!(target: "spec", "Genesis constructor execution at {} failed: {}.", address, e); } @@ -839,39 +856,44 @@ impl Spec { self.engine.genesis_epoch_data(&genesis, &call) } + /// Create a new Spec with InstantSeal consensus which does internal sealing (not requiring + /// work). + pub fn new_instant() -> Spec { + load_bundled!("instant_seal") + } + /// Create a new Spec which conforms to the Frontier-era Morden chain except that it's a /// NullEngine consensus. + #[cfg(any(test, feature = "test-helpers"))] pub fn new_test() -> Spec { load_bundled!("null_morden") } /// Create the EthereumMachine corresponding to Spec::new_test. + #[cfg(any(test, feature = "test-helpers"))] pub fn new_test_machine() -> EthereumMachine { load_machine_bundled!("null_morden") } - /// Create a new Spec which conforms to the Frontier-era Morden chain except that it's a NullEngine consensus with applying reward on block close. + #[cfg(any(test, feature = "test-helpers"))] pub fn new_test_with_reward() -> Spec { load_bundled!("null_morden_with_reward") } /// Create a new Spec which is a NullEngine consensus with a premine of address whose /// secret is keccak(''). + #[cfg(any(test, feature = "test-helpers"))] pub fn new_null() -> Spec { load_bundled!("null") } /// Create a new Spec which constructs a contract at address 5 with storage at 0 equal to 1. + #[cfg(any(test, feature = "test-helpers"))] pub fn new_test_constructor() -> Spec { load_bundled!("constructor") } - /// Create a new Spec with InstantSeal consensus which does internal sealing (not requiring - /// work). - pub fn new_instant() -> Spec { - load_bundled!("instant_seal") - } - /// Create a new Spec with AuthorityRound consensus which does internal sealing (not /// requiring work). /// Accounts with secrets keccak("0") and keccak("1") are the validators. + #[cfg(any(test, feature = "test-helpers"))] pub fn new_test_round() -> Self { load_bundled!("authority_round") } @@ -879,6 +901,7 @@ impl Spec { /// Create a new Spec with AuthorityRound consensus which does internal sealing (not /// requiring work) with empty step messages enabled. /// Accounts with secrets keccak("0") and keccak("1") are the validators. + #[cfg(any(test, feature = "test-helpers"))] pub fn new_test_round_empty_steps() -> Self { load_bundled!("authority_round_empty_steps") } @@ -886,6 +909,7 @@ impl Spec { /// Create a new Spec with AuthorityRound consensus (with empty steps) using a block reward /// contract. The contract source code can be found at: /// https://github.com/parity-contracts/block-reward/blob/daf7d44383b6cdb11cb6b953b018648e2b027cfb/contracts/ExampleBlockReward.sol + #[cfg(any(test, feature = "test-helpers"))] pub fn new_test_round_block_reward_contract() -> Self { load_bundled!("authority_round_block_reward_contract") } @@ -893,6 +917,7 @@ impl Spec { /// Create a new Spec with Tendermint consensus which does internal sealing (not requiring /// work). /// Account keccak("0") and keccak("1") are a authorities. + #[cfg(any(test, feature = "test-helpers"))] pub fn new_test_tendermint() -> Self { load_bundled!("tendermint") } @@ -905,6 +930,7 @@ impl Spec { /// "0xbfc708a000000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1" and added /// back in using /// "0x4d238c8e00000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1". + #[cfg(any(test, feature = "test-helpers"))] pub fn new_validator_safe_contract() -> Self { load_bundled!("validator_safe_contract") } @@ -912,6 +938,7 @@ impl Spec { /// The same as the `safeContract`, but allows reporting and uses AuthorityRound. /// Account is marked with `reportBenign` it can be checked as disliked with "0xd8f2e0bf". /// Validator can be removed with `reportMalicious`. + #[cfg(any(test, feature = "test-helpers"))] pub fn new_validator_contract() -> Self { load_bundled!("validator_contract") } @@ -920,6 +947,7 @@ impl Spec { /// height. /// Account with secrets keccak("0") is the validator for block 1 and with keccak("1") /// onwards. + #[cfg(any(test, feature = "test-helpers"))] pub fn new_validator_multi() -> Self { load_bundled!("validator_multi") } @@ -933,7 +961,7 @@ mod tests { use views::BlockView; use tempdir::TempDir; - // https://github.com/paritytech/parity/issues/1840 + // https://github.com/paritytech/parity-ethereum/issues/1840 #[test] fn test_load_empty() { let tempdir = TempDir::new("").unwrap(); diff --git a/ethcore/src/state/account.rs b/ethcore/src/state/account.rs index 5c1dd403969b8e1e5026878ed9991ab5f2b070d8..eec713a4e36cb23de4da7ae2cd5592eec0e6aaea 100644 --- a/ethcore/src/state/account.rs +++ b/ethcore/src/state/account.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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); } @@ -277,12 +278,13 @@ impl Account { !self.code_cache.is_empty() || (self.code_cache.is_empty() && self.code_hash == KECCAK_EMPTY) } - /// 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> { + /// Provide a database to get `code_hash`. Should not be called if it is a contract without code. Returns the cached code, if successful. + #[must_use] + 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()); - if self.is_cached() { return Some(self.code_cache.clone()) } + if self.is_cached() { return Some(self.code_cache.clone()); } match db.get(&self.code_hash) { Some(x) => { @@ -297,8 +299,7 @@ impl Account { } } - /// Provide code to cache. For correctness, should be the correct code for the - /// account. + /// Provide code to cache. For correctness, should be the correct code for the account. pub fn cache_given_code(&mut self, code: Arc) { trace!("Account::cache_given_code: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty()); @@ -306,8 +307,10 @@ impl Account { self.code_cache = code; } - /// 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 { + /// Provide a database to get `code_size`. Should not be called if it is a contract without code. Returns whether + /// the cache succeeds. + #[must_use] + 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() || @@ -323,7 +326,9 @@ impl Account { }, } } else { - false + // If the code hash is empty hash, then the code size is zero. + self.code_size = Some(0); + true } } @@ -374,7 +379,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 +395,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 +477,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 1e761506d95703afaac0df33f2468578f775b9ed..d07124d8d708d06655d975a8759e510df4abab9b 100644 --- a/ethcore/src/state/backend.rs +++ b/ethcore/src/state/backend.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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 5b969bccb93b656b20c0206bf0e595fec6db351a..323e11ccb2bf58d8e25710ce62197730194938c9 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -44,13 +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; @@ -226,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, @@ -306,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>, @@ -337,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. \ @@ -380,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 { @@ -482,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())) @@ -505,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. @@ -603,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())) + |a| a.as_ref().map(|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)?) { @@ -636,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); @@ -648,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) @@ -671,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(()) } @@ -746,7 +745,8 @@ impl State { fn execute(&mut self, env_info: &EnvInfo, machine: &Machine, t: &SignedTransaction, options: TransactOptions, virt: bool) -> Result, ExecutionError> where T: trace::Tracer, V: trace::VMTracer, { - let mut e = Executive::new(self, env_info, machine); + let schedule = machine.schedule(env_info.number); + let mut e = Executive::new(self, env_info, machine, &schedule); match virt { true => e.transact_virtual(t, options), @@ -754,7 +754,7 @@ impl State { } } - fn touch(&mut self, a: &Address) -> trie::Result<()> { + fn touch(&mut self, a: &Address) -> TrieResult<()> { self.require(a, false)?; Ok(()) } @@ -810,7 +810,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 @@ -851,7 +851,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`. @@ -859,7 +859,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| { @@ -887,7 +887,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)?); @@ -905,37 +905,44 @@ 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) { + /// Load required account data from the databases. Returns whether the cache succeeds. + #[must_use] + fn update_account_cache(require: RequireCache, account: &mut Account, state_db: &B, db: &HashDB) -> bool { if let RequireCache::None = require { - return; + return true; } if account.is_cached() { - return; + return true; } // if there's already code in the global cache, always cache it localy let hash = account.code_hash(); match state_db.get_cached_code(&hash) { - Some(code) => account.cache_given_code(code), + Some(code) => { + account.cache_given_code(code); + true + }, None => match require { - RequireCache::None => {}, + RequireCache::None => true, RequireCache::Code => { if let Some(code) = account.cache_code(db) { // propagate code loaded from the database to // the global code cache. - state_db.cache_code(hash, code) + state_db.cache_code(hash, code); + true + } else { + false } }, RequireCache::CodeSize => { - account.cache_code_size(db); + account.cache_code_size(db) } } } @@ -944,14 +951,17 @@ 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) { if let Some(ref mut account) = maybe_acc.account { let accountdb = self.factories.accountdb.readonly(self.db.as_hashdb(), account.address_hash(a)); - Self::update_account_cache(require, account, &self.db, accountdb.as_hashdb()); - return Ok(f(Some(account))); + if Self::update_account_cache(require, account, &self.db, accountdb.as_hashdb()) { + return Ok(f(Some(account))); + } else { + return Err(Box::new(TrieError::IncompleteDatabase(H256::from(a)))); + } } return Ok(f(None)); } @@ -959,12 +969,14 @@ impl State { let result = self.db.get_cached(a, |mut acc| { if let Some(ref mut account) = acc { let accountdb = self.factories.accountdb.readonly(self.db.as_hashdb(), account.address_hash(a)); - Self::update_account_cache(require, account, &self.db, accountdb.as_hashdb()); + if !Self::update_account_cache(require, account, &self.db, accountdb.as_hashdb()) { + return Err(Box::new(TrieError::IncompleteDatabase(H256::from(a)))); + } } - f(acc.map(|a| &*a)) + Ok(f(acc.map(|a| &*a))) }); match result { - Some(r) => Ok(r), + Some(r) => Ok(r?), None => { // first check if it is not in database for sure if check_null && self.db.is_known_null(a) { return Ok(f(None)); } @@ -975,7 +987,9 @@ impl State { let mut maybe_acc = db.get_with(a, from_rlp)?; if let Some(ref mut account) = maybe_acc.as_mut() { let accountdb = self.factories.accountdb.readonly(self.db.as_hashdb(), account.address_hash(a)); - Self::update_account_cache(require, account, &self.db, accountdb.as_hashdb()); + if !Self::update_account_cache(require, account, &self.db, accountdb.as_hashdb()) { + return Err(Box::new(TrieError::IncompleteDatabase(H256::from(a)))); + } } let r = f(maybe_acc.as_ref()); self.insert_cache(a, AccountEntry::new_clean(maybe_acc)); @@ -985,13 +999,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); @@ -1038,7 +1052,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)) } } @@ -1050,7 +1064,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 = { @@ -1075,7 +1089,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/substate.rs b/ethcore/src/state/substate.rs index e70178a36255133565b01c84a031850ebed66a44..c2f3c62dcb53c87dc5a8dd86d1137b5e8daf0250 100644 --- a/ethcore/src/state/substate.rs +++ b/ethcore/src/state/substate.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/state_db.rs b/ethcore/src/state_db.rs index 3b00a42ee6d64764013c34bec25901ec96b5992c..d614fe42f840ef72970dc15e253ec362aead98c2 100644 --- a/ethcore/src/state_db.rs +++ b/ethcore/src/state_db.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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/test_helpers.rs b/ethcore/src/test_helpers.rs index e57d16a6549ca100128d5456a736c2bfae933bbb..c873db5d14f03bb123d59b005e26c90d5d508f70 100644 --- a/ethcore/src/test_helpers.rs +++ b/ethcore/src/test_helpers.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -16,10 +16,13 @@ //! Set of different helpers for client tests +use std::path::Path; +use std::sync::Arc; +use std::{fs, io}; use account_provider::AccountProvider; use ethereum_types::{H256, U256, Address}; use block::{OpenBlock, Drain}; -use blockchain::{BlockChain, Config as BlockChainConfig, ExtrasInsert}; +use blockchain::{BlockChain, BlockChainDB, BlockChainDBHandler, Config as BlockChainConfig, ExtrasInsert}; use bytes::Bytes; use client::{Client, ClientConfig, ChainInfo, ImportBlock, ChainNotify, ChainMessageType, PrepareOpenBlock}; use ethkey::KeyPair; @@ -34,9 +37,14 @@ use rlp::{self, RlpStream}; use spec::Spec; use state_db::StateDB; use state::*; -use std::sync::Arc; use transaction::{Action, Transaction, SignedTransaction}; use views::BlockView; +use blooms_db; +use kvdb::KeyValueDB; +use kvdb_rocksdb; +use tempdir::TempDir; +use verification::queue::kind::blocks::Unverified; +use encoded; /// Creates test block with corresponding header pub fn create_test_block(header: &Header) -> Bytes { @@ -166,14 +174,14 @@ pub fn generate_dummy_client_with_spec_accounts_and_data(test_spec: F, accoun n += 1; } - let b = b.close_and_lock().seal(test_engine, vec![]).unwrap(); + let b = b.close_and_lock().unwrap().seal(test_engine, vec![]).unwrap(); - if let Err(e) = client.import_block(b.rlp_bytes()) { + if let Err(e) = client.import_block(Unverified::from_rlp(b.rlp_bytes()).unwrap()) { panic!("error importing block which is valid by definition: {:?}", e); } last_header = view!(BlockView, &b.rlp_bytes()).header(); - db = b.drain(); + db = b.drain().state.drop().1; } client.flush_queue(); client.import_verified_blocks(); @@ -204,7 +212,7 @@ pub fn push_blocks_to_client(client: &Arc, timestamp_salt: u64, starting rolling_block_number = rolling_block_number + 1; rolling_timestamp = rolling_timestamp + 10; - if let Err(e) = client.import_block(create_test_block(&header)) { + if let Err(e) = client.import_block(Unverified::from_rlp(create_test_block(&header)).unwrap()) { panic!("error importing block which is valid by definition: {:?}", e); } } @@ -216,15 +224,15 @@ pub fn push_block_with_transactions(client: &Arc, transactions: &[Signed let test_engine = &*test_spec.engine; let block_number = client.chain_info().best_block_number as u64 + 1; - let mut b = client.prepare_open_block(Address::default(), (0.into(), 5000000.into()), Bytes::new()); + let mut b = client.prepare_open_block(Address::default(), (0.into(), 5000000.into()), Bytes::new()).unwrap(); b.set_timestamp(block_number * 10); for t in transactions { b.push_transaction(t.clone(), None).unwrap(); } - let b = b.close_and_lock().seal(test_engine, vec![]).unwrap(); + let b = b.close_and_lock().unwrap().seal(test_engine, vec![]).unwrap(); - if let Err(e) = client.import_block(b.rlp_bytes()) { + if let Err(e) = client.import_block(Unverified::from_rlp(b.rlp_bytes()).unwrap()) { panic!("error importing block which is valid by definition: {:?}", e); } @@ -246,7 +254,7 @@ pub fn get_test_client_with_blocks(blocks: Vec) -> Arc { ).unwrap(); for block in blocks { - if let Err(e) = client.import_block(block) { + if let Err(e) = client.import_block(Unverified::from_rlp(block).unwrap()) { panic!("error importing block which is well-formed: {:?}", e); } } @@ -255,8 +263,89 @@ pub fn get_test_client_with_blocks(blocks: Vec) -> Arc { client } -fn new_db() -> Arc<::kvdb::KeyValueDB> { - Arc::new(::kvdb_memorydb::create(::db::NUM_COLUMNS.unwrap_or(0))) +/// Creates new test instance of `BlockChainDB` +pub fn new_db() -> Arc { + struct TestBlockChainDB { + _blooms_dir: TempDir, + _trace_blooms_dir: TempDir, + blooms: blooms_db::Database, + trace_blooms: blooms_db::Database, + key_value: Arc, + } + + impl BlockChainDB for TestBlockChainDB { + fn key_value(&self) -> &Arc { + &self.key_value + } + + fn blooms(&self) -> &blooms_db::Database { + &self.blooms + } + + fn trace_blooms(&self) -> &blooms_db::Database { + &self.trace_blooms + } + } + + let blooms_dir = TempDir::new("").unwrap(); + let trace_blooms_dir = TempDir::new("").unwrap(); + + let db = TestBlockChainDB { + blooms: blooms_db::Database::open(blooms_dir.path()).unwrap(), + trace_blooms: blooms_db::Database::open(trace_blooms_dir.path()).unwrap(), + _blooms_dir: blooms_dir, + _trace_blooms_dir: trace_blooms_dir, + key_value: Arc::new(::kvdb_memorydb::create(::db::NUM_COLUMNS.unwrap())) + }; + + Arc::new(db) +} + +/// Creates new instance of KeyValueDBHandler +pub fn restoration_db_handler(config: kvdb_rocksdb::DatabaseConfig) -> Box { + struct RestorationDBHandler { + config: kvdb_rocksdb::DatabaseConfig, + } + + struct RestorationDB { + blooms: blooms_db::Database, + trace_blooms: blooms_db::Database, + key_value: Arc, + } + + impl BlockChainDB for RestorationDB { + fn key_value(&self) -> &Arc { + &self.key_value + } + + fn blooms(&self) -> &blooms_db::Database { + &self.blooms + } + + fn trace_blooms(&self) -> &blooms_db::Database { + &self.trace_blooms + } + } + + impl BlockChainDBHandler for RestorationDBHandler { + fn open(&self, db_path: &Path) -> io::Result> { + let key_value = Arc::new(kvdb_rocksdb::Database::open(&self.config, &db_path.to_string_lossy())?); + let blooms_path = db_path.join("blooms"); + let trace_blooms_path = db_path.join("trace_blooms"); + fs::create_dir_all(&blooms_path)?; + fs::create_dir_all(&trace_blooms_path)?; + let blooms = blooms_db::Database::open(blooms_path).unwrap(); + let trace_blooms = blooms_db::Database::open(trace_blooms_path).unwrap(); + let db = RestorationDB { + blooms, + trace_blooms, + key_value, + }; + Ok(Arc::new(db)) + } + } + + Box::new(RestorationDBHandler { config }) } /// Generates dummy blockchain with corresponding amount of blocks @@ -264,17 +353,16 @@ pub fn generate_dummy_blockchain(block_number: u32) -> BlockChain { let db = new_db(); let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), db.clone()); - let mut batch = db.transaction(); + let mut batch = db.key_value().transaction(); for block_order in 1..block_number { // Total difficulty is always 0 here. - bc.insert_block(&mut batch, &create_unverifiable_block(block_order, bc.best_block_hash()), vec![], ExtrasInsert { + bc.insert_block(&mut batch, encoded::Block::new(create_unverifiable_block(block_order, bc.best_block_hash())), vec![], ExtrasInsert { fork_choice: ::engines::ForkChoice::New, is_finalized: false, - metadata: None, }); bc.commit(); } - db.write(batch).unwrap(); + db.key_value().write(batch).unwrap(); bc } @@ -283,18 +371,16 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> BlockChain { let db = new_db(); let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), db.clone()); - - let mut batch = db.transaction(); + let mut batch = db.key_value().transaction(); for block_order in 1..block_number { // Total difficulty is always 0 here. - bc.insert_block(&mut batch, &create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None), vec![], ExtrasInsert { + bc.insert_block(&mut batch, encoded::Block::new(create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None)), vec![], ExtrasInsert { fork_choice: ::engines::ForkChoice::New, is_finalized: false, - metadata: None, }); bc.commit(); } - db.write(batch).unwrap(); + db.key_value().write(batch).unwrap(); bc } @@ -322,7 +408,7 @@ pub fn get_temp_state_with_factory(factory: EvmFactory) -> State<::state_db::Sta /// Returns temp state db pub fn get_temp_state_db() -> StateDB { let db = new_db(); - let journal_db = ::journaldb::new(db, ::journaldb::Algorithm::EarlyMerge, ::db::COL_STATE); + let journal_db = ::journaldb::new(db.key_value().clone(), ::journaldb::Algorithm::EarlyMerge, ::db::COL_STATE); StateDB::new(journal_db, 5 * 1024 * 1024) } diff --git a/ethcore/src/test_helpers_internal.rs b/ethcore/src/test_helpers_internal.rs deleted file mode 100644 index ef98c7c85b5792df09bcc5179c48a729cfe32933..0000000000000000000000000000000000000000 --- a/ethcore/src/test_helpers_internal.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Internal helpers for client tests - -use std::path::Path; -use std::sync::Arc; -use kvdb::{KeyValueDB, KeyValueDBHandler}; -use kvdb_rocksdb::{Database, DatabaseConfig}; - -/// Creates new instance of KeyValueDBHandler -pub fn restoration_db_handler(config: DatabaseConfig) -> Box { - use kvdb::Error; - - struct RestorationDBHandler { - config: DatabaseConfig, - } - - impl KeyValueDBHandler for RestorationDBHandler { - fn open(&self, db_path: &Path) -> Result, Error> { - Ok(Arc::new(Database::open(&self.config, &db_path.to_string_lossy())?)) - } - } - - Box::new(RestorationDBHandler { config }) -} diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index 6dcad9ba62f80eabfcd6d31c92cd5396d4ca4a75..24801cb57569d6c186a0629ec97e173bd0cad966 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -29,27 +29,25 @@ use test_helpers::{ }; use types::filter::Filter; use ethereum_types::{U256, Address}; -use kvdb_rocksdb::{Database, DatabaseConfig}; -use miner::Miner; +use miner::{Miner, PendingOrdering}; use spec::Spec; use views::BlockView; use ethkey::KeyPair; use transaction::{PendingTransaction, Transaction, Action, Condition}; use miner::MinerService; -use rlp::{RlpStream, EMPTY_LIST_RLP}; use tempdir::TempDir; +use test_helpers; +use verification::queue::kind::blocks::Unverified; #[test] fn imports_from_empty() { - let tempdir = TempDir::new("").unwrap(); + let db = test_helpers::new_db(); let spec = Spec::new_test(); - let db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS); - let client_db = Arc::new(Database::open(&db_config, tempdir.path().to_str().unwrap()).unwrap()); let client = Client::new( ClientConfig::default(), &spec, - client_db, + db, Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); @@ -59,15 +57,14 @@ fn imports_from_empty() { #[test] fn should_return_registrar() { + let db = test_helpers::new_db(); let tempdir = TempDir::new("").unwrap(); let spec = ethereum::new_morden(&tempdir.path().to_owned()); - let db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS); - let client_db = Arc::new(Database::open(&db_config, tempdir.path().to_str().unwrap()).unwrap()); let client = Client::new( ClientConfig::default(), &spec, - client_db, + db, Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); @@ -89,20 +86,18 @@ fn returns_state_root_basic() { #[test] fn imports_good_block() { - let tempdir = TempDir::new("").unwrap(); + let db = test_helpers::new_db(); let spec = Spec::new_test(); - let db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS); - let client_db = Arc::new(Database::open(&db_config, tempdir.path().to_str().unwrap()).unwrap()); let client = Client::new( ClientConfig::default(), &spec, - client_db, + db, Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); let good_block = get_good_dummy_block(); - if client.import_block(good_block).is_err() { + if client.import_block(Unverified::from_rlp(good_block).unwrap()).is_err() { panic!("error importing block being good by definition"); } client.flush_queue(); @@ -112,36 +107,15 @@ fn imports_good_block() { assert!(!block.into_inner().is_empty()); } -#[test] -fn fails_to_import_block_with_invalid_rlp() { - use error::{BlockImportError, BlockImportErrorKind}; - - let client = generate_dummy_client(6); - let mut rlp = RlpStream::new_list(3); - rlp.append_raw(&EMPTY_LIST_RLP, 1); // empty header - rlp.append_raw(&EMPTY_LIST_RLP, 1); - rlp.append_raw(&EMPTY_LIST_RLP, 1); - let invalid_header_block = rlp.out(); - - match client.import_block(invalid_header_block) { - Err(BlockImportError(BlockImportErrorKind::Decoder(_), _)) => (), // all good - Err(_) => panic!("Should fail with a decoder error"), - Ok(_) => panic!("Should not import block with invalid header"), - } -} - - #[test] fn query_none_block() { - let tempdir = TempDir::new("").unwrap(); + let db = test_helpers::new_db(); let spec = Spec::new_test(); - let db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS); - let client_db = Arc::new(Database::open(&db_config, tempdir.path().to_str().unwrap()).unwrap()); let client = Client::new( ClientConfig::default(), &spec, - client_db, + db, Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); @@ -221,7 +195,6 @@ fn can_collect_garbage() { assert!(client.blockchain_cache_info().blocks < 100 * 1024); } - #[test] fn can_generate_gas_price_median() { let client = generate_dummy_client_with_data(3, 1, slice_into![1, 2, 3]); @@ -277,18 +250,16 @@ fn can_mine() { let dummy_blocks = get_good_dummy_block_seq(2); let client = get_test_client_with_blocks(vec![dummy_blocks[0].clone()]); - let b = client.prepare_open_block(Address::default(), (3141562.into(), 31415620.into()), vec![]).close(); + let b = client.prepare_open_block(Address::default(), (3141562.into(), 31415620.into()), vec![]).unwrap().close().unwrap(); assert_eq!(*b.block().header().parent_hash(), view!(BlockView, &dummy_blocks[0]).header_view().hash()); } #[test] fn change_history_size() { - let tempdir = TempDir::new("").unwrap(); + let db = test_helpers::new_db(); let test_spec = Spec::new_null(); let mut config = ClientConfig::default(); - let db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS); - let client_db = Arc::new(Database::open(&db_config, tempdir.path().to_str().unwrap()).unwrap()); config.history = 2; let address = Address::random(); @@ -296,16 +267,16 @@ fn change_history_size() { let client = Client::new( ClientConfig::default(), &test_spec, - client_db.clone(), + db.clone(), Arc::new(Miner::new_for_tests(&test_spec, None)), IoChannel::disconnected() ).unwrap(); for _ in 0..20 { - let mut b = client.prepare_open_block(Address::default(), (3141562.into(), 31415620.into()), vec![]); + let mut b = client.prepare_open_block(Address::default(), (3141562.into(), 31415620.into()), vec![]).unwrap(); b.block_mut().state_mut().add_balance(&address, &5.into(), CleanupMode::NoEmpty).unwrap(); b.block_mut().state_mut().commit().unwrap(); - let b = b.close_and_lock().seal(&*test_spec.engine, vec![]).unwrap(); + let b = b.close_and_lock().unwrap().seal(&*test_spec.engine, vec![]).unwrap(); client.import_sealed_block(b).unwrap(); // account change is in the journal overlay } } @@ -314,7 +285,7 @@ fn change_history_size() { let client = Client::new( config, &test_spec, - client_db, + db, Arc::new(Miner::new_for_tests(&test_spec, None)), IoChannel::disconnected(), ).unwrap(); @@ -345,12 +316,12 @@ fn does_not_propagate_delayed_transactions() { client.miner().import_own_transaction(&*client, tx0).unwrap(); client.miner().import_own_transaction(&*client, tx1).unwrap(); - assert_eq!(0, client.ready_transactions().len()); - assert_eq!(0, client.miner().ready_transactions(&*client).len()); + assert_eq!(0, client.transactions_to_propagate().len()); + assert_eq!(0, client.miner().ready_transactions(&*client, 10, PendingOrdering::Priority).len()); push_blocks_to_client(&client, 53, 2, 2); client.flush_queue(); - assert_eq!(2, client.ready_transactions().len()); - assert_eq!(2, client.miner().ready_transactions(&*client).len()); + assert_eq!(2, client.transactions_to_propagate().len()); + assert_eq!(2, client.miner().ready_transactions(&*client, 10, PendingOrdering::Priority).len()); } #[test] @@ -361,10 +332,10 @@ fn transaction_proof() { let address = Address::random(); let test_spec = Spec::new_test(); for _ in 0..20 { - let mut b = client.prepare_open_block(Address::default(), (3141562.into(), 31415620.into()), vec![]); + let mut b = client.prepare_open_block(Address::default(), (3141562.into(), 31415620.into()), vec![]).unwrap(); b.block_mut().state_mut().add_balance(&address, &5.into(), CleanupMode::NoEmpty).unwrap(); b.block_mut().state_mut().commit().unwrap(); - let b = b.close_and_lock().seal(&*test_spec.engine, vec![]).unwrap(); + let b = b.close_and_lock().unwrap().seal(&*test_spec.engine, vec![]).unwrap(); client.import_sealed_block(b).unwrap(); // account change is in the journal overlay } @@ -384,8 +355,11 @@ fn transaction_proof() { factories.accountdb = ::account_db::Factory::Plain; // raw state values, no mangled keys. let root = *client.best_block_header().state_root(); + let machine = test_spec.engine.machine(); + let env_info = client.latest_env_info(); + let schedule = machine.schedule(env_info.number); let mut state = State::from_existing(backend, root, 0.into(), factories.clone()).unwrap(); - Executive::new(&mut state, &client.latest_env_info(), test_spec.engine.machine()) + Executive::new(&mut state, &env_info, &machine, &schedule) .transact(&transaction, TransactOptions::with_no_tracing().dont_check_nonce()).unwrap(); assert_eq!(state.balance(&Address::default()).unwrap(), 5.into()); diff --git a/ethcore/src/tests/evm.rs b/ethcore/src/tests/evm.rs index 4f4ad4241f2b1a39ff60c35ccc8a11fd9279dfc6..239905facf4d9148f786f527361ce6b64f3a30c9 100644 --- a/ethcore/src/tests/evm.rs +++ b/ethcore/src/tests/evm.rs @@ -62,7 +62,8 @@ fn test_blockhash_eip210(factory: Factory) { call_type: CallType::Call, params_type: ParamsType::Separate, }; - let mut ex = Executive::new(&mut state, &env_info, &machine); + let schedule = machine.schedule(env_info.number); + let mut ex = Executive::new(&mut state, &env_info, &machine, &schedule); let mut substate = Substate::new(); let mut output = []; if let Err(e) = ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer) { @@ -85,7 +86,8 @@ fn test_blockhash_eip210(factory: Factory) { call_type: CallType::Call, params_type: ParamsType::Separate, }; - let mut ex = Executive::new(&mut state, &env_info, &machine); + let schedule = machine.schedule(env_info.number); + let mut ex = Executive::new(&mut state, &env_info, &machine, &schedule); let mut substate = Substate::new(); let mut output = H256::new(); if let Err(e) = ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer) { diff --git a/ethcore/src/tests/mod.rs b/ethcore/src/tests/mod.rs index 8b509d2afccbb968574fc5194d757e32c2f853fc..d1d5b6ef7fe9190e4a2217d2eb5d6c4988582952 100644 --- a/ethcore/src/tests/mod.rs +++ b/ethcore/src/tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/tests/trace.rs b/ethcore/src/tests/trace.rs index a98667b142395315c03244a2e63f66618703245a..24ef37800432c61d7e310832e9986bc9023507cb 100644 --- a/ethcore/src/tests/trace.rs +++ b/ethcore/src/tests/trace.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -16,7 +16,6 @@ //! Client tests of tracing -use tempdir::TempDir; use ethkey::KeyPair; use hash::keccak; use block::*; @@ -26,7 +25,6 @@ use spec::*; use client::*; use test_helpers::get_temp_state_db; use client::{BlockChainClient, Client, ClientConfig}; -use kvdb_rocksdb::{Database, DatabaseConfig}; use std::sync::Arc; use header::Header; use miner::Miner; @@ -34,22 +32,22 @@ use transaction::{Action, Transaction}; use views::BlockView; use trace::{RewardType, LocalizedTrace}; use trace::trace::Action::Reward; +use test_helpers; +use verification::queue::kind::blocks::Unverified; #[test] fn can_trace_block_and_uncle_reward() { - let tempdir = TempDir::new("").unwrap(); + let db = test_helpers::new_db(); let spec = Spec::new_test_with_reward(); let engine = &*spec.engine; // Create client - let db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS); let mut client_config = ClientConfig::default(); client_config.tracing.enabled = true; - let client_db = Arc::new(Database::open(&db_config, tempdir.path().to_str().unwrap()).unwrap()); let client = Client::new( client_config, &spec, - client_db, + db, Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); @@ -92,15 +90,15 @@ fn can_trace_block_and_uncle_reward() { rolling_timestamp += 10; root_block.set_timestamp(rolling_timestamp); - let root_block = root_block.close_and_lock().seal(engine, vec![]).unwrap(); + let root_block = root_block.close_and_lock().unwrap().seal(engine, vec![]).unwrap(); - if let Err(e) = client.import_block(root_block.rlp_bytes()) { + if let Err(e) = client.import_block(Unverified::from_rlp(root_block.rlp_bytes()).unwrap()) { panic!("error importing block which is valid by definition: {:?}", e); } last_header = view!(BlockView, &root_block.rlp_bytes()).header(); let root_header = last_header.clone(); - db = root_block.drain(); + db = root_block.drain().state.drop().1; last_hashes.push(last_header.hash()); @@ -121,14 +119,14 @@ fn can_trace_block_and_uncle_reward() { rolling_timestamp += 10; parent_block.set_timestamp(rolling_timestamp); - let parent_block = parent_block.close_and_lock().seal(engine, vec![]).unwrap(); + let parent_block = parent_block.close_and_lock().unwrap().seal(engine, vec![]).unwrap(); - if let Err(e) = client.import_block(parent_block.rlp_bytes()) { + if let Err(e) = client.import_block(Unverified::from_rlp(parent_block.rlp_bytes()).unwrap()) { panic!("error importing block which is valid by definition: {:?}", e); } last_header = view!(BlockView,&parent_block.rlp_bytes()).header(); - db = parent_block.drain(); + db = parent_block.drain().state.drop().1; last_hashes.push(last_header.hash()); @@ -171,9 +169,9 @@ fn can_trace_block_and_uncle_reward() { uncle.set_timestamp(rolling_timestamp); block.push_uncle(uncle).unwrap(); - let block = block.close_and_lock().seal(engine, vec![]).unwrap(); + let block = block.close_and_lock().unwrap().seal(engine, vec![]).unwrap(); - let res = client.import_block(block.rlp_bytes()); + let res = client.import_block(Unverified::from_rlp(block.rlp_bytes()).unwrap()); if res.is_err() { panic!("error importing block: {:#?}", res.err().unwrap()); } diff --git a/ethcore/src/trace/config.rs b/ethcore/src/trace/config.rs index dbd8a97affe1a4d587d5cf4385c6bae34f2d8def..2e667f07f2a0982657f28c51a86a06192541e8fa 100644 --- a/ethcore/src/trace/config.rs +++ b/ethcore/src/trace/config.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -15,7 +15,6 @@ // along with Parity. If not, see . //! Traces config. -use bloomchain::Config as BloomConfig; /// Traces config. #[derive(Debug, PartialEq, Clone)] @@ -23,8 +22,6 @@ pub struct Config { /// Indicates if tracing should be enabled or not. /// If it's None, it will be automatically configured. pub enabled: bool, - /// Traces blooms configuration. - pub blooms: BloomConfig, /// Preferef cache-size. pub pref_cache_size: usize, /// Max cache-size. @@ -35,10 +32,6 @@ impl Default for Config { fn default() -> Self { Config { enabled: false, - blooms: BloomConfig { - levels: 3, - elements_per_index: 16, - }, pref_cache_size: 15 * 1024 * 1024, max_cache_size: 20 * 1024 * 1024, } diff --git a/ethcore/src/trace/db.rs b/ethcore/src/trace/db.rs index 45b9ebc150acf02c4606edf029dd51129be00d13..b74ff7d55b4ab82b56cfcd85f9d96b422aad1745 100644 --- a/ethcore/src/trace/db.rs +++ b/ethcore/src/trace/db.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -15,19 +15,16 @@ // along with Parity. If not, see . //! Trace database. -use std::ops::Deref; use std::collections::{HashMap, VecDeque}; use std::sync::Arc; -use bloomchain::{Number, Config as BloomConfig}; -use bloomchain::group::{BloomGroupDatabase, BloomGroupChain, GroupPosition, BloomGroup}; +use blockchain::{BlockChainDB}; use heapsize::HeapSizeOf; use ethereum_types::{H256, H264}; -use kvdb::{KeyValueDB, DBTransaction}; +use kvdb::{DBTransaction}; use parking_lot::RwLock; use header::BlockNumber; use trace::{LocalizedTrace, Config, Filter, Database as TraceDatabase, ImportRequest, DatabaseExtras}; use db::{self, Key, Writable, Readable, CacheUpdatePolicy}; -use blooms; use super::flat::{FlatTrace, FlatBlockTraces, FlatTransactionTraces}; use cache_manager::CacheManager; @@ -37,8 +34,6 @@ const TRACE_DB_VER: &'static [u8] = b"1.0"; enum TraceDBIndex { /// Block traces index. BlockTraces = 0, - /// Trace bloom group index. - BloomGroups = 1, } impl Key for H256 { @@ -52,55 +47,6 @@ impl Key for H256 { } } -/// Wrapper around `blooms::GroupPosition` so it could be -/// uniquely identified in the database. -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -struct TraceGroupPosition(blooms::GroupPosition); - -impl From for TraceGroupPosition { - fn from(position: GroupPosition) -> Self { - TraceGroupPosition(From::from(position)) - } -} - -impl HeapSizeOf for TraceGroupPosition { - fn heap_size_of_children(&self) -> usize { - 0 - } -} - -/// Helper data structure created cause [u8; 6] does not implement Deref to &[u8]. -pub struct TraceGroupKey([u8; 6]); - -impl Deref for TraceGroupKey { - type Target = [u8]; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Key for TraceGroupPosition { - type Target = TraceGroupKey; - - fn key(&self) -> Self::Target { - let mut result = [0u8; 6]; - result[0] = TraceDBIndex::BloomGroups as u8; - result[1] = self.0.level; - result[2] = self.0.index as u8; - result[3] = (self.0.index >> 8) as u8; - result[4] = (self.0.index >> 16) as u8; - result[5] = (self.0.index >> 24) as u8; - TraceGroupKey(result) - } -} - -#[derive(Debug, Hash, Eq, PartialEq)] -enum CacheId { - Trace(H256), - Bloom(TraceGroupPosition), -} - /// Database to store transaction execution trace. /// /// Whenever a transaction is executed by EVM it's execution trace is stored @@ -108,60 +54,45 @@ enum CacheId { /// touched, which have been created during the execution of transaction, and /// which calls failed. pub struct TraceDB where T: DatabaseExtras { - // cache + /// cache traces: RwLock>, - blooms: RwLock>, - cache_manager: RwLock>, - // db - tracesdb: Arc, - // config, - bloom_config: BloomConfig, - // tracing enabled + /// hashes of cached traces + cache_manager: RwLock>, + /// db + db: Arc, + /// tracing enabled enabled: bool, - // extras + /// extras extras: Arc, } -impl BloomGroupDatabase for TraceDB where T: DatabaseExtras { - fn blooms_at(&self, position: &GroupPosition) -> Option { - let position = TraceGroupPosition::from(position.clone()); - let result = self.tracesdb.read_with_cache(db::COL_TRACE, &self.blooms, &position).map(Into::into); - self.note_used(CacheId::Bloom(position)); - result - } -} - impl TraceDB where T: DatabaseExtras { /// Creates new instance of `TraceDB`. - pub fn new(config: Config, tracesdb: Arc, extras: Arc) -> Self { + pub fn new(config: Config, db: Arc, extras: Arc) -> Self { let mut batch = DBTransaction::new(); let genesis = extras.block_hash(0) .expect("Genesis block is always inserted upon extras db creation qed"); batch.write(db::COL_TRACE, &genesis, &FlatBlockTraces::default()); batch.put(db::COL_TRACE, b"version", TRACE_DB_VER); - tracesdb.write(batch).expect("failed to update version"); + db.key_value().write(batch).expect("failed to update version"); TraceDB { traces: RwLock::new(HashMap::new()), - blooms: RwLock::new(HashMap::new()), cache_manager: RwLock::new(CacheManager::new(config.pref_cache_size, config.max_cache_size, 10 * 1024)), - tracesdb: tracesdb, - bloom_config: config.blooms, + db, enabled: config.enabled, extras: extras, } } fn cache_size(&self) -> usize { - let traces = self.traces.read().heap_size_of_children(); - let blooms = self.blooms.read().heap_size_of_children(); - traces + blooms + self.traces.read().heap_size_of_children() } /// Let the cache system know that a cacheable item has been used. - fn note_used(&self, id: CacheId) { + fn note_trace_used(&self, trace_id: H256) { let mut cache_manager = self.cache_manager.write(); - cache_manager.note_used(id); + cache_manager.note_used(trace_id); } /// Ticks our cache system and throws out any old data. @@ -169,27 +100,22 @@ impl TraceDB where T: DatabaseExtras { let current_size = self.cache_size(); let mut traces = self.traces.write(); - let mut blooms = self.blooms.write(); let mut cache_manager = self.cache_manager.write(); cache_manager.collect_garbage(current_size, | ids | { for id in &ids { - match *id { - CacheId::Trace(ref h) => { traces.remove(h); }, - CacheId::Bloom(ref h) => { blooms.remove(h); }, - } + traces.remove(id); } traces.shrink_to_fit(); - blooms.shrink_to_fit(); - traces.heap_size_of_children() + blooms.heap_size_of_children() + traces.heap_size_of_children() }); } /// Returns traces for block with hash. fn traces(&self, block_hash: &H256) -> Option { - let result = self.tracesdb.read_with_cache(db::COL_TRACE, &self.traces, block_hash); - self.note_used(CacheId::Trace(block_hash.clone())); + let result = self.db.key_value().read_with_cache(db::COL_TRACE, &self.traces, block_hash); + self.note_trace_used(*block_hash); result } @@ -271,10 +197,8 @@ impl TraceDatabase for TraceDB where T: DatabaseExtras { // now let's rebuild the blooms if !request.enacted.is_empty() { - let range_start = request.block_number as Number + 1 - request.enacted.len(); - let range_end = range_start + request.retracted; - let replaced_range = range_start..range_end; - let enacted_blooms = request.enacted + let range_start = request.block_number + 1 - request.enacted.len() as u64; + let enacted_blooms: Vec<_> = request.enacted .iter() // all traces are expected to be found here. That's why `expect` has been used // instead of `filter_map`. If some traces haven't been found, it meens that @@ -286,19 +210,9 @@ impl TraceDatabase for TraceDB where T: DatabaseExtras { }) .collect(); - let chain = BloomGroupChain::new(self.bloom_config, self); - let trace_blooms = chain.replace(&replaced_range, enacted_blooms); - let blooms_to_insert = trace_blooms.into_iter() - .map(|p| (From::from(p.0), From::from(p.1))) - .collect::>(); - - let blooms_keys: Vec<_> = blooms_to_insert.keys().cloned().collect(); - let mut blooms = self.blooms.write(); - batch.extend_with_cache(db::COL_TRACE, &mut *blooms, blooms_to_insert, CacheUpdatePolicy::Remove); - // note_used must be called after locking blooms to avoid cache/traces deadlock on garbage collection - for key in blooms_keys { - self.note_used(CacheId::Bloom(key)); - } + self.db.trace_blooms() + .insert_blooms(range_start, enacted_blooms.iter()) + .expect("Low level database error. Some issue with disk?"); } // insert new block traces into the cache and the database @@ -308,7 +222,7 @@ impl TraceDatabase for TraceDB where T: DatabaseExtras { // cause this value might be queried by hash later batch.write_with_cache(db::COL_TRACE, &mut *traces, request.block_hash, request.traces, CacheUpdatePolicy::Overwrite); // note_used must be called after locking traces to avoid cache/traces deadlock on garbage collection - self.note_used(CacheId::Trace(request.block_hash.clone())); + self.note_trace_used(request.block_hash); } } @@ -396,8 +310,11 @@ impl TraceDatabase for TraceDB where T: DatabaseExtras { } fn filter(&self, filter: &Filter) -> Vec { - let chain = BloomGroupChain::new(self.bloom_config, self); - let numbers = chain.filter(filter); + let possibilities = filter.bloom_possibilities(); + let numbers = self.db.trace_blooms() + .filter(filter.range.start as u64, filter.range.end as u64, &possibilities) + .expect("Low level database error. Some issue with disk?"); + numbers.into_iter() .flat_map(|n| { let number = n as BlockNumber; @@ -416,14 +333,14 @@ mod tests { use std::collections::HashMap; use std::sync::Arc; use ethereum_types::{H256, U256, Address}; - use kvdb::{DBTransaction, KeyValueDB}; - use kvdb_memorydb; + use kvdb::{DBTransaction}; use header::BlockNumber; use trace::{Config, TraceDB, Database as TraceDatabase, DatabaseExtras, ImportRequest}; use trace::{Filter, LocalizedTrace, AddressesFilter, TraceError}; use trace::trace::{Call, Action, Res}; use trace::flat::{FlatTrace, FlatBlockTraces, FlatTransactionTraces}; use evm::CallType; + use test_helpers::new_db; struct NoopExtras; @@ -467,10 +384,6 @@ mod tests { } } - fn new_db() -> Arc { - Arc::new(kvdb_memorydb::create(::db::NUM_COLUMNS.unwrap_or(0))) - } - #[test] fn test_reopening_db_with_tracing_off() { let db = new_db(); @@ -585,12 +498,11 @@ mod tests { let request = create_noncanon_import_request(0, block_0.clone()); let mut batch = DBTransaction::new(); tracedb.import(&mut batch, request); - db.write(batch).unwrap(); + db.key_value().write(batch).unwrap(); assert!(tracedb.traces(&block_0).is_some(), "Traces should be available even if block is non-canon."); } - #[test] fn test_import() { let db = new_db(); @@ -615,7 +527,7 @@ mod tests { let request = create_simple_import_request(1, block_1.clone()); let mut batch = DBTransaction::new(); tracedb.import(&mut batch, request); - db.write(batch).unwrap(); + db.key_value().write(batch).unwrap(); let filter = Filter { range: (1..1), @@ -631,7 +543,7 @@ mod tests { let request = create_simple_import_request(2, block_2.clone()); let mut batch = DBTransaction::new(); tracedb.import(&mut batch, request); - db.write(batch).unwrap(); + db.key_value().write(batch).unwrap(); let filter = Filter { range: (1..2), @@ -693,7 +605,7 @@ mod tests { let request = create_simple_import_request(1, block_0.clone()); let mut batch = DBTransaction::new(); tracedb.import(&mut batch, request); - db.write(batch).unwrap(); + db.key_value().write(batch).unwrap(); } { diff --git a/ethcore/src/trace/executive_tracer.rs b/ethcore/src/trace/executive_tracer.rs index b1d116d69d59accbbbd31a07e8442472a3a0ef1e..1bae15d5954542dcdf688794f2d6e9894b9d23e8 100644 --- a/ethcore/src/trace/executive_tracer.rs +++ b/ethcore/src/trace/executive_tracer.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/trace/import.rs b/ethcore/src/trace/import.rs index fb72e220e45fb91b9a9a8c7b646c9f50854a9a24..b720b0b86a91fb5af2135c4fe6d45851a93544a6 100644 --- a/ethcore/src/trace/import.rs +++ b/ethcore/src/trace/import.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/trace/mod.rs b/ethcore/src/trace/mod.rs index 381dcd9f0d186a51fff8baad461ec96d57baabb6..90ea64b5d218ed66f64bca73a00c7f1ff155250f 100644 --- a/ethcore/src/trace/mod.rs +++ b/ethcore/src/trace/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -49,15 +49,21 @@ pub trait Tracer: Send { type Output; /// Prepares call trace for given params. Noop tracer should return None. + /// + /// This is called before a call has been executed. fn prepare_trace_call(&self, params: &ActionParams) -> Option; /// Prepares create trace for given params. Noop tracer should return None. + /// + /// This is called before a create has been executed. fn prepare_trace_create(&self, params: &ActionParams) -> Option; /// Prepare trace output. Noop tracer should return None. fn prepare_trace_output(&self) -> Option; /// Stores trace call info. + /// + /// This is called after a call has completed successfully. fn trace_call( &mut self, call: Option, @@ -67,6 +73,8 @@ pub trait Tracer: Send { ); /// Stores trace create info. + /// + /// This is called after a create has completed successfully. fn trace_create( &mut self, create: Option, @@ -77,9 +85,13 @@ pub trait Tracer: Send { ); /// Stores failed call trace. + /// + /// This is called after a call has completed erroneously. fn trace_failed_call(&mut self, call: Option, subs: Vec, error: TraceError); /// Stores failed create trace. + /// + /// This is called after a create has completed erroneously. fn trace_failed_create(&mut self, create: Option, subs: Vec, error: TraceError); /// Stores suicide info. diff --git a/ethcore/src/trace/noop_tracer.rs b/ethcore/src/trace/noop_tracer.rs index ab0bf77ff1cad8e676953151aacc33ed00aca3ec..8312de58f875fa66917928cfea017eee85c55e70 100644 --- a/ethcore/src/trace/noop_tracer.rs +++ b/ethcore/src/trace/noop_tracer.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/trace/types/error.rs b/ethcore/src/trace/types/error.rs index f2fa192d3313d54d5770fb49e375951c564ff898..a934443c5dbe6823548dbba2f7bcbfbb9908e682 100644 --- a/ethcore/src/trace/types/error.rs +++ b/ethcore/src/trace/types/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/trace/types/filter.rs b/ethcore/src/trace/types/filter.rs index 308eb72da7b42700510989219b9aad34432c8e09..0bfdc10da3de2321ec3c3de317268db5526b762f 100644 --- a/ethcore/src/trace/types/filter.rs +++ b/ethcore/src/trace/types/filter.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -17,7 +17,6 @@ //! Trace filters type definitions use std::ops::Range; -use bloomchain::{Filter as BloomFilter, Number}; use ethereum_types::{Address, Bloom, BloomInput}; use trace::flat::FlatTrace; use super::trace::{Action, Res}; @@ -88,19 +87,9 @@ pub struct Filter { pub to_address: AddressesFilter, } -impl BloomFilter for Filter { - fn bloom_possibilities(&self) -> Vec { - self.bloom_possibilities() - } - - fn range(&self) -> Range { - self.range.clone() - } -} - impl Filter { /// Returns combinations of each address. - fn bloom_possibilities(&self) -> Vec { + pub fn bloom_possibilities(&self) -> Vec { self.to_address.with_blooms(self.from_address.blooms()) } diff --git a/ethcore/src/trace/types/flat.rs b/ethcore/src/trace/types/flat.rs index 00cf517df804265f0807e996f3736cf66a087246..8610692200c310c505ff3bfdcfbf9e4fb4821bfa 100644 --- a/ethcore/src/trace/types/flat.rs +++ b/ethcore/src/trace/types/flat.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/trace/types/localized.rs b/ethcore/src/trace/types/localized.rs index f649e169971fe62964507dd5742a79848182c3c1..816eccc93798ff76292d70066a485e256c7013fd 100644 --- a/ethcore/src/trace/types/localized.rs +++ b/ethcore/src/trace/types/localized.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/trace/types/mod.rs b/ethcore/src/trace/types/mod.rs index a9be2865b0fbf335dfb5ac30a8f1e81e9b76cc59..0e019ac552d451c60375ae25c015aa6ec06fdc0c 100644 --- a/ethcore/src/trace/types/mod.rs +++ b/ethcore/src/trace/types/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/trace/types/trace.rs b/ethcore/src/trace/types/trace.rs index cdb00a522948d87ea060b103aa71a699a45712fa..1dde16e23baeeef04d4db531333cd431527869cb 100644 --- a/ethcore/src/trace/types/trace.rs +++ b/ethcore/src/trace/types/trace.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -210,7 +210,6 @@ impl Decodable for Reward { } } - /// Suicide action. #[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)] pub struct Suicide { diff --git a/ethcore/src/tx_filter.rs b/ethcore/src/tx_filter.rs index 8bbb499052b28995cd7025555981ab2fff88f9a8..585dc7e3d388ae9b27d1c41b867093f09a648d53 100644 --- a/ethcore/src/tx_filter.rs +++ b/ethcore/src/tx_filter.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -16,7 +16,7 @@ //! Smart contract based transaction filter. -use ethereum_types::{H256, Address}; +use ethereum_types::{H256, U256, Address}; use lru_cache::LruCache; use client::{BlockInfo, CallContract, BlockId}; @@ -25,6 +25,7 @@ use spec::CommonParams; use transaction::{Action, SignedTransaction}; use hash::KECCAK_EMPTY; +use_contract!(transact_acl_deprecated, "TransactAclDeprecated", "res/contracts/tx_acl_deprecated.json"); use_contract!(transact_acl, "TransactAcl", "res/contracts/tx_acl.json"); const MAX_CACHE_SIZE: usize = 4096; @@ -40,9 +41,11 @@ mod tx_permissions { /// Connection filter that uses a contract to manage permissions. pub struct TransactionFilter { + contract_deprecated: transact_acl_deprecated::TransactAclDeprecated, contract: transact_acl::TransactAcl, contract_address: Address, permission_cache: Mutex>, + contract_version_cache: Mutex>> } impl TransactionFilter { @@ -50,46 +53,86 @@ impl TransactionFilter { pub fn from_params(params: &CommonParams) -> Option { params.transaction_permission_contract.map(|address| TransactionFilter { + contract_deprecated: transact_acl_deprecated::TransactAclDeprecated::default(), contract: transact_acl::TransactAcl::default(), contract_address: address, permission_cache: Mutex::new(LruCache::new(MAX_CACHE_SIZE)), + contract_version_cache: Mutex::new(LruCache::new(MAX_CACHE_SIZE)), } ) } /// Check if transaction is allowed at given block. pub fn transaction_allowed(&self, parent_hash: &H256, transaction: &SignedTransaction, client: &C) -> bool { - let mut cache = self.permission_cache.lock(); + let mut permission_cache = self.permission_cache.lock(); + let mut contract_version_cache = self.contract_version_cache.lock(); - let tx_type = match transaction.action { - Action::Create => tx_permissions::CREATE, + let (tx_type, to) = match transaction.action { + Action::Create => (tx_permissions::CREATE, Address::new()), Action::Call(address) => if client.code_hash(&address, BlockId::Hash(*parent_hash)).map_or(false, |c| c != KECCAK_EMPTY) { - tx_permissions::CALL - } else { - tx_permissions::BASIC - } + (tx_permissions::CALL, address) + } else { + (tx_permissions::BASIC, address) + } }; let sender = transaction.sender(); + let value = transaction.value; let key = (*parent_hash, sender); - if let Some(permissions) = cache.get_mut(&key) { + if let Some(permissions) = permission_cache.get_mut(&key) { return *permissions & tx_type != 0; } let contract_address = self.contract_address; - let permissions = self.contract.functions() - .allowed_tx_types() - .call(sender, &|data| client.call_contract(BlockId::Hash(*parent_hash), contract_address, data)) - .map(|p| p.low_u32()) - .unwrap_or_else(|e| { - debug!("Error callling tx permissions contract: {:?}", e); - tx_permissions::NONE - }); - - cache.insert((*parent_hash, sender), permissions); - - trace!("Permissions required: {}, got: {}", tx_type, permissions); + let contract_version = contract_version_cache.get_mut(parent_hash).and_then(|v| *v).or_else(|| { + self.contract.functions() + .contract_version() + .call(&|data| client.call_contract(BlockId::Hash(*parent_hash), contract_address, data)) + .ok() + }); + contract_version_cache.insert(*parent_hash, contract_version); + + // Check permissions in smart contract based on its version + let (permissions, filter_only_sender) = match contract_version { + Some(version) => { + let version_u64 = version.low_u64(); + trace!(target: "tx_filter", "Version of tx permission contract: {}", version); + match version_u64 { + 2 => self.contract.functions() + .allowed_tx_types() + .call(sender, to, value, &|data| client.call_contract(BlockId::Hash(*parent_hash), contract_address, data)) + .map(|(p, f)| (p.low_u32(), f)) + .unwrap_or_else(|e| { + error!(target: "tx_filter", "Error calling tx permissions contract: {:?}", e); + (tx_permissions::NONE, true) + }), + _ => { + error!(target: "tx_filter", "Unknown version of tx permissions contract is used"); + (tx_permissions::NONE, true) + } + } + }, + None => { + trace!(target: "tx_filter", "Fallback to the deprecated version of tx permission contract"); + (self.contract_deprecated.functions() + .allowed_tx_types() + .call(sender, &|data| client.call_contract(BlockId::Hash(*parent_hash), contract_address, data)) + .map(|p| p.low_u32()) + .unwrap_or_else(|e| { + error!(target: "tx_filter", "Error calling tx permissions contract: {:?}", e); + tx_permissions::NONE + }), true) + } + }; + + if filter_only_sender { + permission_cache.insert((*parent_hash, sender), permissions); + } + trace!(target: "tx_filter", + "Given transaction data: sender: {:?} to: {:?} value: {}. Permissions required: {:X}, got: {:X}", + sender, to, value, tx_type, permissions + ); permissions & tx_type != 0 } } @@ -100,70 +143,101 @@ mod test { use spec::Spec; use client::{BlockChainClient, Client, ClientConfig, BlockId}; use miner::Miner; - use ethereum_types::Address; + use ethereum_types::{U256, Address}; use io::IoChannel; use ethkey::{Secret, KeyPair}; use super::TransactionFilter; use transaction::{Transaction, Action}; use tempdir::TempDir; + use test_helpers; - /// Contract code: https://gist.github.com/arkpar/38a87cb50165b7e683585eec71acb05a + /// Contract code: https://gist.github.com/VladLupashevskyi/84f18eabb1e4afadf572cf92af3e7e7f #[test] fn transaction_filter() { - let spec_data = r#" - { - "name": "TestNodeFilterContract", - "engine": { - "authorityRound": { - "params": { - "stepDuration": 1, - "startStep": 2, - "validators": { - "contract": "0x0000000000000000000000000000000000000000" - } - } - } - }, - "params": { - "accountStartNonce": "0x0", - "maximumExtraDataSize": "0x20", - "minGasLimit": "0x1388", - "networkID" : "0x69", - "gasLimitBoundDivisor": "0x0400", - "transactionPermissionContract": "0x0000000000000000000000000000000000000005" - }, - "genesis": { - "seal": { - "generic": "0xc180" - }, - "difficulty": "0x20000", - "author": "0x0000000000000000000000000000000000000000", - "timestamp": "0x00", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData": "0x", - "gasLimit": "0x222222" - }, - "accounts": { - "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, - "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, - "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, - "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, - "0000000000000000000000000000000000000005": { - "balance": "1", - "constructor": "6060604052341561000f57600080fd5b5b6101868061001f6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063e17512211461003e575b600080fd5b341561004957600080fd5b610075600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610097565b604051808263ffffffff1663ffffffff16815260200191505060405180910390f35b6000737e5f4552091a69125d5dfcb7b8c2659029395bdf8273ffffffffffffffffffffffffffffffffffffffff1614156100d75763ffffffff9050610155565b732b5ad5c4795c026514f8317c7a215e218dccd6cf8273ffffffffffffffffffffffffffffffffffffffff1614156101155760026001179050610155565b736813eb9362372eef6200f3b1dbc3f819671cba698273ffffffffffffffffffffffffffffffffffffffff1614156101505760019050610155565b600090505b9190505600a165627a7a72305820f1f21cb978925a8a92c6e30c8c81adf598adff6d1ef941cf5ed6c0ec7ad1ae3d0029" - } - } - } - "#; + let spec_data = include_str!("../res/tx_permission_tests/contract_ver_2_genesis.json"); + let db = test_helpers::new_db(); let tempdir = TempDir::new("").unwrap(); let spec = Spec::load(&tempdir.path(), spec_data.as_bytes()).unwrap(); - let client_db = Arc::new(::kvdb_memorydb::create(::db::NUM_COLUMNS.unwrap_or(0))); let client = Client::new( ClientConfig::default(), &spec, - client_db, + db, + Arc::new(Miner::new_for_tests(&spec, None)), + IoChannel::disconnected(), + ).unwrap(); + let key1 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000001")).unwrap(); + let key2 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000002")).unwrap(); + let key3 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000003")).unwrap(); + let key4 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000004")).unwrap(); + let key5 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000005")).unwrap(); + let key6 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000006")).unwrap(); + let key7 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000007")).unwrap(); + + let filter = TransactionFilter::from_params(spec.params()).unwrap(); + let mut basic_tx = Transaction::default(); + basic_tx.action = Action::Call(Address::from("d41c057fd1c78805aac12b0a94a405c0461a6fbb")); + let create_tx = Transaction::default(); + let mut call_tx = Transaction::default(); + call_tx.action = Action::Call(Address::from("0000000000000000000000000000000000000005")); + + let mut basic_tx_with_ether_and_to_key7 = Transaction::default(); + basic_tx_with_ether_and_to_key7.action = Action::Call(Address::from("d41c057fd1c78805aac12b0a94a405c0461a6fbb")); + basic_tx_with_ether_and_to_key7.value = U256::from(123123); + let mut call_tx_with_ether = Transaction::default(); + call_tx_with_ether.action = Action::Call(Address::from("0000000000000000000000000000000000000005")); + call_tx_with_ether.value = U256::from(123123); + + let mut basic_tx_to_key6 = Transaction::default(); + basic_tx_to_key6.action = Action::Call(Address::from("e57bfe9f44b819898f47bf37e5af72a0783e1141")); + let mut basic_tx_with_ether_and_to_key6 = Transaction::default(); + basic_tx_with_ether_and_to_key6.action = Action::Call(Address::from("e57bfe9f44b819898f47bf37e5af72a0783e1141")); + basic_tx_with_ether_and_to_key6.value = U256::from(123123); + + let genesis = client.block_hash(BlockId::Latest).unwrap(); + + assert!(filter.transaction_allowed(&genesis, &basic_tx.clone().sign(key1.secret(), None), &*client)); + assert!(filter.transaction_allowed(&genesis, &create_tx.clone().sign(key1.secret(), None), &*client)); + assert!(filter.transaction_allowed(&genesis, &call_tx.clone().sign(key1.secret(), None), &*client)); + + assert!(filter.transaction_allowed(&genesis, &basic_tx.clone().sign(key2.secret(), None), &*client)); + assert!(!filter.transaction_allowed(&genesis, &create_tx.clone().sign(key2.secret(), None), &*client)); + assert!(filter.transaction_allowed(&genesis, &call_tx.clone().sign(key2.secret(), None), &*client)); + + assert!(filter.transaction_allowed(&genesis, &basic_tx.clone().sign(key3.secret(), None), &*client)); + assert!(!filter.transaction_allowed(&genesis, &create_tx.clone().sign(key3.secret(), None), &*client)); + assert!(!filter.transaction_allowed(&genesis, &call_tx.clone().sign(key3.secret(), None), &*client)); + + assert!(!filter.transaction_allowed(&genesis, &basic_tx.clone().sign(key4.secret(), None), &*client)); + assert!(!filter.transaction_allowed(&genesis, &create_tx.clone().sign(key4.secret(), None), &*client)); + assert!(!filter.transaction_allowed(&genesis, &call_tx.clone().sign(key4.secret(), None), &*client)); + + assert!(filter.transaction_allowed(&genesis, &basic_tx.clone().sign(key1.secret(), None), &*client)); + assert!(filter.transaction_allowed(&genesis, &create_tx.clone().sign(key1.secret(), None), &*client)); + assert!(filter.transaction_allowed(&genesis, &call_tx.clone().sign(key1.secret(), None), &*client)); + + assert!(!filter.transaction_allowed(&genesis, &basic_tx_with_ether_and_to_key7.clone().sign(key5.secret(), None), &*client)); + assert!(!filter.transaction_allowed(&genesis, &call_tx_with_ether.clone().sign(key5.secret(), None), &*client)); + assert!(filter.transaction_allowed(&genesis, &basic_tx.clone().sign(key6.secret(), None), &*client)); + assert!(filter.transaction_allowed(&genesis, &basic_tx_with_ether_and_to_key7.clone().sign(key6.secret(), None), &*client)); + assert!(filter.transaction_allowed(&genesis, &basic_tx_to_key6.clone().sign(key7.secret(), None), &*client)); + assert!(!filter.transaction_allowed(&genesis, &basic_tx_with_ether_and_to_key6.clone().sign(key7.secret(), None), &*client)); + } + + /// Contract code: https://gist.github.com/arkpar/38a87cb50165b7e683585eec71acb05a + #[test] + fn transaction_filter_deprecated() { + let spec_data = include_str!("../res/tx_permission_tests/deprecated_contract_genesis.json"); + + let db = test_helpers::new_db(); + let tempdir = TempDir::new("").unwrap(); + let spec = Spec::load(&tempdir.path(), spec_data.as_bytes()).unwrap(); + + let client = Client::new( + ClientConfig::default(), + &spec, + db, Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); @@ -198,4 +272,3 @@ mod test { assert!(!filter.transaction_allowed(&genesis, &call_tx.clone().sign(key4.secret(), None), &*client)); } } - diff --git a/ethcore/src/verification/canon_verifier.rs b/ethcore/src/verification/canon_verifier.rs index 3d0fd77c6e5bc906a51be6a964365b76ef64293c..0ace8987e0b01c8ef5f26283d24f03292fcccdbd 100644 --- a/ethcore/src/verification/canon_verifier.rs +++ b/ethcore/src/verification/canon_verifier.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/verification/mod.rs b/ethcore/src/verification/mod.rs index d5fd4e847610fbcda6f5e844283070955fbc6bb9..fdb04df8647a8b41cc1491486d5bb7ca665b1da0 100644 --- a/ethcore/src/verification/mod.rs +++ b/ethcore/src/verification/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -16,8 +16,8 @@ //! Block verification utilities. -pub mod verification; -pub mod verifier; +mod verification; +mod verifier; pub mod queue; mod canon_verifier; mod noop_verifier; @@ -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/src/verification/noop_verifier.rs b/ethcore/src/verification/noop_verifier.rs index 24b117bbc16afbfe19801cce3912741525adc535..d04eec9b113cfc0c55bc5088a14009b39e28e8ed 100644 --- a/ethcore/src/verification/noop_verifier.rs +++ b/ethcore/src/verification/noop_verifier.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/verification/queue/kind.rs b/ethcore/src/verification/queue/kind.rs index ce9bddf4efea6b35a877fe5734e1528e6420db85..fbc6346c9c00d06ff50d67fef3905f6e94c91e24 100644 --- a/ethcore/src/verification/queue/kind.rs +++ b/ethcore/src/verification/queue/kind.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -72,6 +72,7 @@ pub mod blocks { use error::{Error, ErrorKind, BlockError}; use header::Header; use verification::{PreverifiedBlock, verify_block_basic, verify_block_unordered}; + use transaction::UnverifiedTransaction; use heapsize::HeapSizeOf; use ethereum_types::{H256, U256}; @@ -86,7 +87,7 @@ pub mod blocks { type Verified = PreverifiedBlock; fn create(input: Self::Input, engine: &EthEngine) -> Result { - match verify_block_basic(&input.header, &input.bytes, engine) { + match verify_block_basic(&input, engine) { Ok(()) => Ok(input), Err(Error(ErrorKind::Block(BlockError::TemporarilyInvalid(oob)), _)) => { debug!(target: "client", "Block received too early {}: {:?}", input.hash(), oob); @@ -101,7 +102,7 @@ pub mod blocks { fn verify(un: Self::Unverified, engine: &EthEngine, check_seal: bool) -> Result { let hash = un.hash(); - match verify_block_unordered(un.header, un.bytes, engine, check_seal) { + match verify_block_unordered(un, engine, check_seal) { Ok(verified) => Ok(verified), Err(e) => { warn!(target: "client", "Stage 2 block verification failed for {}: {:?}", hash, e); @@ -113,25 +114,43 @@ pub mod blocks { /// An unverified block. pub struct Unverified { - header: Header, - bytes: Bytes, + /// Unverified block header. + pub header: Header, + /// Unverified block transactions. + pub transactions: Vec, + /// Unverified block uncles. + pub uncles: Vec
, + /// Raw block bytes. + pub bytes: Bytes, } impl Unverified { /// Create an `Unverified` from raw bytes. pub fn from_rlp(bytes: Bytes) -> Result { + use rlp::Rlp; + let (header, transactions, uncles) = { + let rlp = Rlp::new(&bytes); + let header = rlp.val_at(0)?; + let transactions = rlp.list_at(1)?; + let uncles = rlp.list_at(2)?; + (header, transactions, uncles) + }; - let header = ::rlp::Rlp::new(&bytes).val_at(0)?; Ok(Unverified { - header: header, - bytes: bytes, + header, + transactions, + uncles, + bytes, }) } } impl HeapSizeOf for Unverified { fn heap_size_of_children(&self) -> usize { - self.header.heap_size_of_children() + self.bytes.heap_size_of_children() + self.header.heap_size_of_children() + + self.transactions.heap_size_of_children() + + self.uncles.heap_size_of_children() + + self.bytes.heap_size_of_children() } } diff --git a/ethcore/src/verification/queue/mod.rs b/ethcore/src/verification/queue/mod.rs index f7a558f33d15d058aab242b4caf2d3337c5f020f..5ae4f7c8fccf08888d86d66e3f49d3f8575003d0 100644 --- a/ethcore/src/verification/queue/mod.rs +++ b/ethcore/src/verification/queue/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index de2f6c7195d62c766be85ce16646beabf779716d..a0ecf963420bc3e39734539778ef04438ada8928 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -25,7 +25,6 @@ use std::collections::HashSet; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use bytes::Bytes; -use ethereum_types::H256; use hash::keccak; use heapsize::HeapSizeOf; use rlp::Rlp; @@ -37,8 +36,8 @@ use client::{BlockInfo, CallContract}; use engines::EthEngine; use error::{BlockError, Error}; use header::{BlockNumber, Header}; -use transaction::{SignedTransaction, UnverifiedTransaction}; -use views::BlockView; +use transaction::SignedTransaction; +use verification::queue::kind::blocks::Unverified; /// Preprocessed block data gathered in `verify_block_unordered` call pub struct PreverifiedBlock { @@ -46,6 +45,8 @@ pub struct PreverifiedBlock { pub header: Header, /// Populated block transactions pub transactions: Vec, + /// Populated block uncles + pub uncles: Vec
, /// Block bytes pub bytes: Bytes, } @@ -59,63 +60,66 @@ impl HeapSizeOf for PreverifiedBlock { } /// Phase 1 quick block verification. Only does checks that are cheap. Operates on a single block -pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &EthEngine) -> Result<(), Error> { - verify_header_params(&header, engine, true)?; - verify_block_integrity(bytes, &header.transactions_root(), &header.uncles_hash())?; - engine.verify_block_basic(&header)?; - for u in Rlp::new(bytes).at(2)?.iter().map(|rlp| rlp.as_val::
()) { - let u = u?; - verify_header_params(&u, engine, false)?; - engine.verify_block_basic(&u)?; +pub fn verify_block_basic(block: &Unverified, engine: &EthEngine) -> Result<(), Error> { + verify_header_params(&block.header, engine, true)?; + verify_block_integrity(block)?; + engine.verify_block_basic(&block.header)?; + + for uncle in &block.uncles { + verify_header_params(uncle, engine, false)?; + engine.verify_block_basic(uncle)?; } - for t in Rlp::new(bytes).at(1)?.iter().map(|rlp| rlp.as_val::()) { - engine.verify_transaction_basic(&t?, &header)?; + for t in &block.transactions { + engine.verify_transaction_basic(t, &block.header)?; } + Ok(()) } /// Phase 2 verification. Perform costly checks such as transaction signatures and block nonce for ethash. /// Still operates on a individual block /// Returns a `PreverifiedBlock` structure populated with transactions -pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &EthEngine, check_seal: bool) -> Result { +pub fn verify_block_unordered(block: Unverified, engine: &EthEngine, check_seal: bool) -> Result { + let header = block.header; if check_seal { engine.verify_block_unordered(&header)?; - for u in Rlp::new(&bytes).at(2)?.iter().map(|rlp| rlp.as_val::
()) { - engine.verify_block_unordered(&u?)?; + for uncle in &block.uncles { + engine.verify_block_unordered(uncle)?; } } // Verify transactions. - let mut transactions = Vec::new(); let nonce_cap = if header.number() >= engine.params().dust_protection_transition { Some((engine.params().nonce_cap_increment * header.number()).into()) - } else { None }; - { - let v = view!(BlockView, &bytes); - for t in v.transactions() { + } else { + None + }; + + let transactions = block.transactions + .into_iter() + .map(|t| { let t = engine.verify_transaction_unordered(t, &header)?; if let Some(max_nonce) = nonce_cap { if t.nonce >= max_nonce { return Err(BlockError::TooManyTransactions(t.sender()).into()); } } - transactions.push(t); - } - } + Ok(t) + }) + .collect::, Error>>()?; + Ok(PreverifiedBlock { - header: header, - transactions: transactions, - bytes: bytes, + header, + transactions, + uncles: block.uncles, + bytes: block.bytes, }) } /// Parameters for full verification of block family pub struct FullFamilyParams<'a, C: BlockInfo + CallContract + 'a> { - /// Serialized block bytes - pub block_bytes: &'a [u8], - - /// Signed transactions - pub transactions: &'a [SignedTransaction], + /// Preverified block + pub block: &'a PreverifiedBlock, /// Block provider to use during verification pub block_provider: &'a BlockProvider, @@ -135,17 +139,18 @@ pub fn verify_block_family(header: &Header, parent: None => return Ok(()), }; - verify_uncles(header, params.block_bytes, params.block_provider, engine)?; + verify_uncles(params.block, params.block_provider, engine)?; - for transaction in params.transactions { - engine.machine().verify_transaction(transaction, header, params.client)?; + for tx in ¶ms.block.transactions { + engine.machine().verify_transaction(tx, header, params.client)?; } Ok(()) } -fn verify_uncles(header: &Header, bytes: &[u8], bc: &BlockProvider, engine: &EthEngine) -> Result<(), Error> { - let num_uncles = Rlp::new(bytes).at(2)?.item_count()?; +fn verify_uncles(block: &PreverifiedBlock, bc: &BlockProvider, engine: &EthEngine) -> Result<(), Error> { + let header = &block.header; + let num_uncles = block.uncles.len(); let max_uncles = engine.maximum_uncle_count(header.number()); if num_uncles != 0 { if num_uncles > max_uncles { @@ -174,8 +179,7 @@ fn verify_uncles(header: &Header, bytes: &[u8], bc: &BlockProvider, engine: &Eth } let mut verified = HashSet::new(); - for uncle in Rlp::new(bytes).at(2)?.iter().map(|rlp| rlp.as_val::
()) { - let uncle = uncle?; + for uncle in &block.uncles { if excluded.contains(&uncle.hash()) { return Err(From::from(BlockError::UncleInChain(uncle.hash()))) } @@ -332,16 +336,22 @@ fn verify_parent(header: &Header, parent: &Header, engine: &EthEngine) -> Result } /// Verify block data against header: transactions root and uncles hash. -fn verify_block_integrity(block: &[u8], transactions_root: &H256, uncles_hash: &H256) -> Result<(), Error> { - let block = Rlp::new(block); - let tx = block.at(1)?; - let expected_root = &ordered_trie_root(tx.iter().map(|r| r.as_raw())); - if expected_root != transactions_root { - return Err(From::from(BlockError::InvalidTransactionsRoot(Mismatch { expected: expected_root.clone(), found: transactions_root.clone() }))) - } - let expected_uncles = &keccak(block.at(2)?.as_raw()); - if expected_uncles != uncles_hash { - return Err(From::from(BlockError::InvalidUnclesHash(Mismatch { expected: expected_uncles.clone(), found: uncles_hash.clone() }))) +fn verify_block_integrity(block: &Unverified) -> Result<(), Error> { + let block_rlp = Rlp::new(&block.bytes); + let tx = block_rlp.at(1)?; + let expected_root = ordered_trie_root(tx.iter().map(|r| r.as_raw())); + if &expected_root != block.header.transactions_root() { + bail!(BlockError::InvalidTransactionsRoot(Mismatch { + expected: expected_root, + found: *block.header.transactions_root(), + })); + } + let expected_uncles = keccak(block_rlp.at(2)?.as_raw()); + if &expected_uncles != block.header.uncles_hash(){ + bail!(BlockError::InvalidUnclesHash(Mismatch { + expected: expected_uncles, + found: *block.header.uncles_hash(), + })); } Ok(()) } @@ -352,7 +362,7 @@ mod tests { use std::collections::{BTreeMap, HashMap}; use std::time::{SystemTime, UNIX_EPOCH}; - use ethereum_types::{H256, Bloom, U256}; + use ethereum_types::{H256, BloomRef, U256}; use blockchain::{BlockDetails, TransactionAddress, BlockReceipts}; use encoded; use hash::keccak; @@ -366,6 +376,7 @@ mod tests { use types::log_entry::{LogEntry, LocalizedLogEntry}; use rlp; use triehash::ordered_trie_root; + use views::BlockView; fn check_ok(result: Result<(), Error>) { result.unwrap_or_else(|e| panic!("Block verification failed: {:?}", e)); @@ -456,7 +467,6 @@ mod tests { parent: header.parent_hash().clone(), children: Vec::new(), is_finalized: false, - metadata: None, } }) } @@ -474,7 +484,8 @@ mod tests { unimplemented!() } - fn blocks_with_bloom(&self, _bloom: &Bloom, _from_block: BlockNumber, _to_block: BlockNumber) -> Vec { + fn blocks_with_bloom<'a, B, I, II>(&self, _blooms: II, _from_block: BlockNumber, _to_block: BlockNumber) -> Vec + where BloomRef<'a>: From, II: IntoIterator + Copy, I: Iterator, Self: Sized { unimplemented!() } @@ -485,8 +496,8 @@ mod tests { } fn basic_test(bytes: &[u8], engine: &EthEngine) -> Result<(), Error> { - let header = view!(BlockView, bytes).header(); - verify_block_basic(&header, bytes, engine) + let unverified = Unverified::from_rlp(bytes.to_vec())?; + verify_block_basic(&unverified, engine) } fn family_test(bytes: &[u8], engine: &EthEngine, bc: &BC) -> Result<(), Error> where BC: BlockProvider { @@ -506,18 +517,25 @@ mod tests { .ok_or(BlockError::UnknownParent(header.parent_hash().clone()))? .decode()?; + let block = PreverifiedBlock { + header, + transactions, + uncles: view.uncles(), + bytes: bytes.to_vec(), + }; + let full_params = FullFamilyParams { - block_bytes: bytes, - transactions: &transactions[..], + block: &block, block_provider: bc as &BlockProvider, client: &client, }; - verify_block_family(&header, &parent, engine, Some(full_params)) + verify_block_family(&block.header, &parent, engine, Some(full_params)) } fn unordered_test(bytes: &[u8], engine: &EthEngine) -> Result<(), Error> { - let header = view!(BlockView, bytes).header(); - verify_block_unordered(header, bytes.to_vec(), engine, false)?; + use verification::queue::kind::blocks::Unverified; + let un = Unverified::from_rlp(bytes.to_vec())?; + verify_block_unordered(un, engine, false)?; Ok(()) } @@ -576,7 +594,17 @@ mod tests { nonce: U256::from(2) }.sign(keypair.secret(), None); + let tr3 = Transaction { + action: Action::Call(0x0.into()), + value: U256::from(0), + data: Bytes::new(), + gas: U256::from(30_000), + gas_price: U256::from(0), + nonce: U256::zero(), + }.null_sign(0); + let good_transactions = [ tr1.clone(), tr2.clone() ]; + let eip86_transactions = [ tr3.clone() ]; let diff_inc = U256::from(0x40); @@ -612,6 +640,7 @@ mod tests { uncles_rlp.append_list(&good_uncles); let good_uncles_hash = keccak(uncles_rlp.as_raw()); let good_transactions_root = ordered_trie_root(good_transactions.iter().map(|t| ::rlp::encode::(t))); + let eip86_transactions_root = ordered_trie_root(eip86_transactions.iter().map(|t| ::rlp::encode::(t))); let mut parent = good.clone(); parent.set_number(9); @@ -632,6 +661,14 @@ mod tests { check_ok(basic_test(&create_test_block(&good), engine)); + let mut bad_header = good.clone(); + bad_header.set_transactions_root(eip86_transactions_root.clone()); + bad_header.set_uncles_hash(good_uncles_hash.clone()); + match basic_test(&create_test_block_with_data(&bad_header, &eip86_transactions, &good_uncles), engine) { + Err(Error(ErrorKind::Transaction(ref e), _)) if e == &::ethkey::Error::InvalidSignature.into() => (), + e => panic!("Block verification failed.\nExpected: Transaction Error (Invalid Signature)\nGot: {:?}", e), + } + let mut header = good.clone(); header.set_transactions_root(good_transactions_root.clone()); header.set_uncles_hash(good_uncles_hash.clone()); diff --git a/ethcore/src/verification/verifier.rs b/ethcore/src/verification/verifier.rs index a9ca22a4c8aa8534cd7fcb07c112606408cb361e..188254b4317fcbca14662817337d0c133ab67885 100644 --- a/ethcore/src/verification/verifier.rs +++ b/ethcore/src/verification/verifier.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/views/block.rs b/ethcore/src/views/block.rs index 3bed1818f24db7e0d9e41760505b8c182f9278ca..2a7c2ebd5310c87637e98f8e3a87df97f660c71d 100644 --- a/ethcore/src/views/block.rs +++ b/ethcore/src/views/block.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/views/body.rs b/ethcore/src/views/body.rs index d2864b97259452eb76ce7ea975435ea1edb80c31..6560140cad1e0a635c695c2304fd8fdfbf47e6cf 100644 --- a/ethcore/src/views/body.rs +++ b/ethcore/src/views/body.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/views/header.rs b/ethcore/src/views/header.rs index 8d407f0a1bba66af289a0cd3e5b39a44d78d35e1..4b7b1225d0213981645b2b264372c44ab41d7459 100644 --- a/ethcore/src/views/header.rs +++ b/ethcore/src/views/header.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/views/mod.rs b/ethcore/src/views/mod.rs index b9cbad88891a0c1cf54a9f29b518442b7f9ef166..6d326493825552ff6605de7fc0ed9859ae366782 100644 --- a/ethcore/src/views/mod.rs +++ b/ethcore/src/views/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -38,4 +38,4 @@ mod tests { fn should_include_file_line_number_in_panic_for_invalid_rlp() { let _ = view!(HeaderView, &[]).parent_hash(); } -} \ No newline at end of file +} diff --git a/ethcore/src/views/transaction.rs b/ethcore/src/views/transaction.rs index 5607482b309165411f59d064de4fa0caf980d7e0..911fde944e3f7292cae820bee69ead9d8734a5c6 100644 --- a/ethcore/src/views/transaction.rs +++ b/ethcore/src/views/transaction.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/views/view_rlp.rs b/ethcore/src/views/view_rlp.rs index 6afdb3af8c0a8ef8918860e5efb7c7bffd545f98..2dd1b33a946915b017d066dae46eb7705351e90e 100644 --- a/ethcore/src/views/view_rlp.rs +++ b/ethcore/src/views/view_rlp.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -39,10 +39,10 @@ impl<'a, 'view> ViewRlp<'a> where 'a : 'view { /// Returns a new instance replacing existing rlp with new rlp, maintaining debug info fn new_from_rlp(&self, rlp: Rlp<'a>) -> Self { - ViewRlp { - rlp, + ViewRlp { + rlp, file: self.file, - line: self.line + line: self.line } } @@ -53,7 +53,12 @@ impl<'a, 'view> ViewRlp<'a> where 'a : 'view { } fn expect_valid_rlp(&self, r: Result) -> T { - r.expect(&format!("View rlp is trusted and should be valid. Constructed in {} on line {}", self.file, self.line)) + r.unwrap_or_else(|e| panic!( + "View rlp is trusted and should be valid. Constructed in {} on line {}: {}", + self.file, + self.line, + e + )) } /// Returns rlp at the given index, panics if no rlp at that index @@ -75,7 +80,7 @@ impl<'a, 'view> ViewRlp<'a> where 'a : 'view { /// Returns decoded value at the given index, panics not present or valid at that index pub fn val_at(&self, index: usize) -> T where T : Decodable { self.expect_valid_rlp(self.rlp.val_at(index)) - } + } /// Returns decoded list of values, panics if rlp is invalid pub fn list_at(&self, index: usize) -> Vec where T: Decodable { @@ -127,4 +132,4 @@ macro_rules! view { ($view: ident, $bytes: expr) => { $view::new($crate::views::ViewRlp::new($bytes, file!(), line!())) }; -} \ No newline at end of file +} diff --git a/ethcore/stratum/Cargo.toml b/ethcore/stratum/Cargo.toml index bf967df504aef39d351064db9b2c1517fb874d40..1da27c01a9f38080afd1cd0fba42d0f45998550b 100644 --- a/ethcore/stratum/Cargo.toml +++ b/ethcore/stratum/Cargo.toml @@ -7,12 +7,12 @@ authors = ["Parity Technologies "] [dependencies] ethereum-types = "0.3" -keccak-hash = { path = "../../util/hash" } +keccak-hash = { git = "https://github.com/paritytech/parity-common" } jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } 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/stratum/src/lib.rs b/ethcore/stratum/src/lib.rs index a4abeffd73e22db0315685e09f97f1a6f249967e..0e9de9b43c54928dcd1104394c596e836b0eaece 100644 --- a/ethcore/stratum/src/lib.rs +++ b/ethcore/stratum/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/stratum/src/traits.rs b/ethcore/stratum/src/traits.rs index 431d338a428f15dd9a108fc8bc2a5b0e2e40e30f..d1bb9a4da731b14aa1f37037d0a0027c28d33897 100644 --- a/ethcore/stratum/src/traits.rs +++ b/ethcore/stratum/src/traits.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/Cargo.toml b/ethcore/sync/Cargo.toml index cf163cc7bd5559e78471e9e2f8f8f6c403a17995..dfd457772331f3a24485f086476861f32b0c5eed 100644 --- a/ethcore/sync/Cargo.toml +++ b/ethcore/sync/Cargo.toml @@ -8,7 +8,7 @@ authors = ["Parity Technologies "] [lib] [dependencies] -ethcore-bytes = { path = "../../util/bytes" } +parity-bytes = { git = "https://github.com/paritytech/parity-common" } ethcore-network = { path = "../../util/network" } ethcore-network-devp2p = { path = "../../util/network-devp2p" } ethcore-io = { path = "../../util/io" } @@ -16,12 +16,14 @@ ethcore-light = { path = "../light" } ethcore-transaction = { path = "../transaction" } ethcore = { path = ".." } ethereum-types = "0.3" -plain_hasher = { path = "../../util/plain_hasher" } -rlp = { path = "../../util/rlp" } +hashdb = { git = "https://github.com/paritytech/parity-common" } +plain_hasher = { git = "https://github.com/paritytech/parity-common" } +rlp = { git = "https://github.com/paritytech/parity-common" } rustc-hex = "1.0" -keccak-hash = { path = "../../util/hash" } -triehash = { path = "../../util/triehash" } -kvdb = { path = "../../util/kvdb" } +keccak-hash = { git = "https://github.com/paritytech/parity-common" } +keccak-hasher = { path = "../../util/keccak-hasher" } +triehash-ethereum = {version = "0.2", path = "../../util/triehash-ethereum" } +kvdb = { git = "https://github.com/paritytech/parity-common" } macros = { path = "../../util/macros" } log = "0.3" env_logger = "0.4" @@ -29,12 +31,13 @@ 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" [dev-dependencies] ethcore-io = { path = "../../util/io", features = ["mio"] } ethkey = { path = "../../ethkey" } -kvdb-memorydb = { path = "../../util/kvdb-memorydb" } +kvdb-memorydb = { git = "https://github.com/paritytech/parity-common" } ethcore-private-tx = { path = "../private-tx" } +ethcore = { path = "..", features = ["test-helpers"] } diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index 9e6cdafa6eca58b2b6d781241f29dd1a6d6eb6bb..ef54a4802d9376f1a4bd684256dde4c005cf4466 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -21,7 +21,7 @@ use std::ops::Range; use std::time::Duration; use bytes::Bytes; use devp2p::NetworkService; -use network::{NetworkProtocolHandler, NetworkContext, HostInfo, PeerId, ProtocolId, +use network::{NetworkProtocolHandler, NetworkContext, PeerId, ProtocolId, NetworkConfiguration as BasicNetworkConfiguration, NonReservedPeerMode, Error, ErrorKind, ConnectionFilter}; use ethereum_types::{H256, H512, U256}; @@ -359,6 +359,10 @@ impl SyncProvider for EthSync { } } +const PEERS_TIMER: TimerToken = 0; +const SYNC_TIMER: TimerToken = 1; +const TX_TIMER: TimerToken = 2; + struct SyncProtocolHandler { /// Shared blockchain client. chain: Arc, @@ -371,14 +375,15 @@ struct SyncProtocolHandler { } impl NetworkProtocolHandler for SyncProtocolHandler { - fn initialize(&self, io: &NetworkContext, _host_info: &HostInfo) { + fn initialize(&self, io: &NetworkContext) { if io.subprotocol_name() != WARP_SYNC_PROTOCOL_ID { - io.register_timer(0, Duration::from_secs(1)).expect("Error registering sync timer"); + io.register_timer(PEERS_TIMER, Duration::from_millis(700)).expect("Error registering peers timer"); + io.register_timer(SYNC_TIMER, Duration::from_millis(1100)).expect("Error registering sync timer"); + io.register_timer(TX_TIMER, Duration::from_millis(1300)).expect("Error registering transactions timer"); } } 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); } @@ -399,12 +404,17 @@ impl NetworkProtocolHandler for SyncProtocolHandler { } } - fn timeout(&self, io: &NetworkContext, _timer: TimerToken) { + fn timeout(&self, io: &NetworkContext, timer: TimerToken) { trace_time!("sync::timeout"); let mut io = NetSyncIo::new(io, &*self.chain, &*self.snapshot_service, &self.overlay); - self.sync.write().maintain_peers(&mut io); - self.sync.write().maintain_sync(&mut io); - self.sync.write().propagate_new_transactions(&mut io); + match timer { + PEERS_TIMER => self.sync.write().maintain_peers(&mut io), + SYNC_TIMER => self.sync.write().maintain_sync(&mut io), + TX_TIMER => { + self.sync.write().propagate_new_transactions(&mut io); + }, + _ => warn!("Unknown timer {} triggered.", timer), + } } } @@ -536,7 +546,6 @@ pub trait ManageNetwork : Send + Sync { fn with_proto_context(&self, proto: ProtocolId, f: &mut FnMut(&NetworkContext)); } - impl ManageNetwork for EthSync { fn accept_unreserved_peers(&self) { self.network.set_non_reserved_mode(NonReservedPeerMode::Accept); diff --git a/ethcore/sync/src/block_sync.rs b/ethcore/sync/src/block_sync.rs index 7411fa30ccf3aa132fc67e7b9f1373efc9a99677..588bfc0c711b1c96d4e67b69043ec8f5fdd96302 100644 --- a/ethcore/sync/src/block_sync.rs +++ b/ethcore/sync/src/block_sync.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -22,12 +22,11 @@ use std::collections::{HashSet, VecDeque}; use std::cmp; use heapsize::HeapSizeOf; use ethereum_types::H256; -use rlp::Rlp; -use ethcore::views::BlockView; +use rlp::{self, Rlp}; use ethcore::header::{BlockNumber, Header as BlockHeader}; use ethcore::client::{BlockStatus, BlockId, BlockImportError, BlockImportErrorKind}; -use ethcore::block::Block; use ethcore::error::{ImportErrorKind, BlockError}; +use ethcore::verification::queue::kind::blocks::Unverified; use sync_io::SyncIo; use blocks::BlockCollection; @@ -76,12 +75,18 @@ pub enum DownloadAction { #[derive(Eq, PartialEq, Debug)] pub enum BlockDownloaderImportError { - /// Imported data is rejected as invalid. + /// Imported data is rejected as invalid. Peer should be dropped. Invalid, /// Imported data is valid but rejected cause the downloader does not need it. Useless, } +impl From for BlockDownloaderImportError { + fn from(_: rlp::DecoderError) -> BlockDownloaderImportError { + BlockDownloaderImportError::Invalid + } +} + /// Block downloader strategy. /// Manages state and block data for a block download process. pub struct BlockDownloader { @@ -316,7 +321,7 @@ impl BlockDownloader { } /// Called by peer once it has new block bodies - pub fn import_bodies(&mut self, _io: &mut SyncIo, r: &Rlp) -> Result<(), BlockDownloaderImportError> { + pub fn import_bodies(&mut self, r: &Rlp) -> Result<(), BlockDownloaderImportError> { let item_count = r.item_count().unwrap_or(0); if item_count == 0 { return Err(BlockDownloaderImportError::Useless); @@ -477,17 +482,19 @@ impl BlockDownloader { for block_and_receipts in blocks { let block = block_and_receipts.block; let receipts = block_and_receipts.receipts; - let (h, number, parent) = { - let header = view!(BlockView, &block).header_view(); - (header.hash(), header.number(), header.parent_hash()) + + let block = match Unverified::from_rlp(block) { + Ok(block) => block, + Err(_) => { + debug!(target: "sync", "Bad block rlp"); + bad = true; + break; + } }; - // Perform basic block verification - if !Block::is_good(&block) { - debug!(target: "sync", "Bad block rlp {:?} : {:?}", h, block); - bad = true; - break; - } + let h = block.header.hash(); + let number = block.header.number(); + let parent = *block.header.parent_hash(); if self.target_hash.as_ref().map_or(false, |t| t == &h) { self.state = State::Complete; diff --git a/ethcore/sync/src/blocks.rs b/ethcore/sync/src/blocks.rs index 283f4ed610dde27ce3daf4194db5bc50d75077a1..248180b281d9d5f15217185e7e48f0e95836bb2a 100644 --- a/ethcore/sync/src/blocks.rs +++ b/ethcore/sync/src/blocks.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,13 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::collections::{HashSet, HashMap}; -use std::collections::hash_map::Entry; +use std::collections::{HashSet, HashMap, hash_map}; use smallvec::SmallVec; use hash::{keccak, KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP}; use heapsize::HeapSizeOf; use ethereum_types::H256; -use triehash::ordered_trie_root; +use triehash_ethereum::ordered_trie_root; use bytes::Bytes; use rlp::{Rlp, RlpStream, DecoderError}; use network; @@ -194,7 +193,6 @@ impl BlockCollection { needed_bodies } - /// Returns a set of block hashes that require a receipt download. The returned set is marked as being downloaded. pub fn needed_receipts(&mut self, count: usize, _ignore_downloading: bool) -> Vec { if self.head.is_none() || !self.need_receipts { @@ -296,7 +294,7 @@ impl BlockCollection { let header = view!(HeaderView, &block.header); let block_view = Block::new_from_header_and_body(&header, &body); drained.push(BlockAndReceipts { - block: block_view.rlp().as_raw().to_vec(), + block: block_view.into_inner(), receipts: block.receipts.clone(), }); } @@ -381,7 +379,7 @@ impl BlockCollection { }; self.downloading_receipts.remove(&receipt_root); match self.receipt_ids.entry(receipt_root) { - Entry::Occupied(entry) => { + hash_map::Entry::Occupied(entry) => { for h in entry.remove() { match self.blocks.get_mut(&h) { Some(ref mut block) => { @@ -395,8 +393,8 @@ impl BlockCollection { } } Ok(()) - } - _ => { + }, + hash_map::Entry::Vacant(_) => { trace!(target: "sync", "Ignored unknown/stale block receipt {:?}", receipt_root); Err(network::ErrorKind::BadProtocol.into()) } @@ -616,4 +614,3 @@ mod test { assert_eq!(bc.drain().len(), 2); } } - diff --git a/ethcore/sync/src/chain/handler.rs b/ethcore/sync/src/chain/handler.rs index 7668a6459457591319a15109ee5eb5dc56c4f9b9..8547be7b3ff05823afa6088bb1a7fc5d7d10df1d 100644 --- a/ethcore/sync/src/chain/handler.rs +++ b/ethcore/sync/src/chain/handler.rs @@ -19,8 +19,9 @@ use block_sync::{BlockDownloaderImportError as DownloaderImportError, DownloadAc use bytes::Bytes; use ethcore::client::{BlockStatus, BlockId, BlockImportError, BlockImportErrorKind}; use ethcore::error::*; -use ethcore::header::{BlockNumber, Header as BlockHeader}; +use ethcore::header::BlockNumber; use ethcore::snapshot::{ManifestData, RestorationStatus}; +use ethcore::verification::queue::kind::blocks::Unverified; use ethereum_types::{H256, U256}; use hash::keccak; use network::PeerId; @@ -87,9 +88,23 @@ impl SyncHandler { Ok(()) } }; - result.unwrap_or_else(|e| { - debug!(target:"sync", "{} -> Malformed packet {} : {}", peer, packet_id, e); - }) + + match result { + Err(DownloaderImportError::Invalid) => { + debug!(target:"sync", "{} -> Invalid packet {}", peer, packet_id); + io.disable_peer(peer); + sync.deactivate_peer(io, peer); + }, + Err(DownloaderImportError::Useless) => { + sync.deactivate_peer(io, peer); + }, + Ok(()) => { + // give a task to the same peer first + sync.sync_peer(io, peer, false); + }, + } + // give tasks to other peers + sync.continue_sync(io); } /// Called when peer sends us new consensus packet @@ -137,7 +152,7 @@ impl SyncHandler { } /// Called by peer once it has new block bodies - pub fn on_peer_new_block(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + pub fn on_peer_new_block(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), DownloaderImportError> { if !sync.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { trace!(target: "sync", "Ignoring new block from unconfirmed peer {}", peer_id); return Ok(()); @@ -148,63 +163,60 @@ impl SyncHandler { peer.difficulty = Some(difficulty); } } - let block_rlp = r.at(0)?; - let header_rlp = block_rlp.at(0)?; - let h = keccak(&header_rlp.as_raw()); - trace!(target: "sync", "{} -> NewBlock ({})", peer_id, h); - let header: BlockHeader = header_rlp.as_val()?; - if header.number() > sync.highest_block.unwrap_or(0) { - sync.highest_block = Some(header.number()); + let block = Unverified::from_rlp(r.at(0)?.as_raw().to_vec())?; + let hash = block.header.hash(); + let number = block.header.number(); + trace!(target: "sync", "{} -> NewBlock ({})", peer_id, hash); + if number > sync.highest_block.unwrap_or(0) { + sync.highest_block = Some(number); } let mut unknown = false; - { - if let Some(ref mut peer) = sync.peers.get_mut(&peer_id) { - peer.latest_hash = header.hash(); - } + + if let Some(ref mut peer) = sync.peers.get_mut(&peer_id) { + peer.latest_hash = hash; } + let last_imported_number = sync.new_blocks.last_imported_block_number(); - if last_imported_number > header.number() && last_imported_number - header.number() > MAX_NEW_BLOCK_AGE { - trace!(target: "sync", "Ignored ancient new block {:?}", h); - io.disable_peer(peer_id); - return Ok(()); + if last_imported_number > number && last_imported_number - number > MAX_NEW_BLOCK_AGE { + trace!(target: "sync", "Ignored ancient new block {:?}", hash); + return Err(DownloaderImportError::Invalid); } - match io.chain().import_block(block_rlp.as_raw().to_vec()) { + match io.chain().import_block(block) { Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain), _)) => { - trace!(target: "sync", "New block already in chain {:?}", h); + trace!(target: "sync", "New block already in chain {:?}", hash); }, Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyQueued), _)) => { - trace!(target: "sync", "New block already queued {:?}", h); + trace!(target: "sync", "New block already queued {:?}", hash); }, Ok(_) => { // abort current download of the same block sync.complete_sync(io); - sync.new_blocks.mark_as_known(&header.hash(), header.number()); - trace!(target: "sync", "New block queued {:?} ({})", h, header.number()); + sync.new_blocks.mark_as_known(&hash, number); + trace!(target: "sync", "New block queued {:?} ({})", hash, number); }, Err(BlockImportError(BlockImportErrorKind::Block(BlockError::UnknownParent(p)), _)) => { unknown = true; - trace!(target: "sync", "New block with unknown parent ({:?}) {:?}", p, h); + trace!(target: "sync", "New block with unknown parent ({:?}) {:?}", p, hash); }, Err(e) => { - debug!(target: "sync", "Bad new block {:?} : {:?}", h, e); - io.disable_peer(peer_id); + debug!(target: "sync", "Bad new block {:?} : {:?}", hash, e); + return Err(DownloaderImportError::Invalid); } }; if unknown { if sync.state != SyncState::Idle { trace!(target: "sync", "NewBlock ignored while seeking"); } else { - trace!(target: "sync", "New unknown block {:?}", h); + trace!(target: "sync", "New unknown block {:?}", hash); //TODO: handle too many unknown blocks sync.sync_peer(io, peer_id, true); } } - sync.continue_sync(io); Ok(()) } /// Handles `NewHashes` packet. Initiates headers download for any unknown hashes. - pub fn on_peer_new_hashes(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + pub fn on_peer_new_hashes(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), DownloaderImportError> { if !sync.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { trace!(target: "sync", "Ignoring new hashes from unconfirmed peer {}", peer_id); return Ok(()); @@ -223,7 +235,6 @@ impl SyncHandler { if max > sync.highest_block.unwrap_or(0) { sync.highest_block = Some(max); } - sync.continue_sync(io); return Ok(()); } trace!(target: "sync", "{} -> NewHashes ({} entries)", peer_id, r.item_count()?); @@ -241,8 +252,7 @@ impl SyncHandler { } if last_imported_number > number && last_imported_number - number > MAX_NEW_BLOCK_AGE { trace!(target: "sync", "Ignored ancient new block hash {:?}", hash); - io.disable_peer(peer_id); - continue; + return Err(DownloaderImportError::Invalid); } match io.chain().block_status(BlockId::Hash(hash.clone())) { BlockStatus::InChain => { @@ -263,8 +273,7 @@ impl SyncHandler { }, BlockStatus::Bad => { debug!(target: "sync", "Bad new block hash {:?}", hash); - io.disable_peer(peer_id); - return Ok(()); + return Err(DownloaderImportError::Invalid); } } }; @@ -274,73 +283,46 @@ impl SyncHandler { sync.state = SyncState::NewBlocks; sync.sync_peer(io, peer_id, true); } - sync.continue_sync(io); Ok(()) } /// Called by peer once it has new block bodies - fn on_peer_block_bodies(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + fn on_peer_block_bodies(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), DownloaderImportError> { sync.clear_peer_download(peer_id); - let block_set = sync.peers.get(&peer_id).and_then(|p| p.block_set).unwrap_or(BlockSet::NewBlocks); + let block_set = sync.peers.get(&peer_id) + .and_then(|p| p.block_set) + .unwrap_or(BlockSet::NewBlocks); if !sync.reset_peer_asking(peer_id, PeerAsking::BlockBodies) { trace!(target: "sync", "{}: Ignored unexpected bodies", peer_id); - sync.continue_sync(io); return Ok(()); } let item_count = r.item_count()?; trace!(target: "sync", "{} -> BlockBodies ({} entries), set = {:?}", peer_id, item_count, block_set); if item_count == 0 { - sync.deactivate_peer(io, peer_id); - } - else if sync.state == SyncState::Waiting { + Err(DownloaderImportError::Useless) + } else if sync.state == SyncState::Waiting { trace!(target: "sync", "Ignored block bodies while waiting"); - } - else - { - let result = { + Ok(()) + } else { + { let downloader = match block_set { BlockSet::NewBlocks => &mut sync.new_blocks, BlockSet::OldBlocks => match sync.old_blocks { None => { trace!(target: "sync", "Ignored block headers while block download is inactive"); - sync.continue_sync(io); return Ok(()); }, Some(ref mut blocks) => blocks, } }; - downloader.import_bodies(io, r) - }; - - match result { - Err(DownloaderImportError::Invalid) => { - io.disable_peer(peer_id); - sync.deactivate_peer(io, peer_id); - sync.continue_sync(io); - return Ok(()); - }, - Err(DownloaderImportError::Useless) => { - sync.deactivate_peer(io, peer_id); - }, - Ok(()) => (), + downloader.import_bodies(r)?; } - sync.collect_blocks(io, block_set); - sync.sync_peer(io, peer_id, false); + Ok(()) } - sync.continue_sync(io); - Ok(()) } - fn on_peer_confirmed(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId) { - { - let peer = sync.peers.get_mut(&peer_id).expect("Is only called when peer is present in peers"); - peer.confirmation = ForkConfirmation::Confirmed; - } - sync.sync_peer(io, peer_id, false); - } - - fn on_peer_fork_header(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + fn on_peer_fork_header(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), DownloaderImportError> { { let peer = sync.peers.get_mut(&peer_id).expect("Is only called when peer is present in peers"); peer.asking = PeerAsking::Nothing; @@ -349,29 +331,30 @@ impl SyncHandler { if item_count == 0 || item_count != 1 { trace!(target: "sync", "{}: Chain is too short to confirm the block", peer_id); - io.disable_peer(peer_id); - return Ok(()); - } + peer.confirmation = ForkConfirmation::TooShort; - let header = r.at(0)?.as_raw(); - if keccak(&header) != fork_hash { - trace!(target: "sync", "{}: Fork mismatch", peer_id); - io.disable_peer(peer_id); - return Ok(()); - } + } else { + let header = r.at(0)?.as_raw(); + if keccak(&header) != fork_hash { + trace!(target: "sync", "{}: Fork mismatch", peer_id); + return Err(DownloaderImportError::Invalid); + } - trace!(target: "sync", "{}: Confirmed peer", peer_id); - if !io.chain_overlay().read().contains_key(&fork_number) { - trace!(target: "sync", "Inserting (fork) block {} header", fork_number); - io.chain_overlay().write().insert(fork_number, header.to_vec()); + trace!(target: "sync", "{}: Confirmed peer", peer_id); + peer.confirmation = ForkConfirmation::Confirmed; + + if !io.chain_overlay().read().contains_key(&fork_number) { + trace!(target: "sync", "Inserting (fork) block {} header", fork_number); + io.chain_overlay().write().insert(fork_number, header.to_vec()); + } } } - SyncHandler::on_peer_confirmed(sync, io, peer_id); + return Ok(()); } /// Called by peer once it has new block headers during sync - fn on_peer_block_headers(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + fn on_peer_block_headers(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), DownloaderImportError> { let is_fork_header_request = match sync.peers.get(&peer_id) { Some(peer) if peer.asking == PeerAsking::ForkHeader => true, _ => false, @@ -387,124 +370,83 @@ impl SyncHandler { let block_set = sync.peers.get(&peer_id).and_then(|p| p.block_set).unwrap_or(BlockSet::NewBlocks); if !sync.reset_peer_asking(peer_id, PeerAsking::BlockHeaders) || expected_hash.is_none() || !allowed { trace!(target: "sync", "{}: Ignored unexpected headers, expected_hash = {:?}", peer_id, expected_hash); - sync.continue_sync(io); return Ok(()); } let item_count = r.item_count()?; trace!(target: "sync", "{} -> BlockHeaders ({} entries), state = {:?}, set = {:?}", peer_id, item_count, sync.state, block_set); if (sync.state == SyncState::Idle || sync.state == SyncState::WaitingPeers) && sync.old_blocks.is_none() { trace!(target: "sync", "Ignored unexpected block headers"); - sync.continue_sync(io); return Ok(()); } if sync.state == SyncState::Waiting { trace!(target: "sync", "Ignored block headers while waiting"); - sync.continue_sync(io); return Ok(()); } - let result = { + let result = { let downloader = match block_set { BlockSet::NewBlocks => &mut sync.new_blocks, BlockSet::OldBlocks => { match sync.old_blocks { None => { trace!(target: "sync", "Ignored block headers while block download is inactive"); - sync.continue_sync(io); return Ok(()); }, Some(ref mut blocks) => blocks, } } }; - downloader.import_headers(io, r, expected_hash) + downloader.import_headers(io, r, expected_hash)? }; - match result { - Err(DownloaderImportError::Useless) => { - sync.deactivate_peer(io, peer_id); - }, - Err(DownloaderImportError::Invalid) => { - io.disable_peer(peer_id); - sync.deactivate_peer(io, peer_id); - sync.continue_sync(io); - return Ok(()); - }, - Ok(DownloadAction::Reset) => { - // mark all outstanding requests as expired - trace!("Resetting downloads for {:?}", block_set); - for (_, ref mut p) in sync.peers.iter_mut().filter(|&(_, ref p)| p.block_set == Some(block_set)) { - p.reset_asking(); - } - + if let DownloadAction::Reset = result { + // mark all outstanding requests as expired + trace!("Resetting downloads for {:?}", block_set); + for (_, ref mut p) in sync.peers.iter_mut().filter(|&(_, ref p)| p.block_set == Some(block_set)) { + p.reset_asking(); } - Ok(DownloadAction::None) => {}, } sync.collect_blocks(io, block_set); - // give a task to the same peer first if received valuable headers. - sync.sync_peer(io, peer_id, false); - // give tasks to other peers - sync.continue_sync(io); Ok(()) } /// Called by peer once it has new block receipts - fn on_peer_block_receipts(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + fn on_peer_block_receipts(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), DownloaderImportError> { sync.clear_peer_download(peer_id); let block_set = sync.peers.get(&peer_id).and_then(|p| p.block_set).unwrap_or(BlockSet::NewBlocks); if !sync.reset_peer_asking(peer_id, PeerAsking::BlockReceipts) { trace!(target: "sync", "{}: Ignored unexpected receipts", peer_id); - sync.continue_sync(io); return Ok(()); } let item_count = r.item_count()?; trace!(target: "sync", "{} -> BlockReceipts ({} entries)", peer_id, item_count); if item_count == 0 { - sync.deactivate_peer(io, peer_id); - } - else if sync.state == SyncState::Waiting { + Err(DownloaderImportError::Useless) + } else if sync.state == SyncState::Waiting { trace!(target: "sync", "Ignored block receipts while waiting"); - } - else - { - let result = { + Ok(()) + } else { + { let downloader = match block_set { BlockSet::NewBlocks => &mut sync.new_blocks, BlockSet::OldBlocks => match sync.old_blocks { None => { trace!(target: "sync", "Ignored block headers while block download is inactive"); - sync.continue_sync(io); return Ok(()); }, Some(ref mut blocks) => blocks, } }; - downloader.import_receipts(io, r) - }; - - match result { - Err(DownloaderImportError::Invalid) => { - io.disable_peer(peer_id); - sync.deactivate_peer(io, peer_id); - sync.continue_sync(io); - return Ok(()); - }, - Err(DownloaderImportError::Useless) => { - sync.deactivate_peer(io, peer_id); - }, - Ok(()) => (), + downloader.import_receipts(io, r)?; } - sync.collect_blocks(io, block_set); - sync.sync_peer(io, peer_id, false); + Ok(()) } - sync.continue_sync(io); - Ok(()) } /// Called when snapshot manifest is downloaded from a peer. - fn on_snapshot_manifest(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + fn on_snapshot_manifest(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), DownloaderImportError> { if !sync.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { trace!(target: "sync", "Ignoring snapshot manifest from unconfirmed peer {}", peer_id); return Ok(()); @@ -512,43 +454,28 @@ impl SyncHandler { sync.clear_peer_download(peer_id); if !sync.reset_peer_asking(peer_id, PeerAsking::SnapshotManifest) || sync.state != SyncState::SnapshotManifest { trace!(target: "sync", "{}: Ignored unexpected/expired manifest", peer_id); - sync.continue_sync(io); return Ok(()); } let manifest_rlp = r.at(0)?; - let manifest = match ManifestData::from_rlp(manifest_rlp.as_raw()) { - Err(e) => { - trace!(target: "sync", "{}: Ignored bad manifest: {:?}", peer_id, e); - io.disable_peer(peer_id); - sync.continue_sync(io); - return Ok(()); - } - Ok(manifest) => manifest, - }; + let manifest = ManifestData::from_rlp(manifest_rlp.as_raw())?; let is_supported_version = io.snapshot_service().supported_versions() .map_or(false, |(l, h)| manifest.version >= l && manifest.version <= h); if !is_supported_version { trace!(target: "sync", "{}: Snapshot manifest version not supported: {}", peer_id, manifest.version); - io.disable_peer(peer_id); - sync.continue_sync(io); - return Ok(()); + return Err(DownloaderImportError::Invalid); } sync.snapshot.reset_to(&manifest, &keccak(manifest_rlp.as_raw())); io.snapshot_service().begin_restore(manifest); sync.state = SyncState::SnapshotData; - // give a task to the same peer first. - sync.sync_peer(io, peer_id, false); - // give tasks to other peers - sync.continue_sync(io); Ok(()) } /// Called when snapshot data is downloaded from a peer. - fn on_snapshot_data(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + fn on_snapshot_data(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), DownloaderImportError> { if !sync.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { trace!(target: "sync", "Ignoring snapshot data from unconfirmed peer {}", peer_id); return Ok(()); @@ -556,7 +483,6 @@ impl SyncHandler { sync.clear_peer_download(peer_id); if !sync.reset_peer_asking(peer_id, PeerAsking::SnapshotData) || (sync.state != SyncState::SnapshotData && sync.state != SyncState::SnapshotWaiting) { trace!(target: "sync", "{}: Ignored unexpected snapshot data", peer_id); - sync.continue_sync(io); return Ok(()); } @@ -574,7 +500,6 @@ impl SyncHandler { } sync.snapshot.clear(); - sync.continue_sync(io); return Ok(()); }, RestorationStatus::Initializing { .. } => { @@ -599,7 +524,6 @@ impl SyncHandler { Err(()) => { trace!(target: "sync", "{}: Got bad snapshot chunk", peer_id); io.disconnect_peer(peer_id); - sync.continue_sync(io); return Ok(()); } } @@ -608,15 +532,12 @@ impl SyncHandler { // wait for snapshot restoration process to complete sync.state = SyncState::SnapshotWaiting; } - // give a task to the same peer first. - sync.sync_peer(io, peer_id, false); - // give tasks to other peers - sync.continue_sync(io); + Ok(()) } /// Called by peer to report status - fn on_peer_status(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + fn on_peer_status(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), DownloaderImportError> { sync.handshaking_peers.remove(&peer_id); let protocol_version: u8 = r.val_at(0)?; let warp_protocol = io.protocol_version(&WARP_SYNC_PROTOCOL_ID, peer_id) != 0; @@ -652,23 +573,20 @@ impl SyncHandler { } let chain_info = io.chain().chain_info(); if peer.genesis != chain_info.genesis_hash { - io.disable_peer(peer_id); trace!(target: "sync", "Peer {} genesis hash mismatch (ours: {}, theirs: {})", peer_id, chain_info.genesis_hash, peer.genesis); - return Ok(()); + return Err(DownloaderImportError::Invalid); } if peer.network_id != sync.network_id { - io.disable_peer(peer_id); trace!(target: "sync", "Peer {} network id mismatch (ours: {}, theirs: {})", peer_id, sync.network_id, peer.network_id); - return Ok(()); + return Err(DownloaderImportError::Invalid); } if false || (warp_protocol && (peer.protocol_version < PAR_PROTOCOL_VERSION_1.0 || peer.protocol_version > PAR_PROTOCOL_VERSION_3.0)) || (!warp_protocol && (peer.protocol_version < ETH_PROTOCOL_VERSION_62.0 || peer.protocol_version > ETH_PROTOCOL_VERSION_63.0)) { - io.disable_peer(peer_id); trace!(target: "sync", "Peer {} unsupported eth protocol ({})", peer_id, peer.protocol_version); - return Ok(()); + return Err(DownloaderImportError::Invalid); } if sync.sync_start_time.is_none() { @@ -681,20 +599,15 @@ impl SyncHandler { sync.active_peers.insert(peer_id.clone()); debug!(target: "sync", "Connected {}:{}", peer_id, io.peer_info(peer_id)); - match sync.fork_block { - Some((fork_block, _)) => { - SyncRequester::request_fork_header(sync, io, peer_id, fork_block); - }, - _ => { - SyncHandler::on_peer_confirmed(sync, io, peer_id); - } + if let Some((fork_block, _)) = sync.fork_block { + SyncRequester::request_fork_header(sync, io, peer_id, fork_block); } Ok(()) } /// Called when peer sends us new transactions - fn on_peer_transactions(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + fn on_peer_transactions(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), DownloaderImportError> { // Accept transactions only when fully synced if !io.is_chain_queue_empty() || (sync.state != SyncState::Idle && sync.state != SyncState::NewBlocks) { trace!(target: "sync", "{} Ignoring transactions while syncing", peer_id); @@ -718,7 +631,7 @@ impl SyncHandler { } /// Called when peer sends us signed private transaction packet - fn on_signed_private_transaction(sync: &ChainSync, _io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + fn on_signed_private_transaction(sync: &ChainSync, _io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), DownloaderImportError> { if !sync.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { trace!(target: "sync", "{} Ignoring packet from unconfirmed/unknown peer", peer_id); return Ok(()); @@ -732,7 +645,7 @@ impl SyncHandler { } /// Called when peer sends us new private transaction packet - fn on_private_transaction(sync: &ChainSync, _io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + fn on_private_transaction(sync: &ChainSync, _io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), DownloaderImportError> { if !sync.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { trace!(target: "sync", "{} Ignoring packet from unconfirmed/unknown peer", peer_id); return Ok(()); diff --git a/ethcore/sync/src/chain/mod.rs b/ethcore/sync/src/chain/mod.rs index 5af289254932f173aee31970daf727b73adf4431..520226a9c7e765647b399d1aad00b989981e03c1 100644 --- a/ethcore/sync/src/chain/mod.rs +++ b/ethcore/sync/src/chain/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -149,8 +149,6 @@ const MAX_NEW_HASHES: usize = 64; const MAX_NEW_BLOCK_AGE: BlockNumber = 20; // maximal packet size with transactions (cannot be greater than 16MB - protocol limitation). const MAX_TRANSACTION_PACKET_SIZE: usize = 8 * 1024 * 1024; -// Maximal number of transactions in sent in single packet. -const MAX_TRANSACTIONS_TO_PROPAGATE: usize = 64; // Min number of blocks to be behind for a snapshot sync const SNAPSHOT_RESTORE_THRESHOLD: BlockNumber = 30000; const SNAPSHOT_MIN_PEERS: usize = 3; @@ -294,6 +292,8 @@ pub enum BlockSet { pub enum ForkConfirmation { /// Fork block confirmation pending. Unconfirmed, + /// Peer's chain is too short to confirm the fork. + TooShort, /// Fork is confirmed. Confirmed, } @@ -656,20 +656,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 @@ -704,14 +713,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; @@ -754,14 +755,24 @@ impl ChainSync { } } - // Only ask for old blocks if the peer has a higher difficulty - if force || higher_difficulty { + // Only ask for old blocks if the peer has a higher difficulty than the last imported old block + let last_imported_old_block_difficulty = self.old_blocks.as_mut().and_then(|d| { + io.chain().block_total_difficulty(BlockId::Number(d.last_imported_block_number())) + }); + + if force || last_imported_old_block_difficulty.map_or(true, |ld| peer_difficulty.map_or(true, |pd| pd > ld)) { if let Some(request) = self.old_blocks.as_mut().and_then(|d| d.request_blocks(io, num_active_peers)) { SyncRequester::request_blocks(self, io, peer_id, request, BlockSet::OldBlocks); return; } } else { - trace!(target: "sync", "peer {} is not suitable for asking old blocks", peer_id); + trace!( + target: "sync", + "peer {:?} is not suitable for requesting old blocks, last_imported_old_block_difficulty={:?}, peer_difficulty={:?}", + peer_id, + last_imported_old_block_difficulty, + peer_difficulty + ); self.deactivate_peer(io, peer_id); } }, @@ -1141,7 +1152,7 @@ pub mod tests { use super::{PeerInfo, PeerAsking}; use ethcore::header::*; use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient, ChainInfo, BlockInfo}; - use ethcore::miner::MinerService; + use ethcore::miner::{MinerService, PendingOrdering}; use private_tx::NoopPrivateTxHandler; pub fn get_dummy_block(order: u32, parent_hash: H256) -> Bytes { @@ -1346,7 +1357,6 @@ pub mod tests { client.set_nonce(sender, U256::from(0)); } - // when { let queue = RwLock::new(VecDeque::new()); @@ -1354,7 +1364,7 @@ pub mod tests { let mut io = TestIo::new(&mut client, &ss, &queue, None); io.chain.miner.chain_new_blocks(io.chain, &[], &[], &[], &good_blocks, false); sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks, &[], &[]); - assert_eq!(io.chain.miner.ready_transactions(io.chain).len(), 1); + assert_eq!(io.chain.miner.ready_transactions(io.chain, 10, PendingOrdering::Priority).len(), 1); } // We need to update nonce status (because we say that the block has been imported) for h in &[good_blocks[0]] { @@ -1370,7 +1380,7 @@ pub mod tests { } // then - assert_eq!(client.miner.ready_transactions(&client).len(), 1); + assert_eq!(client.miner.ready_transactions(&client, 10, PendingOrdering::Priority).len(), 1); } #[test] diff --git a/ethcore/sync/src/chain/propagator.rs b/ethcore/sync/src/chain/propagator.rs index 4ae0518a5379b990a1e539cb04b6a70447d146e0..7cb145f362668a643d226b5eb661758e1b7ef57d 100644 --- a/ethcore/sync/src/chain/propagator.rs +++ b/ethcore/sync/src/chain/propagator.rs @@ -29,10 +29,9 @@ use transaction::SignedTransaction; use super::{ random, ChainSync, + MAX_TRANSACTION_PACKET_SIZE, MAX_PEER_LAG_PROPAGATION, MAX_PEERS_PROPAGATION, - MAX_TRANSACTION_PACKET_SIZE, - MAX_TRANSACTIONS_TO_PROPAGATE, MIN_PEERS_PROPAGATION, CONSENSUS_DATA_PACKET, NEW_BLOCK_HASHES_PACKET, @@ -47,15 +46,21 @@ fn accepts_service_transaction(client_id: &str) -> bool { // Parity versions starting from this will accept service-transactions const SERVICE_TRANSACTIONS_VERSION: (u32, u32) = (1u32, 6u32); // Parity client string prefix - const PARITY_CLIENT_ID_PREFIX: &'static str = "Parity/v"; - - if !client_id.starts_with(PARITY_CLIENT_ID_PREFIX) { + const LEGACY_CLIENT_ID_PREFIX: &'static str = "Parity/v"; + const PARITY_CLIENT_ID_PREFIX: &'static str = "Parity-Ethereum/v"; + + let splitted = if client_id.starts_with(LEGACY_CLIENT_ID_PREFIX) { + client_id[LEGACY_CLIENT_ID_PREFIX.len()..].split('.') + } else if client_id.starts_with(PARITY_CLIENT_ID_PREFIX) { + client_id[PARITY_CLIENT_ID_PREFIX.len()..].split('.') + } else { return false; - } - let ver: Vec = client_id[PARITY_CLIENT_ID_PREFIX.len()..].split('.') - .take(2) - .filter_map(|s| s.parse().ok()) - .collect(); + }; + + let ver: Vec = splitted + .take(2) + .filter_map(|s| s.parse().ok()) + .collect(); ver.len() == 2 && (ver[0] > SERVICE_TRANSACTIONS_VERSION.0 || (ver[0] == SERVICE_TRANSACTIONS_VERSION.0 && ver[1] >= SERVICE_TRANSACTIONS_VERSION.1)) } @@ -114,7 +119,7 @@ impl SyncPropagator { return 0; } - let transactions = io.chain().ready_transactions(); + let transactions = io.chain().transactions_to_propagate(); if transactions.is_empty() { return 0; } @@ -177,7 +182,6 @@ impl SyncPropagator { // Get hashes of all transactions to send to this peer let to_send = all_transactions_hashes.difference(&peer_info.last_sent_transactions) - .take(MAX_TRANSACTIONS_TO_PROPAGATE) .cloned() .collect::>(); if to_send.is_empty() { @@ -576,13 +580,13 @@ mod tests { io.peers_info.insert(1, "Geth".to_owned()); // and peer#2 is Parity, accepting service transactions insert_dummy_peer(&mut sync, 2, block_hash); - io.peers_info.insert(2, "Parity/v1.6".to_owned()); + io.peers_info.insert(2, "Parity-Ethereum/v2.6".to_owned()); // and peer#3 is Parity, discarding service transactions insert_dummy_peer(&mut sync, 3, block_hash); io.peers_info.insert(3, "Parity/v1.5".to_owned()); // and peer#4 is Parity, accepting service transactions insert_dummy_peer(&mut sync, 4, block_hash); - io.peers_info.insert(4, "Parity/v1.7.3-ABCDEFGH".to_owned()); + io.peers_info.insert(4, "Parity-Ethereum/v2.7.3-ABCDEFGH".to_owned()); // and new service transaction is propagated to peers SyncPropagator::propagate_new_transactions(&mut sync, &mut io); @@ -606,7 +610,7 @@ mod tests { // when peer#1 is Parity, accepting service transactions insert_dummy_peer(&mut sync, 1, block_hash); - io.peers_info.insert(1, "Parity/v1.6".to_owned()); + io.peers_info.insert(1, "Parity-Ethereum/v2.6".to_owned()); // and service + non-service transactions are propagated to peers SyncPropagator::propagate_new_transactions(&mut sync, &mut io); diff --git a/ethcore/sync/src/chain/supplier.rs b/ethcore/sync/src/chain/supplier.rs index e0245fdbcd9d2a4bc4337f6b54596dc2f28fbae5..e8a5c93ea3dec9eba4bfb5fcc48a52f080e62860 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::{ @@ -133,7 +134,7 @@ impl SyncSupplier { let max_count = cmp::min(MAX_HEADERS_TO_SEND, max_headers); let mut count = 0; let mut data = Bytes::new(); - let inc = (skip + 1) as BlockNumber; + let inc = skip.saturating_add(1) as BlockNumber; let overlay = io.chain_overlay().read(); // We are checking the `overlay` as well since it's where the ForkBlock @@ -155,9 +156,9 @@ impl SyncSupplier { if number <= inc || number == 0 { break; } - number -= inc; + number = number.saturating_sub(inc); } else { - number += inc; + number = number.saturating_add(inc); } } let mut rlp = RlpStream::new_list(count as usize); diff --git a/ethcore/sync/src/lib.rs b/ethcore/sync/src/lib.rs index c00ea5e4404ec6e05af2e3ff7dfb038a443f2415..f9f8a3e3e93d1dd3b72c692331ac68e8ff6322ee 100644 --- a/ethcore/sync/src/lib.rs +++ b/ethcore/sync/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -23,13 +23,14 @@ extern crate ethcore_network as network; extern crate ethcore_network_devp2p as devp2p; -extern crate ethcore_bytes as bytes; +extern crate parity_bytes as bytes; extern crate ethcore_io as io; extern crate ethcore_transaction as transaction; #[macro_use] 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,7 +39,8 @@ extern crate smallvec; extern crate rlp; extern crate ipnetwork; extern crate keccak_hash as hash; -extern crate triehash; +extern crate keccak_hasher; +extern crate triehash_ethereum; extern crate kvdb; extern crate ethcore_light as light; diff --git a/ethcore/sync/src/light_sync/mod.rs b/ethcore/sync/src/light_sync/mod.rs index 9fa669817ae99befb3db423c9e2a824155f55f4c..32e3a0dbfde2a793498d2ef2338ee5ebf55f3903 100644 --- a/ethcore/sync/src/light_sync/mod.rs +++ b/ethcore/sync/src/light_sync/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/src/light_sync/response.rs b/ethcore/sync/src/light_sync/response.rs index 3629613224d4eecdcc75163431dd99bcee3c8905..161461c2a5978509238a797ff9e7c4fe4782c160 100644 --- a/ethcore/sync/src/light_sync/response.rs +++ b/ethcore/sync/src/light_sync/response.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/src/light_sync/sync_round.rs b/ethcore/sync/src/light_sync/sync_round.rs index d477ecc81503f074d9cce3993b116502fb4e4d04..79684efe53dad9f233b052b5bca8e7fb3c7bdf71 100644 --- a/ethcore/sync/src/light_sync/sync_round.rs +++ b/ethcore/sync/src/light_sync/sync_round.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/src/light_sync/tests/mod.rs b/ethcore/sync/src/light_sync/tests/mod.rs index 3fee1c717070776f597d0c0c15ac78a4745c0cd0..e3d46188a65bf634c93fbcde6815336e2039bf9b 100644 --- a/ethcore/sync/src/light_sync/tests/mod.rs +++ b/ethcore/sync/src/light_sync/tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/src/light_sync/tests/test_net.rs b/ethcore/sync/src/light_sync/tests/test_net.rs index badd35668b91e8c39fedcac8e3fa5964bb70fee1..5995bd7c6c0b94309e166a50c45c096ecd2831d6 100644 --- a/ethcore/sync/src/light_sync/tests/test_net.rs +++ b/ethcore/sync/src/light_sync/tests/test_net.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/src/private_tx.rs b/ethcore/sync/src/private_tx.rs index ded5de2d866935dfcb7e3eb9c5834881f4059833..d7434c8bd5b13c7dc27b6aec4112f7f5842c6b01 100644 --- a/ethcore/sync/src/private_tx.rs +++ b/ethcore/sync/src/private_tx.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/src/snapshot.rs b/ethcore/sync/src/snapshot.rs index b603a2a007af17305ef19de09b8b0959264b79bd..c7f0d284f39a0a9807d89cd830bc1bc5d48da393 100644 --- a/ethcore/sync/src/snapshot.rs +++ b/ethcore/sync/src/snapshot.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -17,7 +17,6 @@ use ethcore::snapshot::{ManifestData, SnapshotService}; use ethereum_types::H256; use hash::keccak; -use rand::{thread_rng, Rng}; use std::collections::HashSet; use std::iter::FromIterator; @@ -114,35 +113,32 @@ impl Snapshot { Err(()) } - /// Find a random chunk to download + /// Find a chunk to download pub fn needed_chunk(&mut self) -> Option { - // Find all random chunks: first blocks, then state - let needed_chunks = { + // Find next needed chunk: first block, then state chunks + let chunk = { let chunk_filter = |h| !self.downloading_chunks.contains(h) && !self.completed_chunks.contains(h); - let needed_block_chunks = self.pending_block_chunks.iter() + let needed_block_chunk = self.pending_block_chunks.iter() .filter(|&h| chunk_filter(h)) .map(|h| *h) - .collect::>(); + .next(); // If no block chunks to download, get the state chunks - if needed_block_chunks.len() == 0 { + if needed_block_chunk.is_none() { self.pending_state_chunks.iter() .filter(|&h| chunk_filter(h)) .map(|h| *h) - .collect::>() + .next() } else { - needed_block_chunks + needed_block_chunk } }; - // Get a random chunk - let chunk = thread_rng().choose(&needed_chunks); - if let Some(hash) = chunk { self.downloading_chunks.insert(hash.clone()); } - chunk.map(|h| *h) + chunk } pub fn clear_chunk_download(&mut self, hash: &H256) { @@ -274,4 +270,3 @@ mod test { assert_eq!(snapshot.is_known_bad(&hash), true); } } - diff --git a/ethcore/sync/src/sync_io.rs b/ethcore/sync/src/sync_io.rs index 76f323e82614151344a67786c4bdad18d0a3e42c..c7704724c6625f954b3578373c22f273d92d1163 100644 --- a/ethcore/sync/src/sync_io.rs +++ b/ethcore/sync/src/sync_io.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -136,5 +136,3 @@ impl<'s> SyncIo for NetSyncIo<'s> { self.network.peer_client_version(peer_id) } } - - diff --git a/ethcore/sync/src/tests/chain.rs b/ethcore/sync/src/tests/chain.rs index 6b5ef65da10639af286b73e3ebaf4e60a65ef278..0d9c83f2fb49b27ec746b40f65b750ef3931dde5 100644 --- a/ethcore/sync/src/tests/chain.rs +++ b/ethcore/sync/src/tests/chain.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -253,7 +253,6 @@ fn high_td_attach() { assert_eq!(net.peer(0).chain.chain_info().best_block_number, 5); } - #[test] fn disconnect_on_unrelated_chain() { ::env_logger::init().ok(); @@ -267,4 +266,3 @@ fn disconnect_on_unrelated_chain() { net.sync(); assert_eq!(net.disconnect_events, vec![(0, 0)]); } - diff --git a/ethcore/sync/src/tests/consensus.rs b/ethcore/sync/src/tests/consensus.rs index 8825bad2c8c45b527173d122d29f40c2b07348c1..40a4edef3944fade0ea8ca814da63715e15031fe 100644 --- a/ethcore/sync/src/tests/consensus.rs +++ b/ethcore/sync/src/tests/consensus.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -44,8 +44,8 @@ fn authority_round() { let s0 = KeyPair::from_secret_slice(&keccak("1")).unwrap(); let s1 = KeyPair::from_secret_slice(&keccak("0")).unwrap(); let ap = Arc::new(AccountProvider::transient_provider()); - ap.insert_account(s0.secret().clone(), "").unwrap(); - ap.insert_account(s1.secret().clone(), "").unwrap(); + ap.insert_account(s0.secret().clone(), &"".into()).unwrap(); + ap.insert_account(s1.secret().clone(), &"".into()).unwrap(); let chain_id = Spec::new_test_round().chain_id(); let mut net = TestNet::with_spec_and_accounts(2, SyncConfig::default(), Spec::new_test_round, Some(ap)); @@ -53,7 +53,7 @@ fn authority_round() { let io_handler1: Arc> = Arc::new(TestIoHandler::new(net.peer(1).chain.clone())); // Push transaction to both clients. Only one of them gets lucky to produce a block. net.peer(0).miner.set_author(s0.address(), Some("".into())).unwrap(); - net.peer(1).miner.set_author(s1.address(), Some("".to_owned())).unwrap(); + net.peer(1).miner.set_author(s1.address(), Some("".into())).unwrap(); net.peer(0).chain.engine().register_client(Arc::downgrade(&net.peer(0).chain) as _); net.peer(1).chain.engine().register_client(Arc::downgrade(&net.peer(1).chain) as _); net.peer(0).chain.set_io_channel(IoChannel::to_handler(Arc::downgrade(&io_handler1))); @@ -131,8 +131,8 @@ fn tendermint() { let s0 = KeyPair::from_secret_slice(&keccak("1")).unwrap(); let s1 = KeyPair::from_secret_slice(&keccak("0")).unwrap(); let ap = Arc::new(AccountProvider::transient_provider()); - ap.insert_account(s0.secret().clone(), "").unwrap(); - ap.insert_account(s1.secret().clone(), "").unwrap(); + ap.insert_account(s0.secret().clone(), &"".into()).unwrap(); + ap.insert_account(s1.secret().clone(), &"".into()).unwrap(); let chain_id = Spec::new_test_tendermint().chain_id(); let mut net = TestNet::with_spec_and_accounts(2, SyncConfig::default(), Spec::new_test_tendermint, Some(ap)); diff --git a/ethcore/sync/src/tests/helpers.rs b/ethcore/sync/src/tests/helpers.rs index 407f699e0e6959c9cd8f0f9ce4740ee08c88306f..59db57dc5eacc121530d557d5cd9b428b23fddcb 100644 --- a/ethcore/sync/src/tests/helpers.rs +++ b/ethcore/sync/src/tests/helpers.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -29,6 +29,7 @@ use ethcore::snapshot::SnapshotService; use ethcore::spec::Spec; use ethcore::account_provider::AccountProvider; use ethcore::miner::Miner; +use ethcore::test_helpers; use sync_io::SyncIo; use io::{IoChannel, IoContext, IoHandler}; use api::WARP_SYNC_PROTOCOL_ID; @@ -384,7 +385,7 @@ impl TestNet> { let client = EthcoreClient::new( ClientConfig::default(), &spec, - Arc::new(::kvdb_memorydb::create(::ethcore::db::NUM_COLUMNS.unwrap_or(0))), + test_helpers::new_db(), miner.clone(), channel.clone() ).unwrap(); diff --git a/ethcore/sync/src/tests/mod.rs b/ethcore/sync/src/tests/mod.rs index eb01108286bd098b88c4371495044e304f515f42..0168913aa1655c398054a8de0532bfd4c07d8c0d 100644 --- a/ethcore/sync/src/tests/mod.rs +++ b/ethcore/sync/src/tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/src/tests/private.rs b/ethcore/sync/src/tests/private.rs index b54240bfb87f432b223bffa9ecaae5a13457b427..04b414b94c385fcadcd7bb10019d304ee4eea23e 100644 --- a/ethcore/sync/src/tests/private.rs +++ b/ethcore/sync/src/tests/private.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -42,8 +42,8 @@ fn send_private_transaction() { let s0 = KeyPair::from_secret_slice(&keccak("1")).unwrap(); let s1 = KeyPair::from_secret_slice(&keccak("0")).unwrap(); let ap = Arc::new(AccountProvider::transient_provider()); - ap.insert_account(s0.secret().clone(), "").unwrap(); - ap.insert_account(s1.secret().clone(), "").unwrap(); + ap.insert_account(s0.secret().clone(), &"".into()).unwrap(); + ap.insert_account(s1.secret().clone(), &"".into()).unwrap(); let mut net = TestNet::with_spec_and_accounts(2, SyncConfig::default(), seal_spec, Some(ap.clone())); let client0 = net.peer(0).chain.clone(); @@ -52,7 +52,7 @@ fn send_private_transaction() { let io_handler1: Arc> = Arc::new(TestIoHandler::new(net.peer(1).chain.clone())); net.peer(0).miner.set_author(s0.address(), Some("".into())).unwrap(); - net.peer(1).miner.set_author(s1.address(), Some("".to_owned())).unwrap(); + net.peer(1).miner.set_author(s1.address(), Some("".into())).unwrap(); net.peer(0).chain.engine().register_client(Arc::downgrade(&net.peer(0).chain) as _); net.peer(1).chain.engine().register_client(Arc::downgrade(&net.peer(1).chain) as _); net.peer(0).chain.set_io_channel(IoChannel::to_handler(Arc::downgrade(&io_handler0))); diff --git a/ethcore/sync/src/tests/rpc.rs b/ethcore/sync/src/tests/rpc.rs index 5806fbbd8d40114f5c2e1045d2a9eb259daf2acd..99e95959be6a091687728a96ffa08d223ae3bb88 100644 --- a/ethcore/sync/src/tests/rpc.rs +++ b/ethcore/sync/src/tests/rpc.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/src/tests/snapshot.rs b/ethcore/sync/src/tests/snapshot.rs index ffb71d7a730e5b48716cbfb874c58e55c6c89fcf..e6636c02f42385deb1ab2d02f2dfd362eddff51d 100644 --- a/ethcore/sync/src/tests/snapshot.rs +++ b/ethcore/sync/src/tests/snapshot.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -154,4 +154,3 @@ fn snapshot_sync() { assert_eq!(net.peer(4).snapshot_service.state_restoration_chunks.lock().len(), net.peer(0).snapshot_service.manifest.as_ref().unwrap().state_hashes.len()); assert_eq!(net.peer(4).snapshot_service.block_restoration_chunks.lock().len(), net.peer(0).snapshot_service.manifest.as_ref().unwrap().block_hashes.len()); } - diff --git a/ethcore/sync/src/transactions_stats.rs b/ethcore/sync/src/transactions_stats.rs index 4d33008621a2e35e06b2611051cf6c22cd7e1d6b..c45b1ad8b3cf895385c72ca7bc74e00b41b7fc00 100644 --- a/ethcore/sync/src/transactions_stats.rs +++ b/ethcore/sync/src/transactions_stats.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/transaction/Cargo.toml b/ethcore/transaction/Cargo.toml index 79e7282c388d2836adf21a85cca73dbaa8ea6782..bde83f478d36cbe2969b40d314592293f0a49dca 100644 --- a/ethcore/transaction/Cargo.toml +++ b/ethcore/transaction/Cargo.toml @@ -9,8 +9,8 @@ ethjson = { path = "../../json" } ethkey = { path = "../../ethkey" } evm = { path = "../evm" } heapsize = "0.4" -keccak-hash = { path = "../../util/hash" } -rlp = { path = "../../util/rlp" } +keccak-hash = { git = "https://github.com/paritytech/parity-common" } +rlp = { git = "https://github.com/paritytech/parity-common" } unexpected = { path = "../../util/unexpected" } ethereum-types = "0.3" diff --git a/ethcore/transaction/src/error.rs b/ethcore/transaction/src/error.rs index eeeba4e53a91c36459f1256481d57d9684aa2a0c..0efd18ae6b363d883e5a49b983f98a52824035ab 100644 --- a/ethcore/transaction/src/error.rs +++ b/ethcore/transaction/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -130,4 +130,3 @@ impl error::Error for Error { "Transaction error" } } - diff --git a/ethcore/transaction/src/lib.rs b/ethcore/transaction/src/lib.rs index 6a478b94635a8469801fa0bcc3e2cf16c3628340..829613cf9c79546adf1f61df6800b5cd215a2447 100644 --- a/ethcore/transaction/src/lib.rs +++ b/ethcore/transaction/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 6152e61acb6a158a4f55076c9514f4456888b37a..49804f1870feaa5b4aba99c35b5ac58fb8bf321b 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -282,6 +282,12 @@ pub struct UnverifiedTransaction { hash: H256, } +impl HeapSizeOf for UnverifiedTransaction { + fn heap_size_of_children(&self) -> usize { + self.unsigned.heap_size_of_children() + } +} + impl Deref for UnverifiedTransaction { type Target = Transaction; @@ -409,6 +415,10 @@ impl UnverifiedTransaction { if check_low_s && !(allow_empty_signature && self.is_unsigned()) { self.check_low_s()?; } + // Disallow unsigned transactions in case EIP-86 is disabled. + if !allow_empty_signature && self.is_unsigned() { + return Err(ethkey::Error::InvalidSignature.into()); + } // EIP-86: Transactions of this form MUST have gasprice = 0, nonce = 0, value = 0, and do NOT increment the nonce of account 0. if allow_empty_signature && self.is_unsigned() && !(self.gas_price.is_zero() && self.value.is_zero() && self.nonce.is_zero()) { return Err(ethkey::Error::InvalidSignature.into()) @@ -432,7 +442,7 @@ pub struct SignedTransaction { impl HeapSizeOf for SignedTransaction { fn heap_size_of_children(&self) -> usize { - self.transaction.unsigned.heap_size_of_children() + self.transaction.heap_size_of_children() } } diff --git a/ethcore/types/Cargo.toml b/ethcore/types/Cargo.toml index 92cc74551d38bc321b8c81c08d548a7e0569fe90..82b42c51987ff6d8ce128ac96fe715b2f2d1cf4f 100644 --- a/ethcore/types/Cargo.toml +++ b/ethcore/types/Cargo.toml @@ -5,12 +5,12 @@ version = "0.1.0" authors = ["Parity Technologies "] [dependencies] -rlp = { path = "../../util/rlp" } +rlp = { git = "https://github.com/paritytech/parity-common" } rlp_derive = { path = "../../util/rlp_derive" } -ethcore-bytes = { path = "../../util/bytes" } +parity-bytes = { git = "https://github.com/paritytech/parity-common" } ethereum-types = "0.3" ethjson = { path = "../../json" } -keccak-hash = { path = "../../util/hash" } +keccak-hash = { git = "https://github.com/paritytech/parity-common" } heapsize = "0.4" [dev-dependencies] diff --git a/ethcore/types/src/account_diff.rs b/ethcore/types/src/account_diff.rs index c3edb1fb1e3d18186346306dcfeacf5b207b4e24..9633ffeb0787273d82a297523c7077747e0583e9 100644 --- a/ethcore/types/src/account_diff.rs +++ b/ethcore/types/src/account_diff.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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 } } @@ -138,4 +144,3 @@ impl fmt::Display for AccountDiff { Ok(()) } } - diff --git a/ethcore/types/src/basic_account.rs b/ethcore/types/src/basic_account.rs index 79e75dfc0144a72176fd1211df57111524598e90..94157977bc7d30a5be26bb7413c1f49c1b8a2fd1 100644 --- a/ethcore/types/src/basic_account.rs +++ b/ethcore/types/src/basic_account.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/block_status.rs b/ethcore/types/src/block_status.rs index d330b9ed1b01522efb2b2b5d0e057e229423cc74..5455f1d40f216550eb492bd5eec9505928aa6a83 100644 --- a/ethcore/types/src/block_status.rs +++ b/ethcore/types/src/block_status.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/blockchain_info.rs b/ethcore/types/src/blockchain_info.rs index 836ee7618bd7f0ac5b18ec13ee1da34c888190e9..b82582bda090ccd4db169df0fa5aa99ba4db1b4f 100644 --- a/ethcore/types/src/blockchain_info.rs +++ b/ethcore/types/src/blockchain_info.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -50,7 +50,7 @@ pub struct BlockChainInfo { impl BlockChainInfo { /// Determine the security model for the current state. pub fn security_level(&self) -> SecurityLevel { - // TODO: Detect SecurityLevel::FullState : https://github.com/paritytech/parity/issues/3834 + // TODO: Detect SecurityLevel::FullState : https://github.com/paritytech/parity-ethereum/issues/3834 if self.ancient_block_number.is_none() || self.first_block_number.is_none() { SecurityLevel::FullProofOfWork } else { diff --git a/ethcore/types/src/call_analytics.rs b/ethcore/types/src/call_analytics.rs index b0520a0d3ff67b3724570efa416f969beed3cd87..ae53e6911e136a969bc11f473d881a7fbc96fc18 100644 --- a/ethcore/types/src/call_analytics.rs +++ b/ethcore/types/src/call_analytics.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/filter.rs b/ethcore/types/src/filter.rs index 0a37482b94e66aaf23b8ed3e4375e30ffa5a7aab..c32551473d133a4b5d8a4be90dd820aa56c277c3 100644 --- a/ethcore/types/src/filter.rs +++ b/ethcore/types/src/filter.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/ids.rs b/ethcore/types/src/ids.rs index e304698a4ca83c01506bc43b1ca1d390340a6f6d..d1457832c010fa1141ae6afd23a19e050cb46538 100644 --- a/ethcore/types/src/ids.rs +++ b/ethcore/types/src/ids.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/lib.rs b/ethcore/types/src/lib.rs index 18e0dde86ad9cb7ca2ae06846792887fd01795c6..f375fec13c9c14b46e1c0ef2e4473a48ed59d9cc 100644 --- a/ethcore/types/src/lib.rs +++ b/ethcore/types/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Types used in the public API extern crate ethereum_types; -extern crate ethcore_bytes as bytes; +extern crate parity_bytes as bytes; extern crate ethjson; extern crate rlp; #[macro_use] @@ -36,7 +36,6 @@ pub mod call_analytics; pub mod filter; pub mod ids; pub mod log_entry; -pub mod mode; pub mod pruning_info; pub mod receipt; pub mod restoration_status; diff --git a/ethcore/types/src/log_entry.rs b/ethcore/types/src/log_entry.rs index 951a7389f2901b28179c5e85f1ea934f3eb83ec4..0b7455df496e0f3b48f3a79b6159180a42ff70f5 100644 --- a/ethcore/types/src/log_entry.rs +++ b/ethcore/types/src/log_entry.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/mode.rs b/ethcore/types/src/mode.rs deleted file mode 100644 index 539ebcdbd8ff0ffe01b2b616bf4d4433035ceb13..0000000000000000000000000000000000000000 --- a/ethcore/types/src/mode.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Mode type - -pub use std::time::Duration; - -/// IPC-capable shadow-type for `client::config::Mode` -#[derive(Clone, Debug)] -pub enum Mode { - /// Same as `ClientMode::Off`. - Off, - /// Same as `ClientMode::Dark`; values in seconds. - Dark(u64), - /// Same as `ClientMode::Passive`; values in seconds. - Passive(u64, u64), - /// Same as `ClientMode::Active`. - Active, -} diff --git a/ethcore/types/src/pruning_info.rs b/ethcore/types/src/pruning_info.rs index 8a47fdd8b902ee72703547e21349f96ceaf61fd3..fcf4a774a20317f2f39f19493b6335ccd2ad36f4 100644 --- a/ethcore/types/src/pruning_info.rs +++ b/ethcore/types/src/pruning_info.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/receipt.rs b/ethcore/types/src/receipt.rs index 8846d27c027de3752139044f5f3f0d3f18483ea7..ec3b3c66f553e16ff85122f8d0badf32919c7d77 100644 --- a/ethcore/types/src/receipt.rs +++ b/ethcore/types/src/receipt.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -16,11 +16,11 @@ //! Receipt -use ethereum_types::{H256, U256, Address, Bloom}; +use ethereum_types::{H160, H256, U256, Address, Bloom}; use heapsize::HeapSizeOf; use rlp::{Rlp, RlpStream, Encodable, Decodable, DecoderError}; -use {BlockNumber}; +use BlockNumber; use log_entry::{LogEntry, LocalizedLogEntry}; /// Transaction outcome store in the receipt. @@ -49,12 +49,15 @@ pub struct Receipt { impl Receipt { /// Create a new receipt. - pub fn new(outcome: TransactionOutcome, gas_used: U256, logs: Vec) -> Receipt { - Receipt { - gas_used: gas_used, - log_bloom: logs.iter().fold(Bloom::default(), |mut b, l| { b = &b | &l.bloom(); b }), //TODO: use |= operator - logs: logs, - outcome: outcome, + pub fn new(outcome: TransactionOutcome, gas_used: U256, logs: Vec) -> Self { + Self { + gas_used, + log_bloom: logs.iter().fold(Bloom::default(), |mut b, l| { + b.accrue_bloom(&l.bloom()); + b + }), + logs, + outcome, } } } @@ -157,6 +160,10 @@ pub struct LocalizedReceipt { pub log_bloom: Bloom, /// Transaction outcome. pub outcome: TransactionOutcome, + /// Receiver address + pub to: Option, + /// Sender + pub from: H160 } #[cfg(test)] diff --git a/ethcore/types/src/restoration_status.rs b/ethcore/types/src/restoration_status.rs index 51f5b8aa0a3c4e38ad3300af44753b8607e68739..ec15bf4809fefa95288dc07620b7c1e7a8b8a453 100644 --- a/ethcore/types/src/restoration_status.rs +++ b/ethcore/types/src/restoration_status.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -40,4 +40,3 @@ pub enum RestorationStatus { /// Failed restoration. Failed, } - diff --git a/ethcore/types/src/security_level.rs b/ethcore/types/src/security_level.rs index ea39dc32807f6c01f7173300a4c673f06a1de835..5917584704673e84b9ff6a1dbe57e7c4fc7c944d 100644 --- a/ethcore/types/src/security_level.rs +++ b/ethcore/types/src/security_level.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/snapshot_manifest.rs b/ethcore/types/src/snapshot_manifest.rs index c59402023a8feee48730b864de1b78e224fe009f..40ff4c532f70528c1c5fc4be4100d3e6d2e35801 100644 --- a/ethcore/types/src/snapshot_manifest.rs +++ b/ethcore/types/src/snapshot_manifest.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -76,4 +76,3 @@ impl ManifestData { }) } } - diff --git a/ethcore/types/src/state_diff.rs b/ethcore/types/src/state_diff.rs index dd976eb36c6938a326f1bc99f0e82f56cf07ee26..4cc85fff93f23c6e391b3d0e477ff67d2a2f2894 100644 --- a/ethcore/types/src/state_diff.rs +++ b/ethcore/types/src/state_diff.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/trace_filter.rs b/ethcore/types/src/trace_filter.rs index 2afa752ccbb44d054541ea1b20aa1229d944872e..69a37870277efefb406f9da698585680befd6264 100644 --- a/ethcore/types/src/trace_filter.rs +++ b/ethcore/types/src/trace_filter.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/tree_route.rs b/ethcore/types/src/tree_route.rs index 5d1bddd87b38dc3e24167c86d6ba143813155933..9c84052be35ddfba4ae5f806fd3c2dff8984509b 100644 --- a/ethcore/types/src/tree_route.rs +++ b/ethcore/types/src/tree_route.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/verification_queue_info.rs b/ethcore/types/src/verification_queue_info.rs index db818590aff780ffdfec119ab2bf88df4fa81bb5..bc280b15bfea50c24a71a813150872f3c393dca1 100644 --- a/ethcore/types/src/verification_queue_info.rs +++ b/ethcore/types/src/verification_queue_info.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/vm/Cargo.toml b/ethcore/vm/Cargo.toml index c5d31f58e61578de7ce8d4b677722fede41f8022..194f4600d82c216ca27e5d6366d8482abf37fa87 100644 --- a/ethcore/vm/Cargo.toml +++ b/ethcore/vm/Cargo.toml @@ -5,11 +5,12 @@ authors = ["Parity Technologies "] [dependencies] byteorder = "1.0" -ethcore-bytes = { path = "../../util/bytes" } +parity-bytes = { git = "https://github.com/paritytech/parity-common" } ethereum-types = "0.3" -patricia-trie = { path = "../../util/patricia_trie" } +patricia-trie = { git = "https://github.com/paritytech/parity-common" } +patricia-trie-ethereum = { path = "../../util/patricia-trie-ethereum" } log = "0.3" common-types = { path = "../types" } ethjson = { path = "../../json" } -rlp = { path = "../../util/rlp" } -keccak-hash = { path = "../../util/hash" } +rlp = { git = "https://github.com/paritytech/parity-common" } +keccak-hash = { git = "https://github.com/paritytech/parity-common" } diff --git a/ethcore/vm/src/action_params.rs b/ethcore/vm/src/action_params.rs index 9e9a35528c89e3247ed07683a86c438bb3a3e45d..481f6373104935e516d5e6ba1dbe39a9ee04d340 100644 --- a/ethcore/vm/src/action_params.rs +++ b/ethcore/vm/src/action_params.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/vm/src/call_type.rs b/ethcore/vm/src/call_type.rs index dc00b2b83923a76f48cd8c0ed997481d7fd34d07..0e58d76bbd269ca02aeccd2495db6f45993c79b9 100644 --- a/ethcore/vm/src/call_type.rs +++ b/ethcore/vm/src/call_type.rs @@ -1,3 +1,19 @@ +// 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 . + //! EVM call types. use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; diff --git a/ethcore/vm/src/env_info.rs b/ethcore/vm/src/env_info.rs index 71bb48eeb721383f127866717f6affb093db59d2..bb1c9ecd91f05d9e4e4890d6ec8f3c875f9990f2 100644 --- a/ethcore/vm/src/env_info.rs +++ b/ethcore/vm/src/env_info.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/vm/src/error.rs b/ethcore/vm/src/error.rs index fe8d7054cfe1ff8d59490fee0216f1a18dbcc7cf..b5e337a75fbf5c5c798da052927ae45ce52b5be5 100644 --- a/ethcore/vm/src/error.rs +++ b/ethcore/vm/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -16,8 +16,8 @@ //! VM errors module -use trie; use std::fmt; +use ethtrie; /// VM errors. #[derive(Debug, Clone, PartialEq)] @@ -71,9 +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/ext.rs b/ethcore/vm/src/ext.rs index 98661e47e2f8d9c6f82de8ad5f254b7b980e3e1c..3e6ee1e0265c7b087690d506f5c8ff060caeb210 100644 --- a/ethcore/vm/src/ext.rs +++ b/ethcore/vm/src/ext.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -53,11 +53,11 @@ pub enum MessageCallResult { /// Specifies how an address is calculated for a new contract. #[derive(Copy, Clone, PartialEq, Eq)] pub enum CreateContractAddress { - /// Address is calculated from nonce and sender. Pre EIP-86 (Metropolis) + /// Address is calculated from sender and nonce. Pre EIP-86 (Metropolis) FromSenderAndNonce, - /// Address is calculated from code hash. Default since EIP-86 - FromCodeHash, - /// Address is calculated from code hash and sender. Used by CREATE_P2SH instruction. + /// Address is calculated from sender, salt and code hash. EIP-86 CREATE2 scheme. + FromSenderSaltAndCodeHash(H256), + /// Address is calculated from code hash and sender. Used by pwasm create ext. FromSenderAndCodeHash, } @@ -106,10 +106,13 @@ pub trait Ext { ) -> MessageCallResult; /// Returns code at given address - fn extcode(&self, address: &Address) -> Result>; + fn extcode(&self, address: &Address) -> Result>>; + + /// Returns code hash at given address + fn extcodehash(&self, address: &Address) -> Result>; /// Returns code size at given address - fn extcodesize(&self, address: &Address) -> Result; + fn extcodesize(&self, address: &Address) -> Result>; /// Creates log entry with given topics and data fn log(&mut self, topics: Vec, data: &[u8]) -> Result<()>; diff --git a/ethcore/vm/src/lib.rs b/ethcore/vm/src/lib.rs index 67fc59bab5ec02338738ea39c0bdbd59af10f443..2c98cfcd247730dba3aed35aa5db5106de884bba 100644 --- a/ethcore/vm/src/lib.rs +++ b/ethcore/vm/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -17,11 +17,12 @@ //! Virtual machines support library extern crate ethereum_types; -extern crate ethcore_bytes as bytes; +extern crate parity_bytes as bytes; 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/vm/src/return_data.rs b/ethcore/vm/src/return_data.rs index 067a26e35e33a5eb3aa0e59a3f2eef3f1b498615..24191ec55f61240a7db1a57911090f2381201374 100644 --- a/ethcore/vm/src/return_data.rs +++ b/ethcore/vm/src/return_data.rs @@ -1,3 +1,5 @@ +// 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 diff --git a/ethcore/vm/src/schedule.rs b/ethcore/vm/src/schedule.rs index a0085ef1ecea60fabe3ab0772ec5687b1844d5c0..757d8a16d5d5aabb6fbcae223eefce8256fd6319 100644 --- a/ethcore/vm/src/schedule.rs +++ b/ethcore/vm/src/schedule.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -22,10 +22,12 @@ pub struct Schedule { pub exceptional_failed_code_deposit: bool, /// Does it have a delegate cal pub have_delegate_call: bool, - /// Does it have a CREATE_P2SH instruction + /// Does it have a CREATE2 instruction pub have_create2: bool, /// Does it have a REVERT instruction pub have_revert: bool, + /// Does it have a EXTCODEHASH instruction + pub have_extcodehash: bool, /// VM stack limit pub stack_limit: usize, /// Max number of nested calls/creates @@ -92,6 +94,8 @@ pub struct Schedule { pub extcodecopy_base_gas: usize, /// Price of BALANCE pub balance_gas: usize, + /// Price of EXTCODEHASH + pub extcodehash_gas: usize, /// Price of SUICIDE pub suicide_gas: usize, /// Amount of additional gas to pay when SUICIDE credits a non-existant account @@ -197,6 +201,7 @@ impl Schedule { have_revert: false, have_return_data: false, have_bitwise_shifting: false, + have_extcodehash: false, stack_limit: 1024, max_depth: 1024, tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0], @@ -229,6 +234,7 @@ impl Schedule { copy_gas: 3, extcodesize_gas: 700, extcodecopy_base_gas: 700, + extcodehash_gas: 400, balance_gas: 400, suicide_gas: 5000, suicide_to_new_account_cost: 25000, @@ -268,6 +274,7 @@ impl Schedule { have_revert: false, have_return_data: false, have_bitwise_shifting: false, + have_extcodehash: false, stack_limit: 1024, max_depth: 1024, tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0], @@ -300,6 +307,7 @@ impl Schedule { copy_gas: 3, extcodesize_gas: 20, extcodecopy_base_gas: 20, + extcodehash_gas: 400, balance_gas: 20, suicide_gas: 0, suicide_to_new_account_cost: 0, diff --git a/ethcore/vm/src/tests.rs b/ethcore/vm/src/tests.rs index daf46be0f07a3018e43203eda8735a4e857e78ad..d83e6881a12a5035d73ac0614c370b35639f4e1b 100644 --- a/ethcore/vm/src/tests.rs +++ b/ethcore/vm/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -24,6 +24,7 @@ use { ReturnData, Ext, ContractCreateResult, MessageCallResult, CreateContractAddress, Result, GasLeft, }; +use hash::keccak; pub struct FakeLogEntry { pub topics: Vec, @@ -168,12 +169,16 @@ impl Ext for FakeExt { MessageCallResult::Success(*gas, ReturnData::empty()) } - fn extcode(&self, address: &Address) -> Result> { - Ok(self.codes.get(address).unwrap_or(&Arc::new(Bytes::new())).clone()) + fn extcode(&self, address: &Address) -> Result>> { + Ok(self.codes.get(address).cloned()) } - fn extcodesize(&self, address: &Address) -> Result { - Ok(self.codes.get(address).map_or(0, |c| c.len())) + fn extcodesize(&self, address: &Address) -> Result> { + Ok(self.codes.get(address).map(|c| c.len())) + } + + fn extcodehash(&self, address: &Address) -> Result> { + Ok(self.codes.get(address).map(|c| keccak(c.as_ref()))) } fn log(&mut self, topics: Vec, data: &[u8]) -> Result<()> { diff --git a/ethcore/wasm/Cargo.toml b/ethcore/wasm/Cargo.toml index a0362955d1db998943b1284a601f045d6a5d2a16..5ca2f31220ae46a00cd443c005fa89ef1878ea4f 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/run/src/fixture.rs b/ethcore/wasm/run/src/fixture.rs index ba2da0670677a1d80473688ad57d0752684c1811..9fc1ca6fefb1b5c9b5b41d4307b22f7088e82f0d 100644 --- a/ethcore/wasm/run/src/fixture.rs +++ b/ethcore/wasm/run/src/fixture.rs @@ -1,3 +1,19 @@ +// 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 . + use std::borrow::Cow; use ethjson::uint::Uint; use ethjson::hash::{Address, H256}; @@ -67,4 +83,4 @@ pub enum Assert { HasStorage(StorageAssert), UsedGas(u64), Return(Bytes), -} \ No newline at end of file +} diff --git a/ethcore/wasm/run/src/main.rs b/ethcore/wasm/run/src/main.rs index ab8ac631df9136e8263fce5d5e3e8d9dba7a788d..d2a3a0ff5061a89adae744fa3a8e3f9906d96ee4 100644 --- a/ethcore/wasm/run/src/main.rs +++ b/ethcore/wasm/run/src/main.rs @@ -1,3 +1,19 @@ +// 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 . + extern crate serde; extern crate serde_json; #[macro_use] extern crate serde_derive; diff --git a/ethcore/wasm/run/src/runner.rs b/ethcore/wasm/run/src/runner.rs index 5ae0f941a42748b01547e4dc738a3e1a76d93ae1..3e24ced5db2da24885371f9652b349ee437e1e1d 100644 --- a/ethcore/wasm/run/src/runner.rs +++ b/ethcore/wasm/run/src/runner.rs @@ -1,3 +1,19 @@ +// 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 . + use fixture::{Fixture, Assert, CallLocator, Source}; use wasm::WasmInterpreter; use vm::{self, Vm, GasLeft, ActionParams, ActionValue, ParamsType}; diff --git a/ethcore/wasm/src/env.rs b/ethcore/wasm/src/env.rs index 7ffaaf98abd2f04797e9fcd0c30abdc51d5085cb..9bcbee63fb0eedf2fb8f9c0a6b0308839d9c2f42 100644 --- a/ethcore/wasm/src/env.rs +++ b/ethcore/wasm/src/env.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -295,4 +295,4 @@ impl wasmi::ModuleImportResolver for ImportResolver { Err(Error::Instantiation("Memory imported under unknown name".to_owned())) } } -} \ No newline at end of file +} diff --git a/ethcore/wasm/src/lib.rs b/ethcore/wasm/src/lib.rs index 5605a7ea185683c44d0d1e542b7624748e98d20d..f1290318e0f2b7a8b7988002dd11d1e259c3a178 100644 --- a/ethcore/wasm/src/lib.rs +++ b/ethcore/wasm/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/wasm/src/panic_payload.rs b/ethcore/wasm/src/panic_payload.rs index dc95f53fbfc9bca70fbb3b65c5885c120e795489..36aa6c5f585be93f03957dbe048670a8e618ce6a 100644 --- a/ethcore/wasm/src/panic_payload.rs +++ b/ethcore/wasm/src/panic_payload.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/wasm/src/parser.rs b/ethcore/wasm/src/parser.rs index 62cd66cb98c8e50fa13f665dbc24496d11d13eb7..656ebb3019187d89a4f386b52afde2c52a8368c3 100644 --- a/ethcore/wasm/src/parser.rs +++ b/ethcore/wasm/src/parser.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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)); @@ -95,4 +95,4 @@ pub fn payload<'a>(params: &'a vm::ActionParams, wasm_costs: &vm::WasmCosts) }; Ok((contract_module, data)) -} \ No newline at end of file +} diff --git a/ethcore/wasm/src/tests.rs b/ethcore/wasm/src/tests.rs index 2b71a1768eb395befbb6c2d1da3b55684a1c19de..726b9ebabbbf65013c936b8116ef653a644bd949 100644 --- a/ethcore/wasm/src/tests.rs +++ b/ethcore/wasm/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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/ethkey/Cargo.toml b/ethkey/Cargo.toml index 952354739d52750f256f207d3659307877e6e3fc..8449a54c3b255f6c6a99ce8abc44ac2083b976ff 100644 --- a/ethkey/Cargo.toml +++ b/ethkey/Cargo.toml @@ -6,14 +6,16 @@ authors = ["Parity Technologies "] [dependencies] byteorder = "1.0" edit-distance = "2.0" -ethcore-crypto = { path = "../ethcore/crypto" } +parity-crypto = { git = "https://github.com/paritytech/parity-common" } eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" } ethereum-types = "0.3" lazy_static = "1.0" log = "0.3" mem = { path = "../util/mem" } parity-wordlist = "1.2" -quick-error = "1.2" +quick-error = "1.2.2" rand = "0.4" rustc-hex = "1.0" +serde = "1.0" +serde_derive = "1.0" tiny-keccak = "1.4" diff --git a/ethkey/cli/src/main.rs b/ethkey/cli/src/main.rs index 0dfc8aecde01c681d35beeac4d7f08b01fa2e424..555bc2d201051352bbf4b8c5d05b0f23d2d2961f 100644 --- a/ethkey/cli/src/main.rs +++ b/ethkey/cli/src/main.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -161,15 +161,16 @@ impl DisplayMode { } fn main() { - panic_hook::set(); + panic_hook::set_abort(); env_logger::init().expect("Logger initialized only once."); match execute(env::args()) { Ok(ok) => println!("{}", ok), + Err(Error::Docopt(ref e)) => e.exit(), Err(err) => { println!("{}", err); process::exit(1); - }, + } } } diff --git a/ethkey/src/brain.rs b/ethkey/src/brain.rs index fffae0bed8e08ba9955e502969ec37062cd281ed..55b525e2a4137866d9d3fe12e9b21d92a7336081 100644 --- a/ethkey/src/brain.rs +++ b/ethkey/src/brain.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/src/brain_prefix.rs b/ethkey/src/brain_prefix.rs index a4e31e989c969d063dfb36ad600700479deca63a..accf9473700e0630eead6821f355e7a7f20fb36d 100644 --- a/ethkey/src/brain_prefix.rs +++ b/ethkey/src/brain_prefix.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/src/brain_recover.rs b/ethkey/src/brain_recover.rs index f064c6fd0e1bc6bf9dcc1f4134faf69ef09c66c2..51331932328bcd9c1aea6a47393db244d8acee4c 100644 --- a/ethkey/src/brain_recover.rs +++ b/ethkey/src/brain_recover.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -21,7 +21,6 @@ use parity_wordlist; use super::{Address, Brain, Generator}; - /// Tries to find a phrase for address, given the number /// of expected words and a partial phrase. /// @@ -150,7 +149,6 @@ impl Iterator for PhrasesIterator { mod tests { use super::PhrasesIterator; - #[test] fn should_generate_possible_combinations() { let mut it = PhrasesIterator::new(vec![ diff --git a/ethkey/src/crypto.rs b/ethkey/src/crypto.rs index 739a463c072d604a2d756ef76cc4586fa364d624..8049f16b584beee2e35711aa1e27a3c4ec9d96f0 100644 --- a/ethkey/src/crypto.rs +++ b/ethkey/src/crypto.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -16,7 +16,7 @@ use secp256k1; use std::io; -use ethcore_crypto::error::SymmError; +use parity_crypto::error::SymmError; quick_error! { #[derive(Debug)] @@ -67,7 +67,7 @@ pub mod ecdh { /// ECIES function pub mod ecies { - use ethcore_crypto::{aes, digest, hmac, is_equal}; + use parity_crypto::{aes, digest, hmac, is_equal}; use ethereum_types::H128; use super::{ecdh, Error}; use {Random, Generator, Public, Secret}; diff --git a/ethkey/src/error.rs b/ethkey/src/error.rs index c7faf6778807294f379366e1d246c7daddeb8e9a..7cba375d0f2690af20869c8601a5e5199103b2ab 100644 --- a/ethkey/src/error.rs +++ b/ethkey/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/src/extended.rs b/ethkey/src/extended.rs index d41ae54c532ba0b615617b23deb7a817b98876ac..e48f6b5616e10d592fa7ed603cd1bcbd19e8b1d9 100644 --- a/ethkey/src/extended.rs +++ b/ethkey/src/extended.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -207,7 +207,7 @@ impl ExtendedKeyPair { // Work is based on BIP0032 // https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki mod derivation { - use ethcore_crypto::hmac; + use parity_crypto::hmac; use ethereum_types::{U256, U512, H512, H256}; use secp256k1::key::{SecretKey, PublicKey}; use SECP256K1; diff --git a/ethkey/src/keccak.rs b/ethkey/src/keccak.rs index 002f20d9468fbcde383421b8e03e71025ae8409f..3801d841ab0cbc4dfe5c33bee3c26d460e6d3fcc 100644 --- a/ethkey/src/keccak.rs +++ b/ethkey/src/keccak.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/src/keypair.rs b/ethkey/src/keypair.rs index 5a13d476bb329e8128fb1f4d7744b6960139d0c7..610c14524fefd6ebb1e33a536f840521433134ab 100644 --- a/ethkey/src/keypair.rs +++ b/ethkey/src/keypair.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/src/lib.rs b/ethkey/src/lib.rs index b5cf9845306702954d924742ae0fe2fdb2d9b2f9..013a60cd3a8d8d5dcb6ea8247030a5fb415cf298 100644 --- a/ethkey/src/lib.rs +++ b/ethkey/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -18,7 +18,7 @@ extern crate byteorder; extern crate edit_distance; -extern crate ethcore_crypto; +extern crate parity_crypto; extern crate ethereum_types; extern crate mem; extern crate parity_wordlist; @@ -27,18 +27,22 @@ extern crate quick_error; extern crate rand; extern crate rustc_hex; extern crate secp256k1; +extern crate serde; extern crate tiny_keccak; #[macro_use] extern crate lazy_static; #[macro_use] extern crate log; +#[macro_use] +extern crate serde_derive; mod brain; mod brain_prefix; mod error; mod keypair; mod keccak; +mod password; mod prefix; mod random; mod signature; @@ -55,6 +59,7 @@ pub use self::brain_prefix::BrainPrefix; pub use self::error::Error; pub use self::keypair::{KeyPair, public_to_address}; pub use self::math::public_is_valid; +pub use self::password::Password; pub use self::prefix::Prefix; pub use self::random::Random; pub use self::signature::{sign, verify_public, verify_address, recover, Signature}; diff --git a/ethkey/src/math.rs b/ethkey/src/math.rs index e2426b4fbdff3b37a3166276c8a18cca62b2f41d..6b1d4013bd7d534f6ee4d762eb4d65872a20b2d0 100644 --- a/ethkey/src/math.rs +++ b/ethkey/src/math.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/src/password.rs b/ethkey/src/password.rs new file mode 100644 index 0000000000000000000000000000000000000000..d349663739b5091ee9fde35f931f14a5e215a08c --- /dev/null +++ b/ethkey/src/password.rs @@ -0,0 +1,60 @@ +// Copyright 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 . + +use std::{fmt, ptr}; + +#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct Password(String); + +impl fmt::Debug for Password { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Password(******)") + } +} + +impl Password { + pub fn as_bytes(&self) -> &[u8] { + self.0.as_bytes() + } + + pub fn as_str(&self) -> &str { + self.0.as_str() + } +} + +// Custom drop impl to zero out memory. +impl Drop for Password { + fn drop(&mut self) { + unsafe { + for byte_ref in self.0.as_mut_vec() { + ptr::write_volatile(byte_ref, 0) + } + } + } +} + +impl From for Password { + fn from(s: String) -> Password { + Password(s) + } +} + +impl<'a> From<&'a str> for Password { + fn from(s: &'a str) -> Password { + Password::from(String::from(s)) + } +} + diff --git a/ethkey/src/prefix.rs b/ethkey/src/prefix.rs index f2ef0f0ffb4610d05cd37e2d9ca3f59e25cdfe58..2668050ef8e8ac3735393a9bdb85f01dfabd9e8c 100644 --- a/ethkey/src/prefix.rs +++ b/ethkey/src/prefix.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/src/random.rs b/ethkey/src/random.rs index b44a4b2ca8015acef2b72882e1f8cafc03fc9fa9..d42bb4ea4df1c4f3e43b0fe08bf7a0c009d31e17 100644 --- a/ethkey/src/random.rs +++ b/ethkey/src/random.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/src/secret.rs b/ethkey/src/secret.rs index c3bf2a12bae3d0dffda8089cbd7d4328a301f659..a3560698af4a02b78e61cb349b433a5e9be849ac 100644 --- a/ethkey/src/secret.rs +++ b/ethkey/src/secret.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/src/signature.rs b/ethkey/src/signature.rs index ec225ec011b3d78ed743d7573894401169ef868e..cd6d88fe18736847792de6406892c61cff2d715f 100644 --- a/ethkey/src/signature.rs +++ b/ethkey/src/signature.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/Cargo.toml b/ethstore/Cargo.toml index 6108143cb9e9c239341738212c9c6508075beb7d..deeb5a946b8ed9f51540684870701ca2bc0cdc98 100644 --- a/ethstore/Cargo.toml +++ b/ethstore/Cargo.toml @@ -15,8 +15,8 @@ rustc-hex = "1.0" tiny-keccak = "1.4" time = "0.1.34" itertools = "0.5" -parking_lot = "0.5" -ethcore-crypto = { path = "../ethcore/crypto" } +parking_lot = "0.6" +parity-crypto = { git = "https://github.com/paritytech/parity-common" } ethereum-types = "0.3" dir = { path = "../util/dir" } smallvec = "0.4" diff --git a/ethstore/cli/Cargo.toml b/ethstore/cli/Cargo.toml index bd5db86216f111d16648392b1edfb04d3d89db30..b1736efdb3853b29bb3effea94f6a2f479312a3d 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/ethstore/cli/src/crack.rs b/ethstore/cli/src/crack.rs index 64eda66e56ed378ed10fb9d9a92377aee03af1bd..00844b7f016d4e5b1c4fe84184d1926e2baffd5d 100644 --- a/ethstore/cli/src/crack.rs +++ b/ethstore/cli/src/crack.rs @@ -1,12 +1,28 @@ +// 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 . + use std::{cmp, thread}; use std::sync::Arc; use std::collections::VecDeque; use parking_lot::Mutex; -use ethstore::{PresaleWallet, Error}; +use ethstore::{ethkey::Password, PresaleWallet, Error}; use num_cpus; -pub fn run(passwords: VecDeque, wallet_path: &str) -> Result<(), Error> { +pub fn run(passwords: VecDeque, wallet_path: &str) -> Result<(), Error> { let passwords = Arc::new(Mutex::new(passwords)); let mut handles = Vec::new(); @@ -26,7 +42,7 @@ pub fn run(passwords: VecDeque, wallet_path: &str) -> Result<(), Error> Ok(()) } -fn look_for_password(passwords: Arc>>, wallet: PresaleWallet) { +fn look_for_password(passwords: Arc>>, wallet: PresaleWallet) { let mut counter = 0; while !passwords.lock().is_empty() { let package = { @@ -38,7 +54,7 @@ fn look_for_password(passwords: Arc>>, wallet: PresaleWal counter += 1; match wallet.decrypt(&pass) { Ok(_) => { - println!("Found password: {}", &pass); + println!("Found password: {}", pass.as_str()); passwords.lock().clear(); return; }, diff --git a/ethstore/cli/src/main.rs b/ethstore/cli/src/main.rs index 8ebb206a0bf8294cd90b33f95ef8b99e088e63b3..e542bd90899b5d7885ee9180dc2ec7772d0eb10e 100644 --- a/ethstore/cli/src/main.rs +++ b/ethstore/cli/src/main.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -32,7 +32,7 @@ use std::{env, process, fs, fmt}; use docopt::Docopt; use ethstore::accounts_dir::{KeyDirectory, RootDiskDirectory}; -use ethstore::ethkey::Address; +use ethstore::ethkey::{Address, Password}; use ethstore::{EthStore, SimpleSecretStore, SecretStore, import_accounts, PresaleWallet, SecretVaultRef, StoreAccountRef}; mod crack; @@ -145,10 +145,11 @@ impl fmt::Display for Error { } fn main() { - panic_hook::set(); + panic_hook::set_abort(); match execute(env::args()) { Ok(result) => println!("{}", result), + Err(Error::Docopt(ref e)) => e.exit(), Err(err) => { println!("{}", err); process::exit(1); @@ -200,13 +201,13 @@ fn format_vaults(vaults: &[String]) -> String { vaults.join("\n") } -fn load_password(path: &str) -> Result { +fn load_password(path: &str) -> Result { let mut file = fs::File::open(path).map_err(|e| ethstore::Error::Custom(format!("Error opening password file {}: {}", path, e)))?; let mut password = String::new(); file.read_to_string(&mut password).map_err(|e| ethstore::Error::Custom(format!("Error reading password file {}: {}", path, e)))?; // drop EOF let _ = password.pop(); - Ok(password) + Ok(password.into()) } fn execute(command: I) -> Result where I: IntoIterator, S: AsRef { @@ -251,7 +252,7 @@ fn execute(command: I) -> Result where I: IntoIterator>(); + let passwords = passwords.as_str().lines().map(|line| str::to_owned(line).into()).collect::>(); crack::run(passwords, &args.arg_path)?; Ok(format!("Password not found.")) } else if args.cmd_remove { diff --git a/ethstore/cli/tests/cli.rs b/ethstore/cli/tests/cli.rs index a740b95c28c997158d17aa016dafca4555e54fd7..1b899f7082e863d21183377d320dcf31803d20ba 100644 --- a/ethstore/cli/tests/cli.rs +++ b/ethstore/cli/tests/cli.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -74,7 +74,6 @@ fn cli_cmd() { "--vault-pwd", test_password]); assert_eq!(output, "0x54ab6e5cf0c5cb40043fdca5d15d611a3a94285414a076dafecc8dc9c04183f413296a3defff61092c0bb478dc9887ec01070e1275234211208fb8f4be4a9b0101\n"); - let output = run(&["public", &address[2..], test_vault_addr, "--dir", dir_str, "--vault", "test-vault", diff --git a/ethstore/src/account/cipher.rs b/ethstore/src/account/cipher.rs index 427ccafc4a01a6bf99111a558ea3252e546ce1da..92a5304edb9231ccd1fbc886bb9604c2dd66fcf1 100644 --- a/ethstore/src/account/cipher.rs +++ b/ethstore/src/account/cipher.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/account/crypto.rs b/ethstore/src/account/crypto.rs index bd65bc927b0a73e3356308a3aa0380a308c60cb6..07f84af7fa4d45a33295e97a32b6b13b4064f9b3 100644 --- a/ethstore/src/account/crypto.rs +++ b/ethstore/src/account/crypto.rs @@ -1,4 +1,4 @@ -// Copyright 2015, 2016, 2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ // along with Parity. If not, see . use std::str; -use ethkey::Secret; +use ethkey::{Password, Secret}; use {json, Error, crypto}; use crypto::Keccak256; use random::Random; @@ -73,18 +73,18 @@ impl From for String { impl Crypto { /// Encrypt account secret - pub fn with_secret(secret: &Secret, password: &str, iterations: u32) -> Result { + pub fn with_secret(secret: &Secret, password: &Password, iterations: u32) -> Result { Crypto::with_plain(&*secret, password, iterations) } /// Encrypt custom plain data - pub fn with_plain(plain: &[u8], password: &str, iterations: u32) -> Result { + pub fn with_plain(plain: &[u8], password: &Password, iterations: u32) -> Result { let salt: [u8; 32] = Random::random(); let iv: [u8; 16] = Random::random(); // two parts of derived key // DK = [ DK[0..15] DK[16..31] ] = [derived_left_bits, derived_right_bits] - let (derived_left_bits, derived_right_bits) = crypto::derive_key_iterations(password, &salt, iterations); + let (derived_left_bits, derived_right_bits) = crypto::derive_key_iterations(password.as_bytes(), &salt, iterations); // preallocated (on-stack in case of `Secret`) buffer to hold cipher // length = length(plain) as we are using CTR-approach @@ -113,7 +113,7 @@ impl Crypto { } /// Try to decrypt and convert result to account secret - pub fn secret(&self, password: &str) -> Result { + pub fn secret(&self, password: &Password) -> Result { if self.ciphertext.len() > 32 { return Err(Error::InvalidSecret); } @@ -123,15 +123,15 @@ impl Crypto { } /// Try to decrypt and return result as is - pub fn decrypt(&self, password: &str) -> Result, Error> { + pub fn decrypt(&self, password: &Password) -> Result, Error> { let expected_len = self.ciphertext.len(); self.do_decrypt(password, expected_len) } - fn do_decrypt(&self, password: &str, expected_len: usize) -> Result, Error> { + fn do_decrypt(&self, password: &Password, expected_len: usize) -> Result, Error> { let (derived_left_bits, derived_right_bits) = match self.kdf { - Kdf::Pbkdf2(ref params) => crypto::derive_key_iterations(password, ¶ms.salt, params.c), - Kdf::Scrypt(ref params) => crypto::scrypt::derive_key(password, ¶ms.salt, params.n, params.p, params.r)?, + Kdf::Pbkdf2(ref params) => crypto::derive_key_iterations(password.as_bytes(), ¶ms.salt, params.c), + Kdf::Scrypt(ref params) => crypto::scrypt::derive_key(password.as_bytes(), ¶ms.salt, params.n, params.p, params.r)?, }; let mac = crypto::derive_mac(&derived_right_bits, &self.ciphertext).keccak256(); @@ -163,39 +163,43 @@ mod tests { #[test] fn crypto_with_secret_create() { let keypair = Random.generate().unwrap(); - let crypto = Crypto::with_secret(keypair.secret(), "this is sparta", 10240).unwrap(); - let secret = crypto.secret("this is sparta").unwrap(); + let passwd = "this is sparta".into(); + let crypto = Crypto::with_secret(keypair.secret(), &passwd, 10240).unwrap(); + let secret = crypto.secret(&passwd).unwrap(); assert_eq!(keypair.secret(), &secret); } #[test] fn crypto_with_secret_invalid_password() { let keypair = Random.generate().unwrap(); - let crypto = Crypto::with_secret(keypair.secret(), "this is sparta", 10240).unwrap(); - assert_matches!(crypto.secret("this is sparta!"), Err(Error::InvalidPassword)) + let crypto = Crypto::with_secret(keypair.secret(), &"this is sparta".into(), 10240).unwrap(); + assert_matches!(crypto.secret(&"this is sparta!".into()), Err(Error::InvalidPassword)) } #[test] fn crypto_with_null_plain_data() { let original_data = b""; - let crypto = Crypto::with_plain(&original_data[..], "this is sparta", 10240).unwrap(); - let decrypted_data = crypto.decrypt("this is sparta").unwrap(); + let passwd = "this is sparta".into(); + let crypto = Crypto::with_plain(&original_data[..], &passwd, 10240).unwrap(); + let decrypted_data = crypto.decrypt(&passwd).unwrap(); assert_eq!(original_data[..], *decrypted_data); } #[test] fn crypto_with_tiny_plain_data() { let original_data = b"{}"; - let crypto = Crypto::with_plain(&original_data[..], "this is sparta", 10240).unwrap(); - let decrypted_data = crypto.decrypt("this is sparta").unwrap(); + let passwd = "this is sparta".into(); + let crypto = Crypto::with_plain(&original_data[..], &passwd, 10240).unwrap(); + let decrypted_data = crypto.decrypt(&passwd).unwrap(); assert_eq!(original_data[..], *decrypted_data); } #[test] fn crypto_with_huge_plain_data() { let original_data: Vec<_> = (1..65536).map(|i| (i % 256) as u8).collect(); - let crypto = Crypto::with_plain(&original_data, "this is sparta", 10240).unwrap(); - let decrypted_data = crypto.decrypt("this is sparta").unwrap(); + let passwd = "this is sparta".into(); + let crypto = Crypto::with_plain(&original_data, &passwd, 10240).unwrap(); + let decrypted_data = crypto.decrypt(&passwd).unwrap(); assert_eq!(&original_data, &decrypted_data); } } diff --git a/ethstore/src/account/kdf.rs b/ethstore/src/account/kdf.rs index 31b8f304ca63b25972b5dcc876724c33d03737d8..4d6d7cd956df3c6b65dcf10be2a83822becef356 100644 --- a/ethstore/src/account/kdf.rs +++ b/ethstore/src/account/kdf.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/account/mod.rs b/ethstore/src/account/mod.rs index c352ffe78fcb8c3eb5ec4bcd271af310a7d7574e..e13237d827056d886cf9019c29aaf93fcc30dcbf 100644 --- a/ethstore/src/account/mod.rs +++ b/ethstore/src/account/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -25,4 +25,3 @@ pub use self::crypto::Crypto; pub use self::kdf::{Kdf, Pbkdf2, Scrypt, Prf}; pub use self::safe_account::SafeAccount; pub use self::version::Version; - diff --git a/ethstore/src/account/safe_account.rs b/ethstore/src/account/safe_account.rs index 069c997e1017f485fcac4ce784b57fcb66d2de0b..849dafab1035dcd9f860cd8fef81868b87a0a879 100644 --- a/ethstore/src/account/safe_account.rs +++ b/ethstore/src/account/safe_account.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethkey::{self, KeyPair, sign, Address, Signature, Message, Public, Secret}; +use ethkey::{self, KeyPair, sign, Address, Password, Signature, Message, Public, Secret}; use ethkey::crypto::ecdh::agree; use {json, Error}; use account::Version; @@ -58,7 +58,7 @@ impl SafeAccount { pub fn create( keypair: &KeyPair, id: [u8; 16], - password: &str, + password: &Password, iterations: u32, name: String, meta: String @@ -92,7 +92,7 @@ impl SafeAccount { /// Create a new `SafeAccount` from the given vault `json`; if it was read from a /// file, the `filename` should be `Some` name. If it is as yet anonymous, then it /// can be left `None`. - pub fn from_vault_file(password: &str, json: json::VaultKeyFile, filename: Option) -> Result { + pub fn from_vault_file(password: &Password, json: json::VaultKeyFile, filename: Option) -> Result { let meta_crypto: Crypto = json.metacrypto.into(); let meta_plain = meta_crypto.decrypt(password)?; let meta_plain = json::VaultKeyMeta::load(&meta_plain).map_err(|e| Error::Custom(format!("{:?}", e)))?; @@ -108,7 +108,7 @@ impl SafeAccount { } /// Create a new `VaultKeyFile` from the given `self` - pub fn into_vault_file(self, iterations: u32, password: &str) -> Result { + pub fn into_vault_file(self, iterations: u32, password: &Password) -> Result { let meta_plain = json::VaultKeyMeta { address: self.address.into(), name: Some(self.name), @@ -126,31 +126,31 @@ impl SafeAccount { } /// Sign a message. - pub fn sign(&self, password: &str, message: &Message) -> Result { + pub fn sign(&self, password: &Password, message: &Message) -> Result { let secret = self.crypto.secret(password)?; sign(&secret, message).map_err(From::from) } /// Decrypt a message. - pub fn decrypt(&self, password: &str, shared_mac: &[u8], message: &[u8]) -> Result, Error> { + pub fn decrypt(&self, password: &Password, shared_mac: &[u8], message: &[u8]) -> Result, Error> { let secret = self.crypto.secret(password)?; ethkey::crypto::ecies::decrypt(&secret, shared_mac, message).map_err(From::from) } /// Agree on shared key. - pub fn agree(&self, password: &str, other: &Public) -> Result { + pub fn agree(&self, password: &Password, other: &Public) -> Result { let secret = self.crypto.secret(password)?; agree(&secret, other).map_err(From::from) } /// Derive public key. - pub fn public(&self, password: &str) -> Result { + pub fn public(&self, password: &Password) -> Result { let secret = self.crypto.secret(password)?; Ok(KeyPair::from_secret(secret)?.public().clone()) } /// Change account's password. - pub fn change_password(&self, old_password: &str, new_password: &str, iterations: u32) -> Result { + pub fn change_password(&self, old_password: &Password, new_password: &Password, iterations: u32) -> Result { let secret = self.crypto.secret(old_password)?; let result = SafeAccount { id: self.id.clone(), @@ -165,7 +165,7 @@ impl SafeAccount { } /// Check if password matches the account. - pub fn check_password(&self, password: &str) -> bool { + pub fn check_password(&self, password: &Password) -> bool { self.crypto.secret(password).is_ok() } } @@ -178,25 +178,25 @@ mod tests { #[test] fn sign_and_verify_public() { let keypair = Random.generate().unwrap(); - let password = "hello world"; + let password = "hello world".into(); let message = Message::default(); - let account = SafeAccount::create(&keypair, [0u8; 16], password, 10240, "Test".to_owned(), "{}".to_owned()); - let signature = account.unwrap().sign(password, &message).unwrap(); + let account = SafeAccount::create(&keypair, [0u8; 16], &password, 10240, "Test".to_owned(), "{}".to_owned()); + let signature = account.unwrap().sign(&password, &message).unwrap(); assert!(verify_public(keypair.public(), &signature, &message).unwrap()); } #[test] fn change_password() { let keypair = Random.generate().unwrap(); - let first_password = "hello world"; - let sec_password = "this is sparta"; + let first_password = "hello world".into(); + let sec_password = "this is sparta".into(); let i = 10240; let message = Message::default(); - let account = SafeAccount::create(&keypair, [0u8; 16], first_password, i, "Test".to_owned(), "{}".to_owned()).unwrap(); - let new_account = account.change_password(first_password, sec_password, i).unwrap(); - assert!(account.sign(first_password, &message).is_ok()); - assert!(account.sign(sec_password, &message).is_err()); - assert!(new_account.sign(first_password, &message).is_err()); - assert!(new_account.sign(sec_password, &message).is_ok()); + let account = SafeAccount::create(&keypair, [0u8; 16], &first_password, i, "Test".to_owned(), "{}".to_owned()).unwrap(); + let new_account = account.change_password(&first_password, &sec_password, i).unwrap(); + assert!(account.sign(&first_password, &message).is_ok()); + assert!(account.sign(&sec_password, &message).is_err()); + assert!(new_account.sign(&first_password, &message).is_err()); + assert!(new_account.sign(&sec_password, &message).is_ok()); } } diff --git a/ethstore/src/account/version.rs b/ethstore/src/account/version.rs index 2ba0848a682ecef79d64c0e95fb8f38ea55a79f2..d206a2c12d78efbe5e89f55f6018c67c01791869 100644 --- a/ethstore/src/account/version.rs +++ b/ethstore/src/account/version.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/accounts_dir/disk.rs b/ethstore/src/accounts_dir/disk.rs index 29b7e524660053baea8f5cb489253aa4262b9b9b..cf4841e7489a9232f146a8eb44f966e16213d9d9 100644 --- a/ethstore/src/accounts_dir/disk.rs +++ b/ethstore/src/accounts_dir/disk.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -33,22 +33,70 @@ const IGNORED_FILES: &'static [&'static str] = &[ "vault.json", ]; -#[cfg(not(windows))] -fn restrict_permissions_to_owner(file_path: &Path) -> Result<(), i32> { - use std::ffi; - use libc; +/// Find a unique filename that does not exist using four-letter random suffix. +pub fn find_unique_filename_using_random_suffix(parent_path: &Path, original_filename: &str) -> io::Result { + let mut path = parent_path.join(original_filename); + let mut deduped_filename = original_filename.to_string(); + + if path.exists() { + const MAX_RETRIES: usize = 500; + let mut retries = 0; + + while path.exists() { + if retries >= MAX_RETRIES { + return Err(io::Error::new(io::ErrorKind::Other, "Exceeded maximum retries when deduplicating filename.")); + } - let cstr = ffi::CString::new(&*file_path.to_string_lossy()) - .map_err(|_| -1)?; - match unsafe { libc::chmod(cstr.as_ptr(), libc::S_IWUSR | libc::S_IRUSR) } { - 0 => Ok(()), - x => Err(x), + let suffix = ::random::random_string(4); + deduped_filename = format!("{}-{}", original_filename, suffix); + path.set_file_name(&deduped_filename); + retries += 1; + } } + + Ok(deduped_filename) } -#[cfg(windows)] -fn restrict_permissions_to_owner(_file_path: &Path) -> Result<(), i32> { - Ok(()) +/// Create a new file and restrict permissions to owner only. It errors if the file already exists. +#[cfg(unix)] +pub fn create_new_file_with_permissions_to_owner(file_path: &Path) -> io::Result { + use libc; + use std::os::unix::fs::OpenOptionsExt; + + fs::OpenOptions::new() + .write(true) + .create_new(true) + .mode((libc::S_IWUSR | libc::S_IRUSR) as u32) + .open(file_path) +} + +/// Create a new file and restrict permissions to owner only. It errors if the file already exists. +#[cfg(not(unix))] +pub fn create_new_file_with_permissions_to_owner(file_path: &Path) -> io::Result { + fs::OpenOptions::new() + .write(true) + .create_new(true) + .open(file_path) +} + +/// Create a new file and restrict permissions to owner only. It replaces the existing file if it already exists. +#[cfg(unix)] +pub fn replace_file_with_permissions_to_owner(file_path: &Path) -> io::Result { + use libc; + use std::os::unix::fs::PermissionsExt; + + let file = fs::File::create(file_path)?; + let mut permissions = file.metadata()?.permissions(); + permissions.set_mode((libc::S_IWUSR | libc::S_IRUSR) as u32); + file.set_permissions(permissions)?; + + Ok(file) +} + +/// Create a new file and restrict permissions to owner only. It replaces the existing file if it already exists. +#[cfg(not(unix))] +pub fn replace_file_with_permissions_to_owner(file_path: &Path) -> io::Result { + fs::File::create(file_path) } /// Root keys directory implementation @@ -153,20 +201,16 @@ impl DiskDirectory where T: KeyFileManager { ) } - /// insert account with given filename. if the filename is a duplicate of any stored account and dedup is set to /// true, a random suffix is appended to the filename. pub fn insert_with_filename(&self, account: SafeAccount, mut filename: String, dedup: bool) -> Result { - // path to keyfile - let mut keyfile_path = self.path.join(filename.as_str()); - - // check for duplicate filename and append random suffix - if dedup && keyfile_path.exists() { - let suffix = ::random::random_string(4); - filename.push_str(&format!("-{}", suffix)); - keyfile_path.set_file_name(&filename); + if dedup { + filename = find_unique_filename_using_random_suffix(&self.path, &filename)?; } + // path to keyfile + let keyfile_path = self.path.join(filename.as_str()); + // update account filename let original_account = account.clone(); let mut account = account; @@ -174,17 +218,16 @@ impl DiskDirectory where T: KeyFileManager { { // save the file - let mut file = fs::File::create(&keyfile_path)?; + let mut file = if dedup { + create_new_file_with_permissions_to_owner(&keyfile_path)? + } else { + replace_file_with_permissions_to_owner(&keyfile_path)? + }; // write key content self.key_manager.write(original_account, &mut file).map_err(|e| Error::Custom(format!("{:?}", e)))?; file.flush()?; - - if let Err(_) = restrict_permissions_to_owner(keyfile_path.as_path()) { - return Err(Error::Io(io::Error::last_os_error())); - } - file.sync_all()?; } @@ -314,11 +357,11 @@ mod test { let mut dir = env::temp_dir(); dir.push("ethstore_should_create_new_account"); let keypair = Random.generate().unwrap(); - let password = "hello world"; + let password = "hello world".into(); let directory = RootDiskDirectory::create(dir.clone()).unwrap(); // when - let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned()); + let account = SafeAccount::create(&keypair, [0u8; 16], &password, 1024, "Test".to_owned(), "{}".to_owned()); let res = directory.insert(account.unwrap()); // then @@ -335,11 +378,11 @@ mod test { let mut dir = env::temp_dir(); dir.push("ethstore_should_handle_duplicate_filenames"); let keypair = Random.generate().unwrap(); - let password = "hello world"; + let password = "hello world".into(); let directory = RootDiskDirectory::create(dir.clone()).unwrap(); // when - let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned()).unwrap(); + let account = SafeAccount::create(&keypair, [0u8; 16], &password, 1024, "Test".to_owned(), "{}".to_owned()).unwrap(); let filename = "test".to_string(); let dedup = true; @@ -368,14 +411,14 @@ mod test { dir.push("should_create_new_vault"); let directory = RootDiskDirectory::create(dir.clone()).unwrap(); let vault_name = "vault"; - let password = "password"; + let password = "password".into(); // then assert!(directory.as_vault_provider().is_some()); // and when let before_root_items_count = fs::read_dir(&dir).unwrap().count(); - let vault = directory.as_vault_provider().unwrap().create(vault_name, VaultKey::new(password, 1024)); + let vault = directory.as_vault_provider().unwrap().create(vault_name, VaultKey::new(&password, 1024)); // then assert!(vault.is_ok()); @@ -383,7 +426,7 @@ mod test { assert!(after_root_items_count > before_root_items_count); // and when - let vault = directory.as_vault_provider().unwrap().open(vault_name, VaultKey::new(password, 1024)); + let vault = directory.as_vault_provider().unwrap().open(vault_name, VaultKey::new(&password, 1024)); // then assert!(vault.is_ok()); @@ -400,8 +443,8 @@ mod test { let temp_path = TempDir::new("").unwrap(); let directory = RootDiskDirectory::create(&temp_path).unwrap(); let vault_provider = directory.as_vault_provider().unwrap(); - vault_provider.create("vault1", VaultKey::new("password1", 1)).unwrap(); - vault_provider.create("vault2", VaultKey::new("password2", 1)).unwrap(); + vault_provider.create("vault1", VaultKey::new(&"password1".into(), 1)).unwrap(); + vault_provider.create("vault2", VaultKey::new(&"password2".into(), 1)).unwrap(); // then let vaults = vault_provider.list_vaults().unwrap(); @@ -422,8 +465,8 @@ mod test { ); let keypair = Random.generate().unwrap(); - let password = "test pass"; - let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned()); + let password = "test pass".into(); + let account = SafeAccount::create(&keypair, [0u8; 16], &password, 1024, "Test".to_owned(), "{}".to_owned()); directory.insert(account.unwrap()).expect("Account should be inserted ok"); let new_hash = directory.files_hash().expect("New files hash should be calculated ok"); diff --git a/ethstore/src/accounts_dir/memory.rs b/ethstore/src/accounts_dir/memory.rs index 5cfdba0e5c70d4576c2af46ff562f7114b6b7382..71ddfa536e3f086e31f2149a7230e6cd56b7f724 100644 --- a/ethstore/src/accounts_dir/memory.rs +++ b/ethstore/src/accounts_dir/memory.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -72,4 +72,3 @@ impl KeyDirectory for MemoryDirectory { Ok(val) } } - diff --git a/ethstore/src/accounts_dir/mod.rs b/ethstore/src/accounts_dir/mod.rs index ec72d05da32895864a92536df06150549153015e..1191a73d2debd5f1fd72087a7b20d2e3f50c7327 100644 --- a/ethstore/src/accounts_dir/mod.rs +++ b/ethstore/src/accounts_dir/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -16,6 +16,7 @@ //! Accounts Directory +use ethkey::Password; use std::path::{PathBuf}; use {SafeAccount, Error}; @@ -35,10 +36,10 @@ pub enum SetKeyError { } /// Vault key -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq)] pub struct VaultKey { /// Vault password - pub password: String, + pub password: Password, /// Number of iterations to produce a derived key from password pub iterations: u32, } @@ -95,9 +96,9 @@ pub use self::vault::VaultDiskDirectory; impl VaultKey { /// Create new vault key - pub fn new(password: &str, iterations: u32) -> Self { + pub fn new(password: &Password, iterations: u32) -> Self { VaultKey { - password: password.to_owned(), + password: password.clone(), iterations: iterations, } } diff --git a/ethstore/src/accounts_dir/vault.rs b/ethstore/src/accounts_dir/vault.rs index 2705262666106a19be52beda02289c64ea73dc62..249a9c6dc3f9f0393709a91f61dcab182b23bd2d 100644 --- a/ethstore/src/accounts_dir/vault.rs +++ b/ethstore/src/accounts_dir/vault.rs @@ -1,4 +1,4 @@ -// Copyright 2015, 2016, 2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -21,7 +21,7 @@ use {json, SafeAccount, Error}; use crypto::Keccak256; use super::super::account::Crypto; use super::{KeyDirectory, VaultKeyDirectory, VaultKey, SetKeyError}; -use super::disk::{DiskDirectory, KeyFileManager}; +use super::disk::{self, DiskDirectory, KeyFileManager}; /// Name of vault metadata file pub const VAULT_FILE_NAME: &'static str = "vault.json"; @@ -234,17 +234,16 @@ fn check_vault_name(name: &str) -> bool { /// Vault can be empty, but still must be pluggable => we store vault password in separate file fn create_vault_file

(vault_dir_path: P, key: &VaultKey, meta: &str) -> Result<(), Error> where P: AsRef { - let password_hash = key.password.keccak256(); + let password_hash = key.password.as_bytes().keccak256(); let crypto = Crypto::with_plain(&password_hash, &key.password, key.iterations)?; - let mut vault_file_path: PathBuf = vault_dir_path.as_ref().into(); - vault_file_path.push(VAULT_FILE_NAME); - let mut temp_vault_file_path: PathBuf = vault_dir_path.as_ref().into(); - temp_vault_file_path.push(VAULT_TEMP_FILE_NAME); + let vault_file_path = vault_dir_path.as_ref().join(VAULT_FILE_NAME); + let temp_vault_file_name = disk::find_unique_filename_using_random_suffix(vault_dir_path.as_ref(), &VAULT_TEMP_FILE_NAME)?; + let temp_vault_file_path = vault_dir_path.as_ref().join(&temp_vault_file_name); // this method is used to rewrite existing vault file // => write to temporary file first, then rename temporary file to vault file - let mut vault_file = fs::File::create(&temp_vault_file_path)?; + let mut vault_file = disk::create_new_file_with_permissions_to_owner(&temp_vault_file_path)?; let vault_file_contents = json::VaultFile { crypto: crypto.into(), meta: Some(meta.to_owned()), @@ -268,7 +267,7 @@ fn read_vault_file

(vault_dir_path: P, key: Option<&VaultKey>) -> Result Result { + fn insert_account(&self, vault: SecretVaultRef, secret: Secret, password: &Password) -> Result { self.store.insert_account(vault, secret, password) } - fn insert_derived(&self, vault: SecretVaultRef, account_ref: &StoreAccountRef, password: &str, derivation: Derivation) + fn insert_derived(&self, vault: SecretVaultRef, account_ref: &StoreAccountRef, password: &Password, derivation: Derivation) -> Result { self.store.insert_derived(vault, account_ref, password, derivation) } - fn generate_derived(&self, account_ref: &StoreAccountRef, password: &str, derivation: Derivation) -> Result { + fn generate_derived(&self, account_ref: &StoreAccountRef, password: &Password, derivation: Derivation) -> Result { self.store.generate_derived(account_ref, password, derivation) } @@ -86,42 +86,42 @@ impl SimpleSecretStore for EthStore { self.store.accounts() } - fn change_password(&self, account: &StoreAccountRef, old_password: &str, new_password: &str) -> Result<(), Error> { + fn change_password(&self, account: &StoreAccountRef, old_password: &Password, new_password: &Password) -> Result<(), Error> { self.store.change_password(account, old_password, new_password) } - fn export_account(&self, account: &StoreAccountRef, password: &str) -> Result { + fn export_account(&self, account: &StoreAccountRef, password: &Password) -> Result { self.store.export_account(account, password) } - fn remove_account(&self, account: &StoreAccountRef, password: &str) -> Result<(), Error> { + fn remove_account(&self, account: &StoreAccountRef, password: &Password) -> Result<(), Error> { self.store.remove_account(account, password) } - fn sign(&self, account: &StoreAccountRef, password: &str, message: &Message) -> Result { + fn sign(&self, account: &StoreAccountRef, password: &Password, message: &Message) -> Result { self.get(account)?.sign(password, message) } - fn sign_derived(&self, account_ref: &StoreAccountRef, password: &str, derivation: Derivation, message: &Message) + fn sign_derived(&self, account_ref: &StoreAccountRef, password: &Password, derivation: Derivation, message: &Message) -> Result { self.store.sign_derived(account_ref, password, derivation, message) } - fn agree(&self, account: &StoreAccountRef, password: &str, other: &Public) -> Result { + fn agree(&self, account: &StoreAccountRef, password: &Password, other: &Public) -> Result { self.store.agree(account, password, other) } - fn decrypt(&self, account: &StoreAccountRef, password: &str, shared_mac: &[u8], message: &[u8]) -> Result, Error> { + fn decrypt(&self, account: &StoreAccountRef, password: &Password, shared_mac: &[u8], message: &[u8]) -> Result, Error> { let account = self.get(account)?; account.decrypt(password, shared_mac, message) } - fn create_vault(&self, name: &str, password: &str) -> Result<(), Error> { + fn create_vault(&self, name: &str, password: &Password) -> Result<(), Error> { self.store.create_vault(name, password) } - fn open_vault(&self, name: &str, password: &str) -> Result<(), Error> { + fn open_vault(&self, name: &str, password: &Password) -> Result<(), Error> { self.store.open_vault(name, password) } @@ -137,7 +137,7 @@ impl SimpleSecretStore for EthStore { self.store.list_opened_vaults() } - fn change_vault_password(&self, name: &str, new_password: &str) -> Result<(), Error> { + fn change_vault_password(&self, name: &str, new_password: &Password) -> Result<(), Error> { self.store.change_vault_password(name, new_password) } @@ -155,18 +155,18 @@ impl SimpleSecretStore for EthStore { } impl SecretStore for EthStore { - fn raw_secret(&self, account: &StoreAccountRef, password: &str) -> Result { + fn raw_secret(&self, account: &StoreAccountRef, password: &Password) -> Result { Ok(OpaqueSecret(self.get(account)?.crypto.secret(password)?)) } - fn import_presale(&self, vault: SecretVaultRef, json: &[u8], password: &str) -> Result { + fn import_presale(&self, vault: SecretVaultRef, json: &[u8], password: &Password) -> Result { let json_wallet = json::PresaleWallet::load(json).map_err(|_| Error::InvalidKeyFile("Invalid JSON format".to_owned()))?; let wallet = PresaleWallet::from(json_wallet); let keypair = wallet.decrypt(password).map_err(|_| Error::InvalidPassword)?; self.insert_account(vault, keypair.secret().clone(), password) } - fn import_wallet(&self, vault: SecretVaultRef, json: &[u8], password: &str, gen_id: bool) -> Result { + fn import_wallet(&self, vault: SecretVaultRef, json: &[u8], password: &Password, gen_id: bool) -> Result { let json_keyfile = json::KeyFile::load(json).map_err(|_| Error::InvalidKeyFile("Invalid JSON format".to_owned()))?; let mut safe_account = SafeAccount::from_file(json_keyfile, None); @@ -179,19 +179,19 @@ impl SecretStore for EthStore { self.store.import(vault, safe_account) } - fn test_password(&self, account: &StoreAccountRef, password: &str) -> Result { + fn test_password(&self, account: &StoreAccountRef, password: &Password) -> Result { let account = self.get(account)?; Ok(account.check_password(password)) } - fn copy_account(&self, new_store: &SimpleSecretStore, new_vault: SecretVaultRef, account: &StoreAccountRef, password: &str, new_password: &str) -> Result<(), Error> { + fn copy_account(&self, new_store: &SimpleSecretStore, new_vault: SecretVaultRef, account: &StoreAccountRef, password: &Password, new_password: &Password) -> Result<(), Error> { let account = self.get(account)?; let secret = account.crypto.secret(password)?; new_store.insert_account(new_vault, secret, new_password)?; Ok(()) } - fn public(&self, account: &StoreAccountRef, password: &str) -> Result { + fn public(&self, account: &StoreAccountRef, password: &Password) -> Result { let account = self.get(account)?; account.public(password) } @@ -365,7 +365,7 @@ impl EthMultiStore { } } - fn get_matching(&self, account: &StoreAccountRef, password: &str) -> Result, Error> { + fn get_matching(&self, account: &StoreAccountRef, password: &Password) -> Result, Error> { let accounts = self.get_accounts(account)?; Ok(accounts.into_iter() @@ -455,14 +455,14 @@ impl EthMultiStore { } impl SimpleSecretStore for EthMultiStore { - fn insert_account(&self, vault: SecretVaultRef, secret: Secret, password: &str) -> Result { + fn insert_account(&self, vault: SecretVaultRef, secret: Secret, password: &Password) -> Result { let keypair = KeyPair::from_secret(secret).map_err(|_| Error::CreationFailed)?; let id: [u8; 16] = Random::random(); let account = SafeAccount::create(&keypair, id, password, self.iterations, "".to_owned(), "{}".to_owned())?; self.import(vault, account) } - fn insert_derived(&self, vault: SecretVaultRef, account_ref: &StoreAccountRef, password: &str, derivation: Derivation) + fn insert_derived(&self, vault: SecretVaultRef, account_ref: &StoreAccountRef, password: &Password, derivation: Derivation) -> Result { let accounts = self.get_matching(account_ref, password)?; @@ -473,7 +473,7 @@ impl SimpleSecretStore for EthMultiStore { Err(Error::InvalidPassword) } - fn generate_derived(&self, account_ref: &StoreAccountRef, password: &str, derivation: Derivation) + fn generate_derived(&self, account_ref: &StoreAccountRef, password: &Password, derivation: Derivation) -> Result { let accounts = self.get_matching(&account_ref, password)?; @@ -484,7 +484,7 @@ impl SimpleSecretStore for EthMultiStore { Err(Error::InvalidPassword) } - fn sign_derived(&self, account_ref: &StoreAccountRef, password: &str, derivation: Derivation, message: &Message) + fn sign_derived(&self, account_ref: &StoreAccountRef, password: &Password, derivation: Derivation, message: &Message) -> Result { let accounts = self.get_matching(&account_ref, password)?; @@ -518,7 +518,7 @@ impl SimpleSecretStore for EthMultiStore { Ok(self.cache.read().keys().cloned().collect()) } - fn remove_account(&self, account_ref: &StoreAccountRef, password: &str) -> Result<(), Error> { + fn remove_account(&self, account_ref: &StoreAccountRef, password: &Password) -> Result<(), Error> { let accounts = self.get_matching(account_ref, password)?; for account in accounts { @@ -528,7 +528,7 @@ impl SimpleSecretStore for EthMultiStore { Err(Error::InvalidPassword) } - fn change_password(&self, account_ref: &StoreAccountRef, old_password: &str, new_password: &str) -> Result<(), Error> { + fn change_password(&self, account_ref: &StoreAccountRef, old_password: &Password, new_password: &Password) -> Result<(), Error> { let accounts = self.get_matching(account_ref, old_password)?; if accounts.is_empty() { @@ -544,11 +544,11 @@ impl SimpleSecretStore for EthMultiStore { Ok(()) } - fn export_account(&self, account_ref: &StoreAccountRef, password: &str) -> Result { + fn export_account(&self, account_ref: &StoreAccountRef, password: &Password) -> Result { self.get_matching(account_ref, password)?.into_iter().nth(0).map(Into::into).ok_or(Error::InvalidPassword) } - fn sign(&self, account: &StoreAccountRef, password: &str, message: &Message) -> Result { + fn sign(&self, account: &StoreAccountRef, password: &Password, message: &Message) -> Result { let accounts = self.get_matching(account, password)?; match accounts.first() { Some(ref account) => account.sign(password, message), @@ -556,7 +556,7 @@ impl SimpleSecretStore for EthMultiStore { } } - fn decrypt(&self, account: &StoreAccountRef, password: &str, shared_mac: &[u8], message: &[u8]) -> Result, Error> { + fn decrypt(&self, account: &StoreAccountRef, password: &Password, shared_mac: &[u8], message: &[u8]) -> Result, Error> { let accounts = self.get_matching(account, password)?; match accounts.first() { Some(ref account) => account.decrypt(password, shared_mac, message), @@ -564,7 +564,7 @@ impl SimpleSecretStore for EthMultiStore { } } - fn agree(&self, account: &StoreAccountRef, password: &str, other: &Public) -> Result { + fn agree(&self, account: &StoreAccountRef, password: &Password, other: &Public) -> Result { let accounts = self.get_matching(account, password)?; match accounts.first() { Some(ref account) => account.agree(password, other), @@ -572,7 +572,7 @@ impl SimpleSecretStore for EthMultiStore { } } - fn create_vault(&self, name: &str, password: &str) -> Result<(), Error> { + fn create_vault(&self, name: &str, password: &Password) -> Result<(), Error> { let is_vault_created = { // lock border let mut vaults = self.vaults.lock(); if !vaults.contains_key(&name.to_owned()) { @@ -592,7 +592,7 @@ impl SimpleSecretStore for EthMultiStore { Ok(()) } - fn open_vault(&self, name: &str, password: &str) -> Result<(), Error> { + fn open_vault(&self, name: &str, password: &Password) -> Result<(), Error> { let is_vault_opened = { // lock border let mut vaults = self.vaults.lock(); if !vaults.contains_key(&name.to_owned()) { @@ -629,7 +629,7 @@ impl SimpleSecretStore for EthMultiStore { Ok(self.vaults.lock().keys().cloned().collect()) } - fn change_vault_password(&self, name: &str, new_password: &str) -> Result<(), Error> { + fn change_vault_password(&self, name: &str, new_password: &Password) -> Result<(), Error> { let old_key = self.vaults.lock().get(name).map(|v| v.key()).ok_or(Error::VaultNotFound)?; let vault_provider = self.dir.as_vault_provider().ok_or(Error::VaultsAreNotSupported)?; let vault = vault_provider.open(name, old_key)?; @@ -732,7 +732,8 @@ mod tests { let keypair = keypair(); // when - let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), "test").unwrap(); + let passwd = "test".into(); + let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), &passwd).unwrap(); // then assert_eq!(address, StoreAccountRef::root(keypair.address())); @@ -745,7 +746,8 @@ mod tests { // given let store = store(); let keypair = keypair(); - let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), "test").unwrap(); + let passwd = "test".into(); + let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), &passwd).unwrap(); assert_eq!(&store.meta(&address).unwrap(), "{}"); assert_eq!(&store.name(&address).unwrap(), ""); @@ -763,11 +765,12 @@ mod tests { fn should_remove_account() { // given let store = store(); + let passwd = "test".into(); let keypair = keypair(); - let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), "test").unwrap(); + let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), &passwd).unwrap(); // when - store.remove_account(&address, "test").unwrap(); + store.remove_account(&address, &passwd).unwrap(); // then assert_eq!(store.accounts().unwrap().len(), 0, "Should remove account."); @@ -777,12 +780,13 @@ mod tests { fn should_return_true_if_password_is_correct() { // given let store = store(); + let passwd = "test".into(); let keypair = keypair(); - let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), "test").unwrap(); + let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), &passwd).unwrap(); // when - let res1 = store.test_password(&address, "x").unwrap(); - let res2 = store.test_password(&address, "test").unwrap(); + let res1 = store.test_password(&address, &"x".into()).unwrap(); + let res2 = store.test_password(&address, &passwd).unwrap(); assert!(!res1, "First password should be invalid."); assert!(res2, "Second password should be correct."); @@ -792,16 +796,18 @@ mod tests { fn multistore_should_be_able_to_have_the_same_account_twice() { // given let store = multi_store(); + let passwd1 = "test".into(); + let passwd2 = "xyz".into(); let keypair = keypair(); - let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), "test").unwrap(); - let address2 = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), "xyz").unwrap(); + let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), &passwd1).unwrap(); + let address2 = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), &passwd2).unwrap(); assert_eq!(address, address2); // when - assert!(store.remove_account(&address, "test").is_ok(), "First password should work."); + assert!(store.remove_account(&address, &passwd1).is_ok(), "First password should work."); assert_eq!(store.accounts().unwrap().len(), 1); - assert!(store.remove_account(&address, "xyz").is_ok(), "Second password should work too."); + assert!(store.remove_account(&address, &passwd2).is_ok(), "Second password should work too."); assert_eq!(store.accounts().unwrap().len(), 0); } @@ -809,17 +815,19 @@ mod tests { fn should_copy_account() { // given let store = store(); + let passwd1 = "test".into(); + let passwd2 = "xzy".into(); let multi_store = multi_store(); let keypair = keypair(); - let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), "test").unwrap(); + let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), &passwd1).unwrap(); assert_eq!(multi_store.accounts().unwrap().len(), 0); // when - store.copy_account(&multi_store, SecretVaultRef::Root, &address, "test", "xyz").unwrap(); + store.copy_account(&multi_store, SecretVaultRef::Root, &address, &passwd1, &passwd2).unwrap(); // then - assert!(store.test_password(&address, "test").unwrap(), "First password should work for store."); - assert!(multi_store.sign(&address, "xyz", &Default::default()).is_ok(), "Second password should work for second store."); + assert!(store.test_password(&address, &passwd1).unwrap(), "First password should work for store."); + assert!(multi_store.sign(&address, &passwd2, &Default::default()).is_ok(), "Second password should work for second store."); assert_eq!(multi_store.accounts().unwrap().len(), 1); } @@ -828,23 +836,23 @@ mod tests { // given let mut dir = RootDiskDirectoryGuard::new(); let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap(); - let name1 = "vault1"; let password1 = "password1"; - let name2 = "vault2"; let password2 = "password2"; + let name1 = "vault1"; let password1 = "password1".into(); + let name2 = "vault2"; let password2 = "password2".into(); let keypair1 = keypair(); let keypair2 = keypair(); - let keypair3 = keypair(); let password3 = "password3"; + let keypair3 = keypair(); let password3 = "password3".into(); // when - store.create_vault(name1, password1).unwrap(); - store.create_vault(name2, password2).unwrap(); + store.create_vault(name1, &password1).unwrap(); + store.create_vault(name2, &password2).unwrap(); // then [can create vaults] ^^^ // and when - store.insert_account(SecretVaultRef::Vault(name1.to_owned()), keypair1.secret().clone(), password1).unwrap(); - store.insert_account(SecretVaultRef::Vault(name2.to_owned()), keypair2.secret().clone(), password2).unwrap(); - store.insert_account(SecretVaultRef::Root, keypair3.secret().clone(), password3).unwrap(); - store.insert_account(SecretVaultRef::Vault("vault3".to_owned()), keypair1.secret().clone(), password3).unwrap_err(); + store.insert_account(SecretVaultRef::Vault(name1.to_owned()), keypair1.secret().clone(), &password1).unwrap(); + store.insert_account(SecretVaultRef::Vault(name2.to_owned()), keypair2.secret().clone(), &password2).unwrap(); + store.insert_account(SecretVaultRef::Root, keypair3.secret().clone(), &password3).unwrap(); + store.insert_account(SecretVaultRef::Vault("vault3".to_owned()), keypair1.secret().clone(), &password3).unwrap_err(); let accounts = store.accounts().unwrap(); // then [can create accounts in vaults] @@ -864,10 +872,10 @@ mod tests { assert!(accounts.iter().any(|a| a.vault == SecretVaultRef::Root)); // and when - store.open_vault(name1, password2).unwrap_err(); - store.open_vault(name2, password1).unwrap_err(); - store.open_vault(name1, password1).unwrap(); - store.open_vault(name2, password2).unwrap(); + store.open_vault(name1, &password2).unwrap_err(); + store.open_vault(name2, &password1).unwrap_err(); + store.open_vault(name1, &password1).unwrap(); + store.open_vault(name2, &password2).unwrap(); let accounts = store.accounts().unwrap(); // then [can check vaults on open + can reopen vaults + accounts from vaults appear] @@ -882,19 +890,19 @@ mod tests { // given let mut dir = RootDiskDirectoryGuard::new(); let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap(); - let name1 = "vault1"; let password1 = "password1"; - let name2 = "vault2"; let password2 = "password2"; - let password3 = "password3"; + let name1 = "vault1"; let password1 = "password1".into(); + let name2 = "vault2"; let password2 = "password2".into(); + let password3 = "password3".into(); let keypair1 = keypair(); let keypair2 = keypair(); let keypair3 = keypair(); // when - store.create_vault(name1, password1).unwrap(); - store.create_vault(name2, password2).unwrap(); - let account1 = store.insert_account(SecretVaultRef::Vault(name1.to_owned()), keypair1.secret().clone(), password1).unwrap(); - let account2 = store.insert_account(SecretVaultRef::Vault(name1.to_owned()), keypair2.secret().clone(), password1).unwrap(); - let account3 = store.insert_account(SecretVaultRef::Root, keypair3.secret().clone(), password3).unwrap(); + store.create_vault(name1, &password1).unwrap(); + store.create_vault(name2, &password2).unwrap(); + let account1 = store.insert_account(SecretVaultRef::Vault(name1.to_owned()), keypair1.secret().clone(), &password1).unwrap(); + let account2 = store.insert_account(SecretVaultRef::Vault(name1.to_owned()), keypair2.secret().clone(), &password1).unwrap(); + let account3 = store.insert_account(SecretVaultRef::Root, keypair3.secret().clone(), &password3).unwrap(); // then let account1 = store.change_account_vault(SecretVaultRef::Root, account1.clone()).unwrap(); @@ -917,11 +925,11 @@ mod tests { // given let mut dir = RootDiskDirectoryGuard::new(); let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap(); - let password1 = "password1"; + let password1 = "password1".into(); let keypair1 = keypair(); // when - let account1 = store.insert_account(SecretVaultRef::Root, keypair1.secret().clone(), password1).unwrap(); + let account1 = store.insert_account(SecretVaultRef::Root, keypair1.secret().clone(), &password1).unwrap(); store.change_account_vault(SecretVaultRef::Root, account1).unwrap(); // then @@ -934,16 +942,16 @@ mod tests { // given let mut dir = RootDiskDirectoryGuard::new(); let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap(); - let name1 = "vault1"; let password1 = "password1"; + let name1 = "vault1"; let password1 = "password1".into(); let keypair1 = keypair(); // when - store.create_vault(name1, password1).unwrap(); - let account1 = store.insert_account(SecretVaultRef::Vault(name1.to_owned()), keypair1.secret().clone(), password1).unwrap(); + store.create_vault(name1, &password1).unwrap(); + let account1 = store.insert_account(SecretVaultRef::Vault(name1.to_owned()), keypair1.secret().clone(), &password1).unwrap(); assert_eq!(store.accounts().unwrap().len(), 1); // then - store.remove_account(&account1, password1).unwrap(); + store.remove_account(&account1, &password1).unwrap(); assert_eq!(store.accounts().unwrap().len(), 0); } @@ -952,17 +960,17 @@ mod tests { // given let mut dir = RootDiskDirectoryGuard::new(); let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap(); - let name1 = "vault1"; let password1 = "password1"; - let password2 = "password2"; + let name1 = "vault1"; let password1 = "password1".into(); + let password2 = "password2".into(); let keypair1 = keypair(); // when - store.create_vault(name1, password1).unwrap(); - let account1 = store.insert_account(SecretVaultRef::Vault(name1.to_owned()), keypair1.secret().clone(), password1).unwrap(); + store.create_vault(name1, &password1).unwrap(); + let account1 = store.insert_account(SecretVaultRef::Vault(name1.to_owned()), keypair1.secret().clone(), &password1).unwrap(); assert_eq!(store.accounts().unwrap().len(), 1); // then - store.remove_account(&account1, password2).unwrap_err(); + store.remove_account(&account1, &password2).unwrap_err(); assert_eq!(store.accounts().unwrap().len(), 1); } @@ -971,24 +979,24 @@ mod tests { // given let mut dir = RootDiskDirectoryGuard::new(); let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap(); - let name = "vault"; let password = "password"; + let name = "vault"; let password = "password".into(); let keypair = keypair(); // when - store.create_vault(name, password).unwrap(); - store.insert_account(SecretVaultRef::Vault(name.to_owned()), keypair.secret().clone(), password).unwrap(); + store.create_vault(name, &password).unwrap(); + store.insert_account(SecretVaultRef::Vault(name.to_owned()), keypair.secret().clone(), &password).unwrap(); // then assert_eq!(store.accounts().unwrap().len(), 1); - let new_password = "new_password"; - store.change_vault_password(name, new_password).unwrap(); + let new_password = "new_password".into(); + store.change_vault_password(name, &new_password).unwrap(); assert_eq!(store.accounts().unwrap().len(), 1); // and when store.close_vault(name).unwrap(); // then - store.open_vault(name, new_password).unwrap(); + store.open_vault(name, &new_password).unwrap(); assert_eq!(store.accounts().unwrap().len(), 1); } @@ -997,18 +1005,18 @@ mod tests { // given let mut dir = RootDiskDirectoryGuard::new(); let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap(); - let name = "vault"; let password = "password"; - let secret_password = "sec_password"; + let name = "vault"; let password = "password".into(); + let secret_password = "sec_password".into(); let keypair = keypair(); // when - store.create_vault(name, password).unwrap(); - let account_ref = store.insert_account(SecretVaultRef::Vault(name.to_owned()), keypair.secret().clone(), secret_password).unwrap(); + store.create_vault(name, &password).unwrap(); + let account_ref = store.insert_account(SecretVaultRef::Vault(name.to_owned()), keypair.secret().clone(), &secret_password).unwrap(); // then assert_eq!(store.accounts().unwrap().len(), 1); - let new_secret_password = "new_sec_password"; - store.change_password(&account_ref, secret_password, new_secret_password).unwrap(); + let new_secret_password = "new_sec_password".into(); + store.change_password(&account_ref, &secret_password, &new_secret_password).unwrap(); assert_eq!(store.accounts().unwrap().len(), 1); } @@ -1017,14 +1025,14 @@ mod tests { // given let mut dir = RootDiskDirectoryGuard::new(); let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap(); - let name1 = "vault1"; let password1 = "password1"; - let name2 = "vault2"; let password2 = "password2"; - let name3 = "vault3"; let password3 = "password3"; + let name1 = "vault1"; let password1 = "password1".into(); + let name2 = "vault2"; let password2 = "password2".into(); + let name3 = "vault3"; let password3 = "password3".into(); // when - store.create_vault(name1, password1).unwrap(); - store.create_vault(name2, password2).unwrap(); - store.create_vault(name3, password3).unwrap(); + store.create_vault(name1, &password1).unwrap(); + store.create_vault(name2, &password2).unwrap(); + store.create_vault(name3, &password3).unwrap(); store.close_vault(name2).unwrap(); // then @@ -1039,10 +1047,10 @@ mod tests { // given let mut dir = RootDiskDirectoryGuard::new(); let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap(); - let name1 = "vault1"; let password1 = "password1"; + let name1 = "vault1"; let password1 = "password1".into(); // when - store.create_vault(name1, password1).unwrap(); + store.create_vault(name1, &password1).unwrap(); // then assert_eq!(store.get_vault_meta(name1).unwrap(), "{}".to_owned()); @@ -1051,7 +1059,7 @@ mod tests { // and when store.close_vault(name1).unwrap(); - store.open_vault(name1, password1).unwrap(); + store.open_vault(name1, &password1).unwrap(); // then assert_eq!(store.get_vault_meta(name1).unwrap(), "Hello, world!!!".to_owned()); @@ -1069,13 +1077,13 @@ mod tests { // given we have one account in the store let store = store(); let keypair = keypair(); - let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), "test").unwrap(); + let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), &"test".into()).unwrap(); // when we deriving from that account let derived = store.insert_derived( SecretVaultRef::Root, &address, - "test", + &"test".into(), Derivation::HardHash(H256::from(0)), ).unwrap(); @@ -1084,7 +1092,7 @@ mod tests { assert_eq!(accounts.len(), 2); // and we can sign with the derived contract - assert!(store.sign(&derived, "test", &Default::default()).is_ok(), "Second password should work for second store."); + assert!(store.sign(&derived, &"test".into(), &Default::default()).is_ok(), "Second password should work for second store."); } #[test] @@ -1092,13 +1100,13 @@ mod tests { // given let mut dir = RootDiskDirectoryGuard::new(); let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap(); - let name = "vault"; let password = "password1"; - let new_password = "password2"; + let name = "vault"; let password = "password1".into(); + let new_password = "password2".into(); // when - store.create_vault(name, password).unwrap(); + store.create_vault(name, &password).unwrap(); store.set_vault_meta(name, "OldMeta").unwrap(); - store.change_vault_password(name, new_password).unwrap(); + store.change_vault_password(name, &new_password).unwrap(); // then assert_eq!(store.get_vault_meta(name).unwrap(), "OldMeta".to_owned()); @@ -1109,10 +1117,10 @@ mod tests { // given let store = store(); let keypair = keypair(); - let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), "test").unwrap(); + let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), &"test".into()).unwrap(); // when - let exported = store.export_account(&address, "test"); + let exported = store.export_account(&address, &"test".into()); // then assert!(exported.is_ok(), "Should export single account: {:?}", exported); diff --git a/ethstore/src/import.rs b/ethstore/src/import.rs index 2aaef51f504153d9808790f48e0b281137bc6b12..876119fd50a7d5aa78d9dc8819f3fb84a2a1208b 100644 --- a/ethstore/src/import.rs +++ b/ethstore/src/import.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/json/bytes.rs b/ethstore/src/json/bytes.rs index de2c6456361979caf04132581f3f19d79acf731a..b5aae19222a78114b10575f0c085ad76d6e37e1d 100644 --- a/ethstore/src/json/bytes.rs +++ b/ethstore/src/json/bytes.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -72,4 +72,3 @@ impl From for Vec { b.0 } } - diff --git a/ethstore/src/json/cipher.rs b/ethstore/src/json/cipher.rs index 33f4ec5721155482c30530e210b63297be66e3bb..6fffdde9e2ac2d7b0427d43a6e4149b607940e3c 100644 --- a/ethstore/src/json/cipher.rs +++ b/ethstore/src/json/cipher.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/json/crypto.rs b/ethstore/src/json/crypto.rs index 03f72e576e600c4b2a4bb250a4b0f3c8a683a326..0a926cc83fe399ad677ffe7f934936680b1ffc03 100644 --- a/ethstore/src/json/crypto.rs +++ b/ethstore/src/json/crypto.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/json/error.rs b/ethstore/src/json/error.rs index 8a5029642dbf941fae5d9a5959cae48137f87203..81b805bfe2c82765f7853b7abeeed8a95cb7b516 100644 --- a/ethstore/src/json/error.rs +++ b/ethstore/src/json/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/json/hash.rs b/ethstore/src/json/hash.rs index 13564c95d100e7211d750f9ea271b27b5dfcd049..c2ad547734f963cde00685a338029a282fa90e38 100644 --- a/ethstore/src/json/hash.rs +++ b/ethstore/src/json/hash.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/json/id.rs b/ethstore/src/json/id.rs index aa90a4d7a495ed0ba9631740b0ecac6ff35bbf37..7df5c8f7e5afb37fa1c90acd9f1c85d0cfb808ff 100644 --- a/ethstore/src/json/id.rs +++ b/ethstore/src/json/id.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/json/kdf.rs b/ethstore/src/json/kdf.rs index 6498323be243086368ada92a37c7f0cf5a6fae2a..f8df3c2285fedcb5d67bacb3b81b267603a7417e 100644 --- a/ethstore/src/json/kdf.rs +++ b/ethstore/src/json/kdf.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/json/key_file.rs b/ethstore/src/json/key_file.rs index 60b34681e25f3fe4076b747e089c5e6c9c5fe3a1..2c3cf3fdd5d6953dfa57f735e1dc39c3eaa5d6b0 100644 --- a/ethstore/src/json/key_file.rs +++ b/ethstore/src/json/key_file.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -102,7 +102,6 @@ impl<'a> Deserialize<'a> for KeyFile { } } - fn none_if_empty<'a, T>(v: Option) -> Option where T: DeserializeOwned { diff --git a/ethstore/src/json/mod.rs b/ethstore/src/json/mod.rs index 865b75dea66b35dec89615ec32a6ca84fb286901..e39bff651e447921bf0ced33cdfb738ecf0eca4e 100644 --- a/ethstore/src/json/mod.rs +++ b/ethstore/src/json/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/json/presale.rs b/ethstore/src/json/presale.rs index d1cffcb6ad948119de23e1692ec697b4e39e1e17..478f328a43af4b24901bf131e146e00d4dc64fdb 100644 --- a/ethstore/src/json/presale.rs +++ b/ethstore/src/json/presale.rs @@ -1,3 +1,19 @@ +// 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 . + use std::io::Read; use serde_json; use super::{H160, Bytes}; diff --git a/ethstore/src/json/vault_file.rs b/ethstore/src/json/vault_file.rs index d11e71451fb7ae533ad6ec2e4b337f68473d5bee..e9620442272147808815eafac83df1ace93fdfa2 100644 --- a/ethstore/src/json/vault_file.rs +++ b/ethstore/src/json/vault_file.rs @@ -1,4 +1,4 @@ -// Copyright 2015, 2016, 2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/json/vault_key_file.rs b/ethstore/src/json/vault_key_file.rs index 76c59b3808d22ca6c43e9bf74e15316cdf984fb0..818487d52b69e92a6546cc745004a985fdfca195 100644 --- a/ethstore/src/json/vault_key_file.rs +++ b/ethstore/src/json/vault_key_file.rs @@ -1,4 +1,4 @@ -// Copyright 2015, 2016, 2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/json/version.rs b/ethstore/src/json/version.rs index 0eb8450f1499fd022b1ce1df1f0b47c1bc2dd041..683d4a520fa8e440d759cd1d247bb0e075527f46 100644 --- a/ethstore/src/json/version.rs +++ b/ethstore/src/json/version.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -56,4 +56,3 @@ impl<'a> Visitor<'a> for VersionVisitor { } } } - diff --git a/ethstore/src/lib.rs b/ethstore/src/lib.rs index b558126ada603e73a446dc592e85abf614ffea80..ad58bd0e9842ced3f3e564c6d2418677d497c209 100644 --- a/ethstore/src/lib.rs +++ b/ethstore/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -31,7 +31,7 @@ extern crate time; extern crate tiny_keccak; extern crate tempdir; -extern crate ethcore_crypto as crypto; +extern crate parity_crypto as crypto; extern crate ethereum_types; extern crate ethkey as _ethkey; extern crate parity_wordlist; diff --git a/ethstore/src/presale.rs b/ethstore/src/presale.rs index 555d00c1e986a56d82c7cfc57cd0e45722196e5d..7ffde7973c6c082627d32a1350644c2ac6ff41f8 100644 --- a/ethstore/src/presale.rs +++ b/ethstore/src/presale.rs @@ -1,7 +1,23 @@ +// 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 . + use std::fs; use std::path::Path; use json; -use ethkey::{Address, Secret, KeyPair}; +use ethkey::{Address, Secret, KeyPair, Password}; use crypto::{Keccak256, pbkdf2}; use {crypto, Error}; @@ -38,7 +54,7 @@ impl PresaleWallet { } /// Decrypt the wallet. - pub fn decrypt(&self, password: &str) -> Result { + pub fn decrypt(&self, password: &Password) -> Result { let mut derived_key = [0u8; 32]; let salt = pbkdf2::Salt(password.as_bytes()); let sec = pbkdf2::Secret(password.as_bytes()); @@ -77,7 +93,7 @@ mod tests { let wallet = json::PresaleWallet::load(json.as_bytes()).unwrap(); let wallet = PresaleWallet::from(wallet); - assert!(wallet.decrypt("123").is_ok()); - assert!(wallet.decrypt("124").is_err()); + assert!(wallet.decrypt(&"123".into()).is_ok()); + assert!(wallet.decrypt(&"124".into()).is_err()); } } diff --git a/ethstore/src/random.rs b/ethstore/src/random.rs index af754471e1d5bdd85d356e4c4015f03c43ffe0e7..b8b7a71fa8b4e5637af80124def236be6607528a 100644 --- a/ethstore/src/random.rs +++ b/ethstore/src/random.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -43,4 +43,3 @@ pub fn random_string(length: usize) -> String { let mut rng = OsRng::new().expect("Not able to operate without random source."); rng.gen_ascii_chars().take(length).collect() } - diff --git a/ethstore/src/secret_store.rs b/ethstore/src/secret_store.rs index ebac2f992292cb0e79dfe6b1932aded84f752578..b8417bc61c4191cea17d69309fecfe6b25c7dad9 100644 --- a/ethstore/src/secret_store.rs +++ b/ethstore/src/secret_store.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ use std::hash::{Hash, Hasher}; use std::path::PathBuf; use std::cmp::Ordering; -use ethkey::{Address, Message, Signature, Secret, Public}; +use ethkey::{Address, Message, Signature, Secret, Password, Public}; use Error; use json::{Uuid, OpaqueKeyFile}; use ethereum_types::H256; @@ -56,25 +56,25 @@ impl ::std::borrow::Borrow

for StoreAccountRef { /// Simple Secret Store API pub trait SimpleSecretStore: Send + Sync { /// Inserts new accounts to the store (or vault) with given password. - fn insert_account(&self, vault: SecretVaultRef, secret: Secret, password: &str) -> Result; + fn insert_account(&self, vault: SecretVaultRef, secret: Secret, password: &Password) -> Result; /// Inserts new derived account to the store (or vault) with given password. - fn insert_derived(&self, vault: SecretVaultRef, account_ref: &StoreAccountRef, password: &str, derivation: Derivation) -> Result; + fn insert_derived(&self, vault: SecretVaultRef, account_ref: &StoreAccountRef, password: &Password, derivation: Derivation) -> Result; /// Changes accounts password. - fn change_password(&self, account: &StoreAccountRef, old_password: &str, new_password: &str) -> Result<(), Error>; + fn change_password(&self, account: &StoreAccountRef, old_password: &Password, new_password: &Password) -> Result<(), Error>; /// Exports key details for account. - fn export_account(&self, account: &StoreAccountRef, password: &str) -> Result; + fn export_account(&self, account: &StoreAccountRef, password: &Password) -> Result; /// Entirely removes account from the store and underlying storage. - fn remove_account(&self, account: &StoreAccountRef, password: &str) -> Result<(), Error>; + fn remove_account(&self, account: &StoreAccountRef, password: &Password) -> Result<(), Error>; /// Generates new derived account. - fn generate_derived(&self, account_ref: &StoreAccountRef, password: &str, derivation: Derivation) -> Result; + fn generate_derived(&self, account_ref: &StoreAccountRef, password: &Password, derivation: Derivation) -> Result; /// Sign a message with given account. - fn sign(&self, account: &StoreAccountRef, password: &str, message: &Message) -> Result; + fn sign(&self, account: &StoreAccountRef, password: &Password, message: &Message) -> Result; /// Sign a message with derived account. - fn sign_derived(&self, account_ref: &StoreAccountRef, password: &str, derivation: Derivation, message: &Message) -> Result; + fn sign_derived(&self, account_ref: &StoreAccountRef, password: &Password, derivation: Derivation, message: &Message) -> Result; /// Decrypt a messages with given account. - fn decrypt(&self, account: &StoreAccountRef, password: &str, shared_mac: &[u8], message: &[u8]) -> Result, Error>; + fn decrypt(&self, account: &StoreAccountRef, password: &Password, shared_mac: &[u8], message: &[u8]) -> Result, Error>; /// Agree on shared key. - fn agree(&self, account: &StoreAccountRef, password: &str, other: &Public) -> Result; + fn agree(&self, account: &StoreAccountRef, password: &Password, other: &Public) -> Result; /// Returns all accounts in this secret store. fn accounts(&self) -> Result, Error>; @@ -83,9 +83,9 @@ pub trait SimpleSecretStore: Send + Sync { fn account_ref(&self, address: &Address) -> Result; /// Create new vault with given password - fn create_vault(&self, name: &str, password: &str) -> Result<(), Error>; + fn create_vault(&self, name: &str, password: &Password) -> Result<(), Error>; /// Open vault with given password - fn open_vault(&self, name: &str, password: &str) -> Result<(), Error>; + fn open_vault(&self, name: &str, password: &Password) -> Result<(), Error>; /// Close vault fn close_vault(&self, name: &str) -> Result<(), Error>; /// List all vaults @@ -93,7 +93,7 @@ pub trait SimpleSecretStore: Send + Sync { /// List all currently opened vaults fn list_opened_vaults(&self) -> Result, Error>; /// Change vault password - fn change_vault_password(&self, name: &str, new_password: &str) -> Result<(), Error>; + fn change_vault_password(&self, name: &str, new_password: &Password) -> Result<(), Error>; /// Cnage account' vault fn change_account_vault(&self, vault: SecretVaultRef, account: StoreAccountRef) -> Result; /// Get vault metadata string. @@ -106,7 +106,7 @@ pub trait SimpleSecretStore: Send + Sync { pub trait SecretStore: SimpleSecretStore { /// Returns a raw opaque Secret that can be later used to sign a message. - fn raw_secret(&self, account: &StoreAccountRef, password: &str) -> Result; + fn raw_secret(&self, account: &StoreAccountRef, password: &Password) -> Result; /// Signs a message with raw secret. fn sign_with_secret(&self, secret: &OpaqueSecret, message: &Message) -> Result { @@ -114,16 +114,16 @@ pub trait SecretStore: SimpleSecretStore { } /// Imports presale wallet - fn import_presale(&self, vault: SecretVaultRef, json: &[u8], password: &str) -> Result; + fn import_presale(&self, vault: SecretVaultRef, json: &[u8], password: &Password) -> Result; /// Imports existing JSON wallet - fn import_wallet(&self, vault: SecretVaultRef, json: &[u8], password: &str, gen_id: bool) -> Result; + fn import_wallet(&self, vault: SecretVaultRef, json: &[u8], password: &Password, gen_id: bool) -> Result; /// Copies account between stores and vaults. - fn copy_account(&self, new_store: &SimpleSecretStore, new_vault: SecretVaultRef, account: &StoreAccountRef, password: &str, new_password: &str) -> Result<(), Error>; + fn copy_account(&self, new_store: &SimpleSecretStore, new_vault: SecretVaultRef, account: &StoreAccountRef, password: &Password, new_password: &Password) -> Result<(), Error>; /// Checks if password matches given account. - fn test_password(&self, account: &StoreAccountRef, password: &str) -> Result; + fn test_password(&self, account: &StoreAccountRef, password: &Password) -> Result; /// Returns a public key for given account. - fn public(&self, account: &StoreAccountRef, password: &str) -> Result; + fn public(&self, account: &StoreAccountRef, password: &Password) -> Result; /// Returns uuid of an account. fn uuid(&self, account: &StoreAccountRef) -> Result; diff --git a/ethstore/tests/api.rs b/ethstore/tests/api.rs index fb24ff3367d73661ffad6718f15c7784dd2b060e..11ab4f8eddaa76de12ee38f3b11257acc250702e 100644 --- a/ethstore/tests/api.rs +++ b/ethstore/tests/api.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -46,9 +46,9 @@ fn secret_store_create_account() { let dir = TransientDir::create().unwrap(); let store = EthStore::open(Box::new(dir)).unwrap(); assert_eq!(store.accounts().unwrap().len(), 0); - assert!(store.insert_account(SecretVaultRef::Root, random_secret(), "").is_ok()); + assert!(store.insert_account(SecretVaultRef::Root, random_secret(), &"".into()).is_ok()); assert_eq!(store.accounts().unwrap().len(), 1); - assert!(store.insert_account(SecretVaultRef::Root, random_secret(), "").is_ok()); + assert!(store.insert_account(SecretVaultRef::Root, random_secret(), &"".into()).is_ok()); assert_eq!(store.accounts().unwrap().len(), 2); } @@ -56,36 +56,36 @@ fn secret_store_create_account() { fn secret_store_sign() { let dir = TransientDir::create().unwrap(); let store = EthStore::open(Box::new(dir)).unwrap(); - assert!(store.insert_account(SecretVaultRef::Root, random_secret(), "").is_ok()); + assert!(store.insert_account(SecretVaultRef::Root, random_secret(), &"".into()).is_ok()); let accounts = store.accounts().unwrap(); assert_eq!(accounts.len(), 1); - assert!(store.sign(&accounts[0], "", &Default::default()).is_ok()); - assert!(store.sign(&accounts[0], "1", &Default::default()).is_err()); + assert!(store.sign(&accounts[0], &"".into(), &Default::default()).is_ok()); + assert!(store.sign(&accounts[0], &"1".into(), &Default::default()).is_err()); } #[test] fn secret_store_change_password() { let dir = TransientDir::create().unwrap(); let store = EthStore::open(Box::new(dir)).unwrap(); - assert!(store.insert_account(SecretVaultRef::Root, random_secret(), "").is_ok()); + assert!(store.insert_account(SecretVaultRef::Root, random_secret(), &"".into()).is_ok()); let accounts = store.accounts().unwrap(); assert_eq!(accounts.len(), 1); - assert!(store.sign(&accounts[0], "", &Default::default()).is_ok()); - assert!(store.change_password(&accounts[0], "", "1").is_ok()); - assert!(store.sign(&accounts[0], "", &Default::default()).is_err()); - assert!(store.sign(&accounts[0], "1", &Default::default()).is_ok()); + assert!(store.sign(&accounts[0], &"".into(), &Default::default()).is_ok()); + assert!(store.change_password(&accounts[0], &"".into(), &"1".into()).is_ok()); + assert!(store.sign(&accounts[0], &"".into(), &Default::default()).is_err()); + assert!(store.sign(&accounts[0], &"1".into(), &Default::default()).is_ok()); } #[test] fn secret_store_remove_account() { let dir = TransientDir::create().unwrap(); let store = EthStore::open(Box::new(dir)).unwrap(); - assert!(store.insert_account(SecretVaultRef::Root, random_secret(), "").is_ok()); + assert!(store.insert_account(SecretVaultRef::Root, random_secret(), &"".into()).is_ok()); let accounts = store.accounts().unwrap(); assert_eq!(accounts.len(), 1); - assert!(store.remove_account(&accounts[0], "").is_ok()); + assert!(store.remove_account(&accounts[0], &"".into()).is_ok()); assert_eq!(store.accounts().unwrap().len(), 0); - assert!(store.remove_account(&accounts[0], "").is_err()); + assert!(store.remove_account(&accounts[0], &"".into()).is_err()); } fn test_path() -> &'static str { @@ -146,8 +146,8 @@ fn test_decrypting_files_with_short_ciphertext() { let message = Default::default(); - let s1 = store.sign(&accounts[0], "foo", &message).unwrap(); - let s2 = store.sign(&accounts[1], "foo", &message).unwrap(); + let s1 = store.sign(&accounts[0], &"foo".into(), &message).unwrap(); + let s2 = store.sign(&accounts[1], &"foo".into(), &message).unwrap(); assert!(verify_address(&accounts[0].address, &s1, &message).unwrap()); assert!(verify_address(&kp1.address(), &s1, &message).unwrap()); assert!(verify_address(&kp2.address(), &s2, &message).unwrap()); diff --git a/ethstore/tests/util/mod.rs b/ethstore/tests/util/mod.rs index c0002d4e13d090159ec0fb84e60dafee65214b7e..1a7abc93effbfb1422019b568d6958866ed53bdf 100644 --- a/ethstore/tests/util/mod.rs +++ b/ethstore/tests/util/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/tests/util/transient_dir.rs b/ethstore/tests/util/transient_dir.rs index dcc65ec6985365f918fc4aa4d2c5ecb8261cb4f9..c0969418d8c7155a4f93ef2cf1c31b0603dfc9fe 100644 --- a/ethstore/tests/util/transient_dir.rs +++ b/ethstore/tests/util/transient_dir.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/evmbin/Cargo.toml b/evmbin/Cargo.toml index c3ef5847d43b22c7206a12cdf24d473876d55789..43264f042ffa3461c50bce51880ac77b5cfbe514 100644 --- a/evmbin/Cargo.toml +++ b/evmbin/Cargo.toml @@ -10,9 +10,9 @@ path = "./src/main.rs" [dependencies] docopt = "0.8" -ethcore = { path = "../ethcore" } +ethcore = { path = "../ethcore", features = ["test-helpers", "json-tests"] } ethjson = { path = "../json" } -ethcore-bytes = { path = "../util/bytes" } +parity-bytes = { git = "https://github.com/paritytech/parity-common" } ethcore-transaction = { path = "../ethcore/transaction" } ethereum-types = "0.3" evm = { path = "../ethcore/evm" } diff --git a/evmbin/benches/mod.rs b/evmbin/benches/mod.rs index 6b6746e747b25354c3cbcf2cd6b35b3b4a697c2a..8fdd5e9cfe13e5e76f1c893460f3c66844f7b337 100644 --- a/evmbin/benches/mod.rs +++ b/evmbin/benches/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -83,4 +83,3 @@ fn rng(gas: U256, b: &mut Bencher) { run_vm(params) }); } - diff --git a/evmbin/src/display/json.rs b/evmbin/src/display/json.rs index 00ca91b94fef22d9bf7de73257877f4386921969..613be1d2243181c4606935ec7e3e4e9f7c78529f 100644 --- a/evmbin/src/display/json.rs +++ b/evmbin/src/display/json.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -121,13 +121,13 @@ impl trace::VMTracer for Informant { } fn trace_executed(&mut self, gas_used: U256, stack_push: &[U256], mem_diff: Option<(usize, &[u8])>, store_diff: Option<(U256, U256)>) { - let info = ::evm::INSTRUCTIONS[self.instruction as usize]; + let info = ::evm::Instruction::from_u8(self.instruction).map(|i| i.info()); let trace = format!( "{{\"pc\":{pc},\"op\":{op},\"opName\":\"{name}\",\"gas\":\"0x{gas:x}\",\"gasCost\":\"0x{gas_cost:x}\",\"memory\":{memory},\"stack\":{stack},\"storage\":{storage},\"depth\":{depth}}}", pc = self.pc, op = self.instruction, - name = info.name, + name = info.map(|i| i.name).unwrap_or(""), gas = gas_used.saturating_add(self.gas_cost), gas_cost = self.gas_cost, memory = self.memory(), @@ -141,7 +141,8 @@ impl trace::VMTracer for Informant { self.gas_used = gas_used; let len = self.stack.len(); - self.stack.truncate(if len > info.args { len - info.args } else { 0 }); + let info_args = info.map(|i| i.args).unwrap_or(0); + self.stack.truncate(if len > info_args { len - info_args } else { 0 }); self.stack.extend_from_slice(stack_push); // TODO [ToDr] Align memory? @@ -156,7 +157,6 @@ impl trace::VMTracer for Informant { self.storage.insert(pos.into(), val.into()); } - if !self.subtraces.is_empty() { self.traces.extend(mem::replace(&mut self.subtraces, vec![])); } diff --git a/evmbin/src/display/mod.rs b/evmbin/src/display/mod.rs index b9390058b6022230c745786f9cdcb32caa0dac50..a8eb20d9e6c86986189b08534e09eff166c2fa2e 100644 --- a/evmbin/src/display/mod.rs +++ b/evmbin/src/display/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/evmbin/src/display/simple.rs b/evmbin/src/display/simple.rs index 30bb8ffcf7a286c8a6f557f3fd04efbb95764b26..8ff863cfa944f7d19dc56be40783a325b47ebfd6 100644 --- a/evmbin/src/display/simple.rs +++ b/evmbin/src/display/simple.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/evmbin/src/display/std_json.rs b/evmbin/src/display/std_json.rs index 3d8f52dbd1f744068788aaca69d76b6e4313b0e7..b3533ea2c4e791a6d57f1f4d2592bf621bd109fd 100644 --- a/evmbin/src/display/std_json.rs +++ b/evmbin/src/display/std_json.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -118,7 +118,7 @@ impl trace::VMTracer for Informant { type Output = (); fn trace_next_instruction(&mut self, pc: usize, instruction: u8, current_gas: U256) -> bool { - let info = ::evm::INSTRUCTIONS[instruction as usize]; + let info = ::evm::Instruction::from_u8(instruction).map(|i| i.info()); self.instruction = instruction; let storage = self.storage(); let stack = self.stack(); @@ -128,7 +128,7 @@ impl trace::VMTracer for Informant { "{{\"pc\":{pc},\"op\":{op},\"opName\":\"{name}\",\"gas\":\"0x{gas:x}\",\"stack\":{stack},\"storage\":{storage},\"depth\":{depth}}}", pc = pc, op = instruction, - name = info.name, + name = info.map(|i| i.name).unwrap_or(""), gas = current_gas, stack = stack, storage = storage, @@ -142,10 +142,11 @@ impl trace::VMTracer for Informant { } fn trace_executed(&mut self, _gas_used: U256, stack_push: &[U256], _mem_diff: Option<(usize, &[u8])>, store_diff: Option<(U256, U256)>) { - let info = ::evm::INSTRUCTIONS[self.instruction as usize]; + let info = ::evm::Instruction::from_u8(self.instruction).map(|i| i.info()); let len = self.stack.len(); - self.stack.truncate(if len > info.args { len - info.args } else { 0 }); + let info_args = info.map(|i| i.args).unwrap_or(0); + self.stack.truncate(if len > info_args { len - info_args } else { 0 }); self.stack.extend_from_slice(stack_push); if let Some((pos, val)) = store_diff { diff --git a/evmbin/src/info.rs b/evmbin/src/info.rs index 1be81d9132f9d1d80af1f42cdf46dfe77aea7cc2..ce824fe17d3d56a94feb19c1b28b416f171bc858 100644 --- a/evmbin/src/info.rs +++ b/evmbin/src/info.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -105,7 +105,7 @@ pub fn run_transaction( informant.set_gas(env_info.gas_limit); - let result = run(spec, env_info.gas_limit, pre_state, |mut client| { + let result = run(&spec, env_info.gas_limit, pre_state, |mut client| { let result = client.transact(env_info, transaction, trace::NoopTracer, informant); match result { TransactResult::Ok { state_root, .. } if state_root != post_root => { diff --git a/evmbin/src/main.rs b/evmbin/src/main.rs index bddb40ecd235c38cabe0572385381d8e69a5a964..144c99fb3bd52606b9853ce4149fb9d086475786 100644 --- a/evmbin/src/main.rs +++ b/evmbin/src/main.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -26,7 +26,7 @@ extern crate serde; extern crate serde_derive; extern crate docopt; extern crate ethcore_transaction as transaction; -extern crate ethcore_bytes as bytes; +extern crate parity_bytes as bytes; extern crate ethereum_types; extern crate vm; extern crate evm; @@ -46,7 +46,7 @@ use docopt::Docopt; use rustc_hex::FromHex; use ethereum_types::{U256, Address}; use bytes::Bytes; -use ethcore::spec; +use ethcore::{spec, json_tests}; use vm::{ActionParams, CallType}; mod info; @@ -61,9 +61,16 @@ EVM implementation for Parity. Usage: parity-evm state-test [--json --std-json --only NAME --chain CHAIN] parity-evm stats [options] + parity-evm stats-jsontests-vm parity-evm [options] parity-evm [-h | --help] +Commands: + state-test Run a state test from a json file. + stats Execute EVM runtime code and return the statistics. + stats-jsontests-vm Execute standard jsontests format VMTests and return + timing statistcis in tsv format. + Transaction options: --code CODE Contract code as hex (without 0x). --to ADDRESS Recipient address (without 0x). @@ -83,14 +90,15 @@ General options: -h, --help Display this message and exit. "#; - fn main() { - panic_hook::set(); + panic_hook::set_abort(); let args: Args = Docopt::new(USAGE).and_then(|d| d.deserialize()).unwrap_or_else(|e| e.exit()); if args.cmd_state_test { run_state_test(args) + } else if args.cmd_stats_jsontests_vm { + run_stats_jsontests_vm(args) } else if args.flag_json { run_call(args, display::json::Informant::default()) } else if args.flag_std_json { @@ -100,6 +108,40 @@ fn main() { } } +fn run_stats_jsontests_vm(args: Args) { + use json_tests::HookType; + use std::collections::HashMap; + use std::time::{Instant, Duration}; + + let file = args.arg_file.expect("FILE (or PATH) is required"); + + let mut timings: HashMap)> = HashMap::new(); + + { + let mut record_time = |name: &str, typ: HookType| { + match typ { + HookType::OnStart => { + timings.insert(name.to_string(), (Instant::now(), None)); + }, + HookType::OnStop => { + timings.entry(name.to_string()).and_modify(|v| { + v.1 = Some(v.0.elapsed()); + }); + }, + } + }; + if !file.is_file() { + json_tests::run_executive_test_path(&file, &[], &mut record_time); + } else { + json_tests::run_executive_test_file(&file, &mut record_time); + } + } + + for (name, v) in timings { + println!("{}\t{}", name, display::as_micros(&v.1.expect("All hooks are called with OnStop; qed"))); + } +} + fn run_state_test(args: Args) { use ethjson::state::test::Test; @@ -180,6 +222,7 @@ fn run_call(args: Args, informant: T) { struct Args { cmd_stats: bool, cmd_state_test: bool, + cmd_stats_jsontests_vm: bool, arg_file: Option, flag_only: Option, flag_from: Option, diff --git a/hash-fetch/Cargo.toml b/hash-fetch/Cargo.toml index d4f46a121e89327057da587e6c8f67b214788071..c4eb7acd3af59189b4b6942283c1d52bc9d642eb 100644 --- a/hash-fetch/Cargo.toml +++ b/hash-fetch/Cargo.toml @@ -15,10 +15,10 @@ mime_guess = "2.0.0-alpha.2" rand = "0.4" rustc-hex = "1.0" fetch = { path = "../util/fetch" } -ethcore-bytes = { path = "../util/bytes" } +parity-bytes = { git = "https://github.com/paritytech/parity-common" } ethereum-types = "0.3" parity-reactor = { path = "../util/reactor" } -keccak-hash = { path = "../util/hash" } +keccak-hash = { git = "https://github.com/paritytech/parity-common" } registrar = { path = "../registrar" } ethabi = "5.1" @@ -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/hash-fetch/src/client.rs b/hash-fetch/src/client.rs index 1c7d417758f6df3bdf42864e42e567701b3cd14b..ebdab681a4fe83502b3839cb0d3407fe026e443f 100644 --- a/hash-fetch/src/client.rs +++ b/hash-fetch/src/client.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/hash-fetch/src/lib.rs b/hash-fetch/src/lib.rs index 18176be5005576772fc0034432d7404445848f3e..9ed8c59fd6a412cd3ff400927afbe55ba995f345 100644 --- a/hash-fetch/src/lib.rs +++ b/hash-fetch/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -22,7 +22,7 @@ extern crate log; extern crate ethabi; -extern crate ethcore_bytes as bytes; +extern crate parity_bytes as bytes; extern crate ethereum_types; extern crate futures; extern crate futures_cpupool; diff --git a/hash-fetch/src/urlhint.rs b/hash-fetch/src/urlhint.rs index d05dd40a22f225633ed574ea12c1c2886e06d806..d80566ea6202f8077b9bdedb7e316225b3e69810 100644 --- a/hash-fetch/src/urlhint.rs +++ b/hash-fetch/src/urlhint.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -265,8 +265,6 @@ pub mod tests { let calls = registrar.calls.clone(); let urlhint = URLHintContract::new(Arc::new(registrar)); - - // when let res = urlhint.resolve("test".as_bytes().into()).wait().unwrap(); let calls = calls.lock(); @@ -353,7 +351,6 @@ pub mod tests { let url4 = "https://parity.io/parity.png#content-type=image/jpeg"; let url5 = "https://parity.io/parity.png"; - assert_eq!(guess_mime_type(url1), None); assert_eq!(guess_mime_type(url2), Some(mime::IMAGE_PNG)); assert_eq!(guess_mime_type(url3), Some(mime::IMAGE_PNG)); diff --git a/hw/Cargo.toml b/hw/Cargo.toml index 9a717e4bd3c33a489a51b98f0128dbe43c173aa5..b7d90648eac4a790e89b4d3edaa9a271d096aae9 100644 --- a/hw/Cargo.toml +++ b/hw/Cargo.toml @@ -8,13 +8,14 @@ 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" } trezor-sys = { git = "https://github.com/paritytech/trezor-sys" } ethkey = { path = "../ethkey" } ethereum-types = "0.3" +semver = "0.9" [dev-dependencies] rustc-hex = "1.0" diff --git a/hw/src/ledger.rs b/hw/src/ledger.rs index e31d49f1304d04ae00e6a3be62763d1072092d73..f9e20654839ac93d915ad7d928f0e3f26391b2f2 100644 --- a/hw/src/ledger.rs +++ b/hw/src/ledger.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -15,35 +15,38 @@ // along with Parity. If not, see . //! Ledger hardware wallet module. Supports Ledger Blue and Nano S. -/// See https://github.com/LedgerHQ/blue-app-eth/blob/master/doc/ethapp.asc for protocol details. +//! See for protocol details. use std::cmp::min; -use std::fmt; use std::str::FromStr; -use std::sync::atomic; -use std::sync::atomic::AtomicBool; -use std::sync::{Arc, Weak}; +use std::sync::{atomic, atomic::AtomicBool, Arc, Weak}; use std::time::{Duration, Instant}; -use std::thread; +use std::{fmt, thread}; use ethereum_types::{H256, Address}; use ethkey::Signature; use hidapi; use libusb; use parking_lot::{Mutex, RwLock}; +use semver::Version as FirmwareVersion; +use super::{WalletInfo, KeyPath, Device, DeviceDirection, Wallet, USB_DEVICE_CLASS_DEVICE, POLLING_DURATION}; -use super::{WalletInfo, KeyPath, Device, Wallet, USB_DEVICE_CLASS_DEVICE}; +const APDU_TAG: u8 = 0x05; +const APDU_CLA: u8 = 0xe0; +const APDU_PAYLOAD_HEADER_LEN: usize = 7; + +const ETH_DERIVATION_PATH_BE: [u8; 17] = [4, 0x80, 0, 0, 44, 0x80, 0, 0, 60, 0x80, 0, 0, 0, 0, 0, 0, 0]; // 44'/60'/0'/0 +const ETC_DERIVATION_PATH_BE: [u8; 21] = [5, 0x80, 0, 0, 44, 0x80, 0, 0, 60, 0x80, 0x02, 0x73, 0xd0, 0x80, 0, 0, 0, 0, 0, 0, 0]; // 44'/60'/160720'/0'/0 /// Ledger vendor ID const LEDGER_VID: u16 = 0x2c97; /// Ledger product IDs: [Nano S and Blue] const LEDGER_PIDS: [u16; 2] = [0x0000, 0x0001]; +const LEDGER_TRANSPORT_HEADER_LEN: usize = 5; -const ETH_DERIVATION_PATH_BE: [u8; 17] = [4, 0x80, 0, 0, 44, 0x80, 0, 0, 60, 0x80, 0, 0, 0, 0, 0, 0, 0]; // 44'/60'/0'/0 -const ETC_DERIVATION_PATH_BE: [u8; 21] = [5, 0x80, 0, 0, 44, 0x80, 0, 0, 60, 0x80, 0x02, 0x73, 0xd0, 0x80, 0, 0, 0, 0, 0, 0, 0]; // 44'/60'/160720'/0'/0 +const MAX_CHUNK_SIZE: usize = 255; -const APDU_TAG: u8 = 0x05; -const APDU_CLA: u8 = 0xe0; +const HID_PACKET_SIZE: usize = 64 + HID_PREFIX_ZERO; #[cfg(windows)] const HID_PREFIX_ZERO: usize = 1; #[cfg(not(windows))] const HID_PREFIX_ZERO: usize = 0; @@ -52,6 +55,7 @@ mod commands { pub const GET_APP_CONFIGURATION: u8 = 0x06; pub const GET_ETH_PUBLIC_ADDRESS: u8 = 0x02; pub const SIGN_ETH_TRANSACTION: u8 = 0x04; + pub const SIGN_ETH_PERSONAL_MESSAGE: u8 = 0x08; } /// Hardware wallet error. @@ -70,7 +74,11 @@ pub enum Error { /// Invalid device InvalidDevice, /// Impossible error - ImpossibleError, + Impossible, + /// No device arrived + NoDeviceArrived, + /// No device left + NoDeviceLeft, } impl fmt::Display for Error { @@ -82,25 +90,27 @@ impl fmt::Display for Error { Error::KeyNotFound => write!(f, "Key not found"), Error::UserCancel => write!(f, "Operation has been cancelled"), Error::InvalidDevice => write!(f, "Unsupported product was entered"), - Error::ImpossibleError => write!(f, "Placeholder error"), + Error::Impossible => write!(f, "Placeholder error"), + Error::NoDeviceArrived => write!(f, "No device arrived"), + Error::NoDeviceLeft=> write!(f, "No device left"), } } } impl From for Error { - fn from(err: hidapi::HidError) -> Error { + fn from(err: hidapi::HidError) -> Self { Error::Usb(err) } } impl From for Error { - fn from(err: libusb::Error) -> Error { + fn from(err: libusb::Error) -> Self { Error::LibUsb(err) } } /// Ledger device manager. -pub struct Manager { +pub (crate) struct Manager { usb: Arc>, devices: RwLock>, key_path: RwLock, @@ -108,8 +118,8 @@ pub struct Manager { impl Manager { /// Create a new instance. - pub fn new(hidapi: Arc>, exiting: Arc) -> Result, libusb::Error> { - let manager = Arc::new(Manager { + pub fn new(hidapi: Arc>, exiting: Arc) -> Result, libusb::Error> { + let manager = Arc::new(Self { usb: hidapi, devices: RwLock::new(Vec::new()), key_path: RwLock::new(KeyPath::Ethereum), @@ -129,12 +139,12 @@ impl Manager { // Ledger event handler thread thread::Builder::new() .spawn(move || { - if let Err(e) = m.update_devices() { + if let Err(e) = m.update_devices(DeviceDirection::Arrived) { debug!(target: "hw", "Ledger couldn't connect at startup, error: {}", e); } loop { usb_context.handle_events(Some(Duration::from_millis(500))) - .unwrap_or_else(|e| debug!(target: "hw", "Ledger event handler error: {}", e)); + .unwrap_or_else(|e| debug!(target: "hw", "Ledger event handler error: {}", e)); if exiting.load(atomic::Ordering::Acquire) { break; } @@ -145,47 +155,80 @@ impl Manager { Ok(manager) } - fn send_apdu(handle: &hidapi::HidDevice, command: u8, p1: u8, p2: u8, data: &[u8]) -> Result, Error> { - const HID_PACKET_SIZE: usize = 64 + HID_PREFIX_ZERO; + // Transport Protocol: + // * Communication Channel Id (2 bytes big endian ) + // * Command Tag (1 byte) + // * Packet Sequence ID (2 bytes big endian) + // * Payload (Optional) + // + // Payload + // * APDU Total Length (2 bytes big endian) + // * APDU_CLA (1 byte) + // * APDU_INS (1 byte) + // * APDU_P1 (1 byte) + // * APDU_P2 (1 byte) + // * APDU_LENGTH (1 byte) + // * APDU_Payload (Variable) + // + fn write(handle: &hidapi::HidDevice, command: u8, p1: u8, p2: u8, data: &[u8]) -> Result<(), Error> { + let data_len = data.len(); let mut offset = 0; - let mut chunk_index = 0; - loop { - let mut hid_chunk: [u8; HID_PACKET_SIZE] = [0; HID_PACKET_SIZE]; - let mut chunk_size = if chunk_index == 0 { 12 } else { 5 }; - let size = min(64 - chunk_size, data.len() - offset); + let mut sequence_number = 0; + let mut hid_chunk = [0_u8; HID_PACKET_SIZE]; + + while sequence_number == 0 || offset < data_len { + let header = if sequence_number == 0 { LEDGER_TRANSPORT_HEADER_LEN + APDU_PAYLOAD_HEADER_LEN } else { LEDGER_TRANSPORT_HEADER_LEN }; + let size = min(64 - header, data_len - offset); { let chunk = &mut hid_chunk[HID_PREFIX_ZERO..]; - &mut chunk[0..5].copy_from_slice(&[0x01, 0x01, APDU_TAG, (chunk_index >> 8) as u8, (chunk_index & 0xff) as u8 ]); + chunk[0..5].copy_from_slice(&[0x01, 0x01, APDU_TAG, (sequence_number >> 8) as u8, (sequence_number & 0xff) as u8 ]); - if chunk_index == 0 { + if sequence_number == 0 { let data_len = data.len() + 5; - &mut chunk[5..12].copy_from_slice(&[ (data_len >> 8) as u8, (data_len & 0xff) as u8, APDU_CLA, command, p1, p2, data.len() as u8 ]); + chunk[5..12].copy_from_slice(&[(data_len >> 8) as u8, (data_len & 0xff) as u8, APDU_CLA, command, p1, p2, data.len() as u8]); } - &mut chunk[chunk_size..chunk_size + size].copy_from_slice(&data[offset..offset + size]); - offset += size; - chunk_size += size; + chunk[header..header + size].copy_from_slice(&data[offset..offset + size]); } - trace!("writing {:?}", &hid_chunk[..]); + trace!(target: "hw", "Ledger write {:?}", &hid_chunk[..]); let n = handle.write(&hid_chunk[..])?; - if n < chunk_size { + if n < size + header { return Err(Error::Protocol("Write data size mismatch")); } - if offset == data.len() { - break; + offset += size; + sequence_number += 1; + if sequence_number >= 0xffff { + return Err(Error::Protocol("Maximum sequence number reached")); } - chunk_index += 1; } - - // Read response - chunk_index = 0; + Ok(()) + } + + // Transport Protocol: + // * Communication Channel Id (2 bytes big endian ) + // * Command Tag (1 byte) + // * Packet Sequence ID (2 bytes big endian) + // * Payload (Optional) + // + // Payload + // * APDU Total Length (2 bytes big endian) + // * APDU_CLA (1 byte) + // * APDU_INS (1 byte) + // * APDU_P1 (1 byte) + // * APDU_P2 (1 byte) + // * APDU_LENGTH (1 byte) + // * APDU_Payload (Variable) + // + fn read(handle: &hidapi::HidDevice) -> Result, Error> { let mut message_size = 0; let mut message = Vec::new(); - loop { + + // terminate the loop if `sequence_number` reaches its max_value and report error + for chunk_index in 0..=0xffff { let mut chunk: [u8; HID_PACKET_SIZE] = [0; HID_PACKET_SIZE]; let chunk_size = handle.read(&mut chunk)?; - trace!("read {:?}", &chunk[..]); - if chunk_size < 5 || chunk[0] != 0x01 || chunk[1] != 0x01 || chunk[2] != APDU_TAG { + trace!(target: "hw", "Ledger read {:?}", &chunk[..]); + if chunk_size < LEDGER_TRANSPORT_HEADER_LEN || chunk[0] != 0x01 || chunk[1] != 0x01 || chunk[2] != APDU_TAG { return Err(Error::Protocol("Unexpected chunk header")); } let seq = (chunk[3] as usize) << 8 | (chunk[4] as usize); @@ -207,7 +250,6 @@ impl Manager { if message.len() == message_size { break; } - chunk_index += 1; } if message.len() < 2 { return Err(Error::Protocol("No status word")); @@ -221,8 +263,8 @@ impl Manager { 0x6a82 => Err(Error::Protocol("File not found")), 0x6a85 => Err(Error::UserCancel), 0x6b00 => Err(Error::Protocol("Incorrect parameters")), - 0x6d00 => Err(Error::Protocol("Not implemented. Make sure Ethereum app is running.")), - 0x6faa => Err(Error::Protocol("You Ledger need to be unplugged")), + 0x6d00 => Err(Error::Protocol("Not implemented. Make sure the Ledger Ethereum Wallet app is running.")), + 0x6faa => Err(Error::Protocol("Your Ledger need to be unplugged")), 0x6f00...0x6fff => Err(Error::Protocol("Internal error")), 0x9000 => Ok(()), _ => Err(Error::Protocol("Unknown error")), @@ -233,6 +275,11 @@ impl Manager { Ok(message) } + fn send_apdu(handle: &hidapi::HidDevice, command: u8, p1: u8, p2: u8, data: &[u8]) -> Result, Error> { + Self::write(&handle, command, p1, p2, data)?; + Self::read(&handle) + } + fn is_valid_ledger(device: &libusb::Device) -> Result<(), Error> { let desc = device.device_descriptor()?; let vendor_id = desc.vendor_id(); @@ -244,54 +291,64 @@ impl Manager { Err(Error::InvalidDevice) } } -} -// Try to connect to the device using polling in at most the time specified by the `timeout` -fn try_connect_polling(ledger: Arc, timeout: Duration) -> bool { - let start_time = Instant::now(); - while start_time.elapsed() <= timeout { - if let Ok(_) = ledger.update_devices() { - return true + fn get_firmware_version(handle: &hidapi::HidDevice) -> Result { + let ver = Self::send_apdu(&handle, commands::GET_APP_CONFIGURATION, 0, 0, &[])?; + if ver.len() != 4 { + return Err(Error::Protocol("Version packet size mismatch")); } + Ok(FirmwareVersion::new(ver[1].into(), ver[2].into(), ver[3].into())) } - false -} -impl <'a>Wallet<'a> for Manager { - type Error = Error; - type Transaction = &'a [u8]; - - fn sign_transaction(&self, address: &Address, transaction: Self::Transaction) -> Result { + fn get_derivation_path(&self) -> &[u8] { + match *self.key_path.read() { + KeyPath::Ethereum => Ð_DERIVATION_PATH_BE, + KeyPath::EthereumClassic => &ETC_DERIVATION_PATH_BE, + } + } + + fn signer_helper(&self, address: &Address, data: &[u8], command: u8) -> Result { let usb = self.usb.lock(); let devices = self.devices.read(); let device = devices.iter().find(|d| &d.info.address == address).ok_or(Error::KeyNotFound)?; let handle = self.open_path(|| usb.open_path(&device.path))?; - let eth_path = Ð_DERIVATION_PATH_BE[..]; - let etc_path = &ETC_DERIVATION_PATH_BE[..]; - let derivation_path = match *self.key_path.read() { - KeyPath::Ethereum => eth_path, - KeyPath::EthereumClassic => etc_path, - }; - const MAX_CHUNK_SIZE: usize = 255; - let mut chunk: [u8; MAX_CHUNK_SIZE] = [0; MAX_CHUNK_SIZE]; - &mut chunk[0..derivation_path.len()].copy_from_slice(derivation_path); - let mut dest_offset = derivation_path.len(); - let mut data_pos = 0; - let mut result; - loop { - let p1 = if data_pos == 0 { 0x00 } else { 0x80 }; - let dest_left = MAX_CHUNK_SIZE - dest_offset; - let chunk_data_size = min(dest_left, transaction.len() - data_pos); - &mut chunk[dest_offset..][0..chunk_data_size].copy_from_slice(&transaction[data_pos..][0..chunk_data_size]); - result = Self::send_apdu(&handle, commands::SIGN_ETH_TRANSACTION, p1, 0, &chunk[0..(dest_offset + chunk_data_size)])?; - dest_offset = 0; - data_pos += chunk_data_size; - if data_pos == transaction.len() { - break; + // Signing personal messages are only support by Ledger firmware version 1.0.8 or newer + if command == commands::SIGN_ETH_PERSONAL_MESSAGE { + let version = Self::get_firmware_version(&handle)?; + if version < FirmwareVersion::new(1, 0, 8) { + return Err(Error::Protocol("Signing personal messages with Ledger requires version 1.0.8")); } } + let mut chunk= [0_u8; MAX_CHUNK_SIZE]; + let derivation_path = self.get_derivation_path(); + + // Copy the address of the key (only done once) + chunk[0..derivation_path.len()].copy_from_slice(derivation_path); + + let key_length = derivation_path.len(); + let max_payload_size = MAX_CHUNK_SIZE - key_length; + let data_len = data.len(); + + let mut result = Vec::new(); + let mut offset = 0; + + while offset < data_len { + let p1 = if offset == 0 { 0 } else { 0x80 }; + let take = min(max_payload_size, data_len - offset); + + // Fetch piece of data and copy it! + { + let (_key, d) = &mut chunk.split_at_mut(key_length); + let (dst, _rem) = &mut d.split_at_mut(take); + dst.copy_from_slice(&data[offset..(offset + take)]); + } + + result = Self::send_apdu(&handle, command, p1, 0, &chunk[0..(key_length + take)])?; + offset += take; + } + if result.len() != 65 { return Err(Error::Protocol("Signature packet size mismatch")); } @@ -301,56 +358,94 @@ impl <'a>Wallet<'a> for Manager { Ok(Signature::from_rsv(&r, &s, v)) } + pub fn sign_message(&self, address: &Address, msg: &[u8]) -> Result { + self.signer_helper(address, msg, commands::SIGN_ETH_PERSONAL_MESSAGE) + } +} + +// Try to connect to the device using polling in at most the time specified by the `timeout` +fn try_connect_polling(ledger: &Manager, timeout: &Duration, device_direction: DeviceDirection) -> bool { + let start_time = Instant::now(); + while start_time.elapsed() <= *timeout { + if let Ok(num_devices) = ledger.update_devices(device_direction) { + trace!(target: "hw", "{} number of Ledger(s) {}", num_devices, device_direction); + return true; + } + } + false +} + +impl <'a>Wallet<'a> for Manager { + type Error = Error; + type Transaction = &'a [u8]; + + fn sign_transaction(&self, address: &Address, transaction: Self::Transaction) -> Result { + self.signer_helper(address, transaction, commands::SIGN_ETH_TRANSACTION) + } + fn set_key_path(&self, key_path: KeyPath) { *self.key_path.write() = key_path; } - fn update_devices(&self) -> Result { + fn update_devices(&self, device_direction: DeviceDirection) -> Result { let mut usb = self.usb.lock(); usb.refresh_devices(); let devices = usb.devices(); - let mut new_devices = Vec::new(); - let mut num_new_devices = 0; - for device in devices { - trace!("Checking device: {:?}", device); - if device.vendor_id != LEDGER_VID || !LEDGER_PIDS.contains(&device.product_id) { - continue; - } - match self.read_device(&usb, &device) { - Ok(info) => { - debug!(target: "hw", "Found device: {:?}", info); - if !self.devices.read().iter().any(|d| d.path == info.path) { - num_new_devices += 1; + let num_prev_devices = self.devices.read().len(); + + let detected_devices = devices.iter() + .filter(|&d| d.vendor_id == LEDGER_VID && LEDGER_PIDS.contains(&d.product_id)) + .fold(Vec::new(), |mut v, d| { + match self.read_device(&usb, &d) { + Ok(info) => { + trace!(target: "hw", "Found device: {:?}", info); + v.push(info); } - new_devices.push(info); - + Err(e) => trace!(target: "hw", "Error reading device info: {}", e), + }; + v + }); + + let num_curr_devices = detected_devices.len(); + *self.devices.write() = detected_devices; + + match device_direction { + DeviceDirection::Arrived => { + if num_curr_devices > num_prev_devices { + Ok(num_curr_devices - num_prev_devices) + } else { + Err(Error::NoDeviceArrived) + } + } + DeviceDirection::Left => { + if num_prev_devices > num_curr_devices { + Ok(num_prev_devices- num_curr_devices) + } else { + Err(Error::NoDeviceLeft) } - Err(e) => debug!(target: "hw", "Error reading device info: {}", e), - }; + } } - *self.devices.write() = new_devices; - Ok(num_new_devices) } fn read_device(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result { let handle = self.open_path(|| usb.open_path(&dev_info.path))?; - let manufacturer = dev_info.manufacturer_string.clone().unwrap_or("Unknown".to_owned()); - let name = dev_info.product_string.clone().unwrap_or("Unknown".to_owned()); - let serial = dev_info.serial_number.clone().unwrap_or("Unknown".to_owned()); + let manufacturer = dev_info.manufacturer_string.clone().unwrap_or_else(|| "Unknown".to_owned()); + let name = dev_info.product_string.clone().unwrap_or_else(|| "Unknown".to_owned()); + let serial = dev_info.serial_number.clone().unwrap_or_else(|| "Unknown".to_owned()); match self.get_address(&handle) { Ok(Some(addr)) => { Ok(Device { path: dev_info.path.clone(), info: WalletInfo { - name: name, - manufacturer: manufacturer, - serial: serial, + name, + manufacturer, + serial, address: addr, }, }) } // This variant is not possible, but the trait forces this return type - Ok(None) => Err(Error::ImpossibleError), + Ok(None) => Err(Error::Impossible), Err(e) => Err(e), } } @@ -369,22 +464,13 @@ impl <'a>Wallet<'a> for Manager { } fn get_address(&self, device: &hidapi::HidDevice) -> Result, Self::Error> { - let ver = Self::send_apdu(device, commands::GET_APP_CONFIGURATION, 0, 0, &[])?; - if ver.len() != 4 { - return Err(Error::Protocol("Version packet size mismatch")); + let ledger_version = Self::get_firmware_version(&device)?; + if ledger_version < FirmwareVersion::new(1, 0, 3) { + return Err(Error::Protocol("Ledger version 1.0.3 is required")); } - let (major, minor, patch) = (ver[1], ver[2], ver[3]); - if major < 1 || (major == 1 && minor == 0 && patch < 3) { - return Err(Error::Protocol("App version 1.0.3 is required.")); - } + let derivation_path = self.get_derivation_path(); - let eth_path = Ð_DERIVATION_PATH_BE[..]; - let etc_path = &ETC_DERIVATION_PATH_BE[..]; - let derivation_path = match *self.key_path.read() { - KeyPath::Ethereum => eth_path, - KeyPath::EthereumClassic => etc_path, - }; let key_and_address = Self::send_apdu(device, commands::GET_ETH_PUBLIC_ADDRESS, 0, 0, derivation_path)?; if key_and_address.len() != 107 { // 1 + 65 PK + 1 + 40 Addr (ascii-hex) return Err(Error::Protocol("Key packet size mismatch")); @@ -417,7 +503,7 @@ struct EventHandler { impl EventHandler { /// Ledger event handler constructor fn new(ledger: Weak) -> Self { - Self { ledger: ledger } + Self { ledger } } } @@ -425,8 +511,8 @@ impl libusb::Hotplug for EventHandler { fn device_arrived(&mut self, device: libusb::Device) { debug!(target: "hw", "Ledger arrived"); if let (Some(ledger), Ok(_)) = (self.ledger.upgrade(), Manager::is_valid_ledger(&device)) { - if try_connect_polling(ledger, Duration::from_millis(500)) != true { - debug!(target: "hw", "Ledger connect timeout"); + if try_connect_polling(&ledger, &POLLING_DURATION, DeviceDirection::Arrived) != true { + debug!(target: "hw", "No Ledger device was connected"); } } } @@ -434,42 +520,82 @@ impl libusb::Hotplug for EventHandler { fn device_left(&mut self, device: libusb::Device) { debug!(target: "hw", "Ledger left"); if let (Some(ledger), Ok(_)) = (self.ledger.upgrade(), Manager::is_valid_ledger(&device)) { - if try_connect_polling(ledger, Duration::from_millis(500)) != true { - debug!(target: "hw", "Ledger disconnect timeout"); + if try_connect_polling(&ledger, &POLLING_DURATION, DeviceDirection::Left) != true { + debug!(target: "hw", "No Ledger device was disconnected"); } } } } -#[test] -#[ignore] -/// This test can't be run without an actual ledger device connected -fn smoke() { + +#[cfg(test)] +mod tests { use rustc_hex::FromHex; - let hidapi = Arc::new(Mutex::new(hidapi::HidApi::new().expect("HidApi"))); - let manager = Manager::new(hidapi.clone(), Arc::new(AtomicBool::new(false))).expect("Ledger Manager"); - - // Update device list - assert_eq!(try_connect_polling(manager.clone(), Duration::from_millis(500)), true); - - // Fetch the ethereum address of a connected ledger device - let address = manager.list_devices() - .iter() - .filter(|d| d.manufacturer == "Ledger".to_string()) - .nth(0) - .map(|d| d.address.clone()) - .expect("No ledger device detected"); - - let tx = FromHex::from_hex("eb018504a817c80082520894a6ca2e6707f2cc189794a9dd459d5b05ed1bcd1c8703f26fcfb7a22480018080").unwrap(); - let signature = manager.sign_transaction(&address, &tx); - println!("Got {:?}", signature); - assert!(signature.is_ok()); - let large_tx = FromHex::from_hex("f8cb81968504e3b2920083024f279475b02a3c39710d6a3f2870d0d788299d48e790f180b8a4b61d27f6000000000000000000000000e1af840a5a1cb1efdf608a97aa632f4aa39ed199000000000000000000000000000000000000000000000000105ff43f46a9a800000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018080").unwrap(); - let signature = manager.sign_transaction(&address, &large_tx); - println!("Got {:?}", signature); - assert!(signature.is_ok()); - let huge_tx = FromHex::from_hex("f935e98201048505d21dba00833b82608080b935946103e86003908155620d2f00600455601460055560a060405260608190527f2e2e2e00000000000000000000000000000000000000000000000000000000006080908152600d805460008290527f2e2e2e00000000000000000000000000000000000000000000000000000000068255909260008051602062003474833981519152602060026001851615610100026000190190941693909304601f0192909204820192909190620000dc565b82800160010185558215620000dc579182015b82811115620000dc578251825591602001919060010190620000bf565b5b50620001009291505b80821115620000fc5760008155600101620000e6565b5090565b5050600e8054600360ff199182168117909255604080518082019091528281527f2e2e2e00000000000000000000000000000000000000000000000000000000006020918201908152600f80546000829052825160069516949094178155937f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac80260026101006001871615026000190190951694909404601f019290920483019290620001d7565b82800160010185558215620001d7579182015b82811115620001d7578251825591602001919060010190620001ba565b5b50620001fb9291505b80821115620000fc5760008155600101620000e6565b5090565b50506010805460ff19166001179055346200000057604051620034943803806200349483398101604090815281516020830151918301516060840151919390810191015b5b5b60068054600160a060020a0319166c01000000000000000000000000338102041790558151600d80546000829052909160008051602062003474833981519152602060026101006001861615026000190190941693909304601f908101849004820193870190839010620002c157805160ff1916838001178555620002f1565b82800160010185558215620002f1579182015b82811115620002f1578251825591602001919060010190620002d4565b5b50620003159291505b80821115620000fc5760008155600101620000e6565b5090565b505080600f9080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200036557805160ff191683800117855562000395565b8280016001018555821562000395579182015b828111156200039557825182559160200191906001019062000378565b5b50620003b99291505b80821115620000fc5760008155600101620000e6565b5090565b5050600980546c01000000000000000000000000808602819004600160a060020a0319928316179092556007805487840293909304929091169190911790555b505050505b613066806200040e6000396000f300606060405236156102035760e060020a600035046306fdde03811461034b578063095ea7b3146103c65780630b0b6d5b146103ed5780631b1ccc47146103fc57806320e870931461047757806323b872dd1461049657806325b29d84146104c057806327187991146104df578063277ccde2146104f15780632e1fbfcd14610510578063308b2fdc14610532578063313ce5671461055457806338cc48311461057757806340eddc4e146105a057806341f4793a146105bf578063467ed261146105de578063471ad963146105fd5780634e860ebb1461060f5780634efbe9331461061e57806354786b4e1461064257806354e35ba2146106bd57806358793ad4146106d25780635abedab21461073f5780635af2f8211461074e57806360483a3f1461076d57806360d12fa0146107da578063698f2e84146108035780636a749986146108155780636d5f66391461082a5780636e9c36831461083c57806370a082311461085e5780637a290fe5146108805780637e7541461461088f57806394c41bdb1461090a57806395d89b4114610929578063962a64cd146109a4578063a0b6533214610a09578063a9059cbb14610a2b578063ab62438f14610a52578063b63ca98114610aa9578063b7c54c6f14610abb578063c4e41b2214610ada578063ca7c4dba14610af9578063cb79e31b14610b18578063dd62ed3e14610b3a575b6103495b60006000600c546000141561021b57610000565b600354600c54670de0b6b3a764000091349091020204915060009050816001600030600160a060020a031681526020019081526020016000205410156102c557600160a060020a033016600090815260016020526040902054600c54909250828115610000570466038d7ea4c68000023403905033600160a060020a03166108fc829081150290604051809050600060405180830381858888f1935050505015156102c557610000565b5b600160a060020a03338116600081815260016020908152604080832080548801905530909416825283822080548790039055601380543487900301908190559154600c548551908152918201879052845190949293927f5a0391f2a67f11ed0034b68f8cf14e7e41d6f86e0a7622f2af5ea8f07b488396928290030190a45b5050565b005b3461000057610358610b5f565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576103d9600435602435610bed565b604080519115158252519081900360200190f35b3461000057610349610c58565b005b3461000057610358610dbc565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610484610e5a565b60408051918252519081900360200190f35b34610000576103d9600435602435604435610ef9565b604080519115158252519081900360200190f35b3461000057610484610ff3565b60408051918252519081900360200190f35b3461000057610349600435611002565b005b346100005761048461105a565b60408051918252519081900360200190f35b3461000057610484600435611061565b60408051918252519081900360200190f35b346100005761048460043561108d565b60408051918252519081900360200190f35b34610000576105616110b9565b6040805160ff9092168252519081900360200190f35b34610000576105846110c2565b60408051600160a060020a039092168252519081900360200190f35b34610000576104846110c7565b60408051918252519081900360200190f35b34610000576104846110ce565b60408051918252519081900360200190f35b34610000576104846110d5565b60408051918252519081900360200190f35b3461000057610349600435611174565b005b34610000576103496113b5565b005b34610000576103d9600435611407565b604080519115158252519081900360200190f35b3461000057610358611549565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576103496004356024356115e7565b005b346100005760408051602060046024803582810135601f8101859004850286018501909652858552610726958335959394604494939290920191819084018382808284375094965061167e95505050505050565b6040805192835290151560208301528051918290030190f35b3461000057610349611c13565b005b3461000057610484611d46565b60408051918252519081900360200190f35b346100005760408051602060046024803582810135601f81018590048502860185019096528585526107269583359593946044949392909201918190840183828082843750949650611d4d95505050505050565b6040805192835290151560208301528051918290030190f35b3461000057610584612303565b60408051600160a060020a039092168252519081900360200190f35b3461000057610349600435612313565b005b3461000057610349600435602435612347565b005b346100005761034960043561252f565b005b3461000057610484600435612941565b60408051918252519081900360200190f35b346100005761048460043561298d565b60408051918252519081900360200190f35b34610000576103496129ac565b005b3461000057610358612a13565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610484612ab1565b60408051918252519081900360200190f35b3461000057610358612ab8565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610484600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843750949650612b4695505050505050565b60408051918252519081900360200190f35b3461000057610484600435612b63565b60408051918252519081900360200190f35b34610000576103d9600435602435612b8c565b604080519115158252519081900360200190f35b3461000057610349600480803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437509496505093359350612c3c92505050565b005b3461000057610349600435612f38565b005b3461000057610484612f90565b60408051918252519081900360200190f35b346100005761048461300c565b60408051918252519081900360200190f35b3461000057610484613013565b60408051918252519081900360200190f35b346100005761048460043561301a565b60408051918252519081900360200190f35b3461000057610484600435602435613039565b60408051918252519081900360200190f35b600d805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610be55780601f10610bba57610100808354040283529160200191610be5565b820191906000526020600020905b815481529060010190602001808311610bc857829003601f168201915b505050505081565b600160a060020a03338116600081815260026020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b601a54600090600160a060020a03161515610c7257610000565b600160a060020a0333166000908152600a60205260409020541515610c9657610000565b600160a060020a0333166000908152601d602052604090205460ff1615610cbc57610000565b601b54426212750090910111610cd157610000565b600160a060020a0333166000818152601d60209081526040808320805460ff19166001179055600a8252918290208054601c805490910190555482519384529083015280517f475c7605c08471fdc551a58d2c318b163628c5852f69323a1b91c34eb0bb09339281900390910190a150601154601c54606490910490604682029010610db857601a5460068054600160a060020a031916606060020a600160a060020a0393841681020417908190556040805191909216815290517f6b8184e23a898262087be50aa3ea5de648451e63f94413e810586c25282d58c2916020908290030190a15b5b50565b604080516020808201835260008252600d8054845160026001831615610100026000190190921691909104601f810184900484028201840190955284815292939091830182828015610e4f5780601f10610e2457610100808354040283529160200191610e4f565b820191906000526020600020905b815481529060010190602001808311610e3257829003601f168201915b505050505090505b90565b600f805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152600093610ef39391929091830182828015610ee95780601f10610ebe57610100808354040283529160200191610ee9565b820191906000526020600020905b815481529060010190602001808311610ecc57829003601f168201915b5050505050612b46565b90505b90565b600160a060020a038316600090815260016020526040812054829010801590610f495750600160a060020a0380851660009081526002602090815260408083203390941683529290522054829010155b8015610f555750600082115b15610fe757600160a060020a03808516600081815260016020908152604080832080548890039055878516808452818420805489019055848452600283528184203390961684529482529182902080548790039055815186815291517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a3506001610feb56610feb565b5060005b5b9392505050565b600160a060020a033016315b90565b60065433600160a060020a0390811691161461101d57610000565b600c8190556040805182815290517f0bbd501ef336990995d82b5e3fd82a15abe1ff10c982757a1698ac5d1c3e79579181900360200190a15b5b50565b600b545b90565b6000601882815481101561000057906000526020600020906007020160005b506004015490505b919050565b6000601882815481101561000057906000526020600020906007020160005b506001015490505b919050565b600e5460ff1681565b305b90565b6013545b90565b601c545b90565b600d805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152600093610ef39391929091830182828015610ee95780601f10610ebe57610100808354040283529160200191610ee9565b820191906000526020600020905b815481529060010190602001808311610ecc57829003601f168201915b5050505050612b46565b90505b90565b600654600090819033600160a060020a0390811691161461119457610000565b60008381526014602052604090205415156111ae57610000565b60008381526014602052604090206005015433600160a060020a039081169116146111d857610000565b60008381526014602052604090206005015460a060020a900460ff16156111fe57610000565b601154600084815260146020526040902060040154606490910460370292508290111561122a57610000565b60008381526014602052604081206005015460a860020a900460ff16600181116100005714156112eb57600954600084815260146020908152604080832060058101546001909101548251840185905282517fa9059cbb000000000000000000000000000000000000000000000000000000008152600160a060020a0392831660048201526024810191909152915194169363a9059cbb93604480840194938390030190829087803b156100005760325a03f1156100005750611389915050565b60008381526014602052604080822060058101546001909101549151600160a060020a039091169282156108fc02929190818181858888f160008881526014602090815260409182902060058101546001909101548351600160a060020a0390921682529181019190915281519297507f2648a7e2f9c34700b91370233666e5118fa8be3e0c21fed4f7402b941df8efdd9650829003019350915050a15b6000838152601460205260409020600501805460a060020a60ff02191660a060020a1790555b5b505050565b60065433600160a060020a039081169116146113d057610000565b6010805460ff191690556040517fb48c7f694f0a3b9b22d7e61c60ff8aebbb107314b6b698fc489ff3f017cb57e090600090a15b5b565b600060006000600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f115610000575050604051514210905061147c57610000565b60085433600160a060020a0390811691161461149757610000565b5050600b54600160a060020a03328181166000908152600a6020526040902080549386029384019055601180548401905560128054860190556008549092916114e39130911683610ef9565b506114ee8282612b8c565b50600054601154600b5460408051918252602082018590528051600160a060020a038716927fb4d6befef2def3d17bcb13c2b882ec4fa047f33157446d3e0e6094b2a21609ac92908290030190a4600192505b5b5050919050565b604080516020808201835260008252600f8054845160026001831615610100026000190190921691909104601f810184900484028201840190955284815292939091830182828015610e4f5780601f10610e2457610100808354040283529160200191610e4f565b820191906000526020600020905b815481529060010190602001808311610e3257829003601f168201915b505050505090505b90565b60065433600160a060020a0390811691161461160257610000565b60105460ff16151561161357610000565b600160a060020a0330166000908152600160209081526040808320805485019055600c859055825484019283905580518481529051839286927f10cb430288a1696de11938bc5362c6f8c60e58808237bce4436b93a8573e00c3929081900390910190a45b5b5b5050565b6040805161010081018252600080825260208083018290528351908101845281815292820192909252606081018290526080810182905260a0810182905260c0810182905260e08101829052600654829182918291829133600160a060020a039081169116146116ed57610000565b60115460649004935060056016541115801561170c5750836005540288115b1561171657610000565b61171e612f90565b8811156117305761172d612f90565b97505b60003642604051808484808284378201915050828152602001935050505060405180910390209250600454420191506101006040519081016040528084815260200189815260200188815260200183815260200160008152602001338152602001600081526020016000815260200150905080601460008560001916815260200190815260200160002060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061182057805160ff191683800117855561184d565b8280016001018555821561184d579182015b8281111561184d578251825591602001919060010190611832565b5b5061186e9291505b8082111561186a5760008155600101611856565b5090565b5050606082015160038201556080820151600482015560a08201516005909101805460c084015160e09094015160f860020a90810281900460a860020a0260a860020a60ff02199582029190910460a060020a0260a060020a60ff0219606060020a95860295909504600160a060020a031990931692909217939093161792909216179055601880546001810180835582818380158290116119c9576007028160070283600052602060002091820191016119c991905b8082111561186a5760006000820160009055600182016000905560028201805460018160011615610100020316600290046000825580601f10611968575061199a565b601f01602090049060005260206000209081019061199a91905b8082111561186a5760008155600101611856565b5090565b5b50506000600382018190556004820155600581018054600160b060020a0319169055600701611925565b5090565b5b505050916000526020600020906007020160005b83909190915060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611a4a57805160ff1916838001178555611a77565b82800160010185558215611a77579182015b82811115611a77578251825591602001919060010190611a5c565b5b50611a989291505b8082111561186a5760008155600101611856565b5090565b5050606082015181600301556080820151816004015560a08201518160050160006101000a815481600160a060020a030219169083606060020a90810204021790555060c08201518160050160146101000a81548160ff021916908360f860020a90810204021790555060e08201518160050160156101000a81548160ff021916908360f860020a90810204021790555050505060166000815460010191905081905550426017819055507f1a1eea7d2a0f099c2f19efb4e101fcf220558c9f4fbc6961b33fbe02d3a7be908389848a3360405180866000191681526020018581526020018481526020018060200183600160a060020a031681526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611bee5780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a1826001955095505b5b505050509250929050565b60065460009033600160a060020a03908116911614611c3157610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f1156100005750506040515162dd7c00014210159050611ca657610000565b604051600160a060020a0333811691309091163180156108fc02916000818181858888f1600954909550600160a060020a0316935063a9059cbb9250339150611cef9050612f90565b6000604051602001526040518360e060020a0281526004018083600160a060020a0316815260200182815260200192505050602060405180830381600087803b156100005760325a03f115610000575050505b5b50565b6016545b90565b6040805161010081018252600080825260208083018290528351908101845281815292820192909252606081018290526080810182905260a0810182905260c0810182905260e08101829052600654829182918291829133600160a060020a03908116911614611dbc57610000565b60105460ff1615611dcc57610000565b6000611dd73061298d565b1115611de257610000565b6017546212750001421015611df657610000565b6013546064900493508360055402881115611e1057610000565b30600160a060020a031631881115611e305730600160a060020a03163197505b60003642604051808484808284378201915050828152602001935050505060405180910390209250600454420191506101006040519081016040528084815260200189815260200188815260200183815260200160008152602001338152602001600081526020016001815260200150905080601460008560001916815260200190815260200160002060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611f2057805160ff1916838001178555611f4d565b82800160010185558215611f4d579182015b82811115611f4d578251825591602001919060010190611f32565b5b50611f6e9291505b8082111561186a5760008155600101611856565b5090565b5050606082015160038201556080820151600482015560a08201516005909101805460c084015160e09094015160f860020a90810281900460a860020a0260a860020a60ff02199582029190910460a060020a0260a060020a60ff0219606060020a95860295909504600160a060020a031990931692909217939093161792909216179055601880546001810180835582818380158290116120c9576007028160070283600052602060002091820191016120c991905b8082111561186a5760006000820160009055600182016000905560028201805460018160011615610100020316600290046000825580601f10612068575061209a565b601f01602090049060005260206000209081019061209a91905b8082111561186a5760008155600101611856565b5090565b5b50506000600382018190556004820155600581018054600160b060020a0319169055600701612025565b5090565b5b505050916000526020600020906007020160005b83909190915060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061214a57805160ff1916838001178555612177565b82800160010185558215612177579182015b8281111561217757825182559160200191906001019061215c565b5b506121989291505b8082111561186a5760008155600101611856565b5090565b5050606082015181600301556080820151816004015560a08201518160050160006101000a815481600160a060020a030219169083606060020a90810204021790555060c08201518160050160146101000a81548160ff021916908360f860020a90810204021790555060e08201518160050160156101000a81548160ff021916908360f860020a908102040217905550505050426017819055507f1a1eea7d2a0f099c2f19efb4e101fcf220558c9f4fbc6961b33fbe02d3a7be908389848a3360405180866000191681526020018581526020018481526020018060200183600160a060020a031681526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611bee5780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a1826001955095505b5b505050509250929050565b600654600160a060020a03165b90565b600854600160a060020a03161561232957610000565b60088054600160a060020a031916606060020a838102041790555b50565b60065433600160a060020a0390811691161461236257610000565b60105460ff16151561237357610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f11561000057505060405151421090506123e257610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663cdd933326000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f11561000057505060405151421015905061245257610000565b600854600160a060020a0316151561246957610000565b6000805482018155600160a060020a03308116808352600160209081526040808520805487019055600b8790556002825280852060088054861687529083529481902080548701905593548451868152945193169391927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3600054601154600b546040805185815290517f10cb430288a1696de11938bc5362c6f8c60e58808237bce4436b93a8573e00c39181900360200190a45b5b5b5b5b5050565b604080516101008082018352600080835260208084018290528451808201865282815284860152606084018290526080840182905260a0840182905260c0840182905260e0840182905285825260148152848220855180850187528154815260018083015482850152600280840180548a51600019948216159099029390930190921604601f8101859004850287018501895280875296979496879692959394938601938301828280156126245780601f106125f957610100808354040283529160200191612624565b820191906000526020600020905b81548152906001019060200180831161260757829003601f168201915b505050918352505060038201546020820152600482015460408201526005820154600160a060020a038116606083015260ff60a060020a820481161515608084015260a09092019160a860020a909104166001811161000057905250600085815260146020526040902054909350151561269d57610000565b60008481526014602052604090206005015460a060020a900460ff16156126c357610000565b60008481526014602052604090206003015442106126e057610000565b6000848152601460209081526040808320600160a060020a033316845260060190915290205460ff161561271357610000565b600160a060020a0333166000818152600a6020908152604080832054888452601483528184206004810180548301905594845260069094019091529020805460ff19166001179055915061276684612941565b6000858152601460205260409020601880549293509091839081101561000057906000526020600020906007020160005b50600082015481600001556001820154816001015560028201816002019080546001816001161561010002031660029004828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10612801578054855561283d565b8280016001018555821561283d57600052602060002091601f016020900482015b8281111561283d578254825591600101919060010190612822565b5b5061285e9291505b8082111561186a5760008155600101611856565b5090565b5050600382810154908201556004808301549082015560059182018054929091018054600160a060020a031916606060020a600160a060020a0394851681020417808255825460a060020a60ff021990911660f860020a60a060020a9283900460ff908116820282900490930291909117808455935460a860020a60ff021990941660a860020a9485900490921681020490920291909117905560408051868152339092166020830152818101849052517f8f8bbb8c1937f844f6a094cd4c6eeab8ed5e36f83952e6306ffb2c11fffe5bce916060908290030190a15b50505050565b6000805b60185481101561298657601881815481101561000057906000526020600020906007020160005b505483141561297d57809150612986565b5b600101612945565b5b50919050565b600160a060020a0381166000908152600160205260409020545b919050565b60065433600160a060020a039081169116146129c757610000565b600160a060020a03301660009081526001602052604080822080548354038355829055517fe0987873419fe09d3c9a3e0267f4daf163e812d512f867abaf6bf9822f141a8b9190a15b5b565b60408051602080820183526000825260198054845160026001831615610100026000190190921691909104601f810184900484028201840190955284815292939091830182828015610e4f5780601f10610e2457610100808354040283529160200191610e4f565b820191906000526020600020905b815481529060010190602001808311610e3257829003601f168201915b505050505090505b90565b6011545b90565b600f805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610be55780601f10610bba57610100808354040283529160200191610be5565b820191906000526020600020905b815481529060010190602001808311610bc857829003601f168201915b505050505081565b6000602082511115612b5757610000565b5060208101515b919050565b6000601882815481101561000057906000526020600020906007020160005b505490505b919050565b600160a060020a033316600090815260016020526040812054829010801590612bb55750600082115b15612c2d57600160a060020a03338116600081815260016020908152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a3506001610c5256610c52565b506000610c52565b5b92915050565b600160a060020a0333166000908152600a60205260409020541515612c6057610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f11561000057505060405151626ebe00014210159050612cd557610000565b601b5415801590612cef5750426019600201546212750001115b15612cf957610000565b6040805160808101825283815260208082018490524262127500018284015233600160a060020a03166000908152600a8252928320546060830152815180516019805495819052939484937f944998273e477b495144fb8794c914197f3ccb46be2900f4698fd0ef743c969560026001841615610100026000190190931692909204601f90810182900483019490910190839010612da257805160ff1916838001178555612dcf565b82800160010185558215612dcf579182015b82811115612dcf578251825591602001919060010190612db4565b5b50612df09291505b8082111561186a5760008155600101611856565b5090565b505060208201518160010160006101000a815481600160a060020a030219169083606060020a908102040217905550604082015181600201556060820151816003015590505060016019600401600033600160a060020a0316815260200190815260200160002060006101000a81548160ff021916908360f860020a9081020402179055507f854a9cc4d907d23cd8dcc72af48dc0e6a87e6f76376a309a0ffa3231ce8e13363383426212750001846040518085600160a060020a031681526020018060200184815260200183600160a060020a031681526020018281038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015612f235780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a15b5050565b60065433600160a060020a03908116911614612f5357610000565b600b819055600080546011546040519192909184917f17a7f53ef43da32c3936b4ac2b060caff5c4b03cd24b1c8e96a191eb1ec48d1591a45b5b50565b6000600960009054906101000a9004600160a060020a0316600160a060020a03166370a08231306000604051602001526040518260e060020a0281526004018082600160a060020a03168152602001915050602060405180830381600087803b156100005760325a03f115610000575050604051519150505b90565b6000545b90565b600c545b90565b600160a060020a0381166000908152600a60205260409020545b919050565b600160a060020a038083166000908152600260209081526040808320938516835292905220545b9291505056d7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb500000000000000000000000069381683bde924cef65f1c97f7c8fb769a20409300000000000000000000000014f37b574242d366558db61f3335289a5035c506000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000018546573742074657374657220746573746573742063616d700000000000000000000000000000000000000000000000000000000000000000000000000000000354455300000000000000000000000000000000000000000000000000000000001ba033230fce515bea9de982fe85e0ec8fe892984bc3070ad633daab20eb370864d5a05deb41870e2117197b84cb71110fc0508fa7457165cb8cb82cb8d4d801e6e3f1").unwrap(); - let signature = manager.sign_transaction(&address, &huge_tx); - println!("Got {:?}", signature); - assert!(signature.is_ok()); + use super::*; + + /// This test can't be run without an actual ledger device connected with the `Ledger Wallet Ethereum application` running + #[test] + #[ignore] + fn sign_personal_message() { + let manager = Manager::new( + Arc::new(Mutex::new(hidapi::HidApi::new().expect("HidApi"))), + Arc::new(AtomicBool::new(false)) + ).expect("HardwareWalletManager"); + + // Update device list + manager.update_devices(DeviceDirection::Arrived).expect("No Ledger found, make sure you have a unlocked Ledger connected with the Ledger Wallet Ethereum running"); + + // Fetch the ethereum address of a connected ledger device + let address = manager.list_devices() + .iter() + .filter(|d| d.manufacturer == "Ledger".to_string()) + .nth(0) + .map(|d| d.address.clone()) + .expect("No ledger device detected"); + + // 44 bytes transaction + let tx = FromHex::from_hex("eb018504a817c80082520894a6ca2e6707f2cc189794a9dd459d5b05ed1bcd1c8703f26fcfb7a22480018080").unwrap(); + let signature = manager.sign_transaction(&address, &tx); + assert!(signature.is_ok()); + } + + /// This test can't be run without an actual ledger device connected with the `Ledger Wallet Ethereum application` running + #[test] + #[ignore] + fn smoke() { + let manager = Manager::new( + Arc::new(Mutex::new(hidapi::HidApi::new().expect("HidApi"))), + Arc::new(AtomicBool::new(false)) + ).expect("HardwareWalletManager"); + + // Update device list + manager.update_devices(DeviceDirection::Arrived).expect("No Ledger found, make sure you have a unlocked Ledger connected with the Ledger Wallet Ethereum running"); + + // Fetch the ethereum address of a connected ledger device + let address = manager.list_devices() + .iter() + .filter(|d| d.manufacturer == "Ledger".to_string()) + .nth(0) + .map(|d| d.address.clone()) + .expect("No ledger device detected"); + + // 44 bytes transaction + let tx = FromHex::from_hex("eb018504a817c80082520894a6ca2e6707f2cc189794a9dd459d5b05ed1bcd1c8703f26fcfb7a22480018080").unwrap(); + let signature = manager.sign_transaction(&address, &tx); + println!("Got {:?}", signature); + assert!(signature.is_ok()); + + // 218 bytes transaction + let large_tx = FromHex::from_hex("f86b028511cfc15d00825208940975ca9f986eee35f5cbba2d672ad9bc8d2a08448766c92c5cf830008026a0d2b0d401b543872d2a6a50de92455decbb868440321bf63a13b310c069e2ba5ba03c6d51bcb2e1653be86546b87f8a12ddb45b6d4e568420299b96f64c19701040f86b028511cfc15d00825208940975ca9f986eee35f5cbba2d672ad9bc8d2a08448766c92c5cf830008026a0d2b0d401b543872d2a6a50de92455decbb868440321bf63a13b310c069e2ba5ba03c6d51bcb2e1653be86546b87f8a12ddb45b6d4e568420299b96f64c19701040").unwrap(); + let signature = manager.sign_transaction(&address, &large_tx); + println!("Got {:?}", signature); + assert!(signature.is_ok()); + + // 36206 bytes transaction (You need to confirm many transaction on your `Ledger` for this) + let huge_tx = FromHex::from_hex("f86b028511cfc15d00825208940975ca9f986eee35f5cbba2d672ad9bc8d2a08448766c92c5cf830008026a0d2b0d401b543872d2a6a50de92455decbb868440321bf63a13b310c069e2ba5ba03c6d51bcb2e1653be86546b87f8a12ddb45b6d4e568420299b96f64c19701040f86b028511cfc15d00825208940975ca9f986eee35f5cbba2d672ad9bc8d2a08448766c92c5cf830008026a0d2b0d401b543872d2a6a50de92455decbb868440321bf63a13b310c069e2ba5ba03c6d51bcb2e1653be86546b87f8a12ddb45b6d4e568420299b96f64c1970104000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7cd58ab9190c2792714ab06df5b67e66d9e3873eed251d7beb4fa252d6fed6a0ab1e5fabd284f40878d38f6e63d72eec55c6e1aa8d79c06adf714e3523a1f83da763f4bcc9d34424aba82981534066379c1cba244352042de13168556be761f8b1000807b6a6cd340b97a93cd850ee54335b1043bac153c1b0736a88919bb1a21d6befba34d9af51a9b3eb39164c64fe88efe62f136d0bc83cad1f963aec6344b9e406f7381ad2462dcf1434c90c426ee907e6a05abe39c2b36d1dfb966bcf5a4de5af9f07819256357489365c96b21d92a103a776b656fc10ad1083cf679d240bf09bf2eb7635d7bfa969ce7fbb4e0cd5835f79ca9f5583e3a9eca219fab2f773d9c7e838a7a9ef8755dc22e4880367c2b5e40795fe526fc5d1461e50d5cb053e001206460fc6617a38499db525112a7edde38b9547853ad6e5ab359233611148f196501deafae414acde9df81efd7c4144b8fd27f63ac252ecede9609b3f9e634ae95c13058ad2b4529bbb07b5d7ac567c2da994084c3c73ef7c453fc139fcdb3939461da5bf0fa3f2a83517463d02b903af5d845929cf12c9a1479f6801f20085887a94d72814671dac994e14b2faa3251d465ce16d855f33259d94fcc9553b25b488d5c45fe74de60c303bc75bcdde9374ca268767f5767638d1aec5f6f95cab8e9e27b9a80ddf3dbbe24f790debd9e3baa30145d499dd1afb5662a11788b1bb3dedc1ebc5eff9641fa6918d958e4738bae3854e4cd43f9173cd4c9c821190ec287c18035a530c2dc63077d292b3a35b3756ba9e08295a02e37d332552f9f4fdbb945df004aa5b072f9f0e9fc2e4ed6fe455d95b003e5e593dcbfad0b3b47aa855b34008e0e9a2e1cc23b975a3e6808be59dcaa8a87145c1d5183c799d06100d500227e6a758757b4f7d042b3485aa0ce5e91b2b2e67d3cfdf1c226b7ab90e40f0a0d30cbbf425f495bd5a80202909ad419745a59210e2c42a1846e656f67a764ee307abbd76fbb0c99a702253b7a753c3b93e974881f3c97987856b57449e92ffa759da041a2acac59ea2d53836098196355ae0aa2a185dbb002a67c1a278a6032f156bc1e6d7f4ff6c674126af272fdfd1dcd6a810f42878164f1c7ae346b0dd91b678b363d0e33f4b81f2d7cc14da555dcbe4b9f80ac0fed6265a6ecce278888c9794373dcb0d20aa811a9fe9864fab25eaf12764bb2f1a68cd8756cd0b3583f6e5ec74ca5c327b3f6599fa9ec32ccd1831ae323689ef4a1b1a587cbbd2120e0bb8e59f9fc87d93e0365eb36557be6c45c30c1baeba33cdaa877a87e51fd70f2b5521078607d012d65f1fcca8051a01004a6d10f662dfa6445b2ac015cb3ce8fde56bbff93f5d620171e638c6e05504c2aeeeb74c7667aee1709846cb84d345a011c21c1b4e3fd09774ab4dcc63bda04bb0f4fc49d6145d202d807cc2d8eab29b3babe15e53a3656daf0b022ac37513f77660d43d60bdd3e882eef239bfe13dba2e12707733d56e49f638005e06019a7335d8184f1039ab18084de896a946c23045e5c164dc9d32f2f227c89f717a87d1243516b922e5f270c751f1bdb2b1d3a38a15b18a7b8b7e0818573f31320d496e14a348f979b7606c5124e007493f2f40c931f68e3483a46ab2b853a90bd38ae85e6252fece6fd36f7dad0d07b6763d8001a0d6abee62452904f979cc52fa15001b06eef08f17d6e16d493d227ce9277392337a1c71713603e03803d38d1c24184b52049bc029f4f00b22d2acdef91c776a74aa184cc84b0e764f463ed05c2e16a7a0dcb6c27dd4aeca8aeac1545b48896775ba3fe9de4ea36e946d8f4ec16ca7ae58165e8ddc9189d5cc569888a59733529add4b213ea5c00ad3ed3709c0175b542513c90e18f2d4fa2301389102839d969e9f0d614943fe489750f27382f7ab273f51fcb995f449fa5fba108ad0955ed0819a0a62308021ac4ab0c97f04de9fb8533489b2685447ad71c7f9a9bc89975f9cdde87a3af89ae5bff37d1f192a31b7c5aad50486931bc07820d7dae398960965baba6cfc05c56df18b8ef0f5db488eb87be803fc94e3ad3bd6e4f358fe7ce15ca21c9a4752ddfa98337177a7c096d829886e8d71340a01644c64090c84e88235b11bd1fefe506d59733cdd82286fb466ee215914b06a138356e82c0ae6d5fd8e5fb310eb375540308d95b5d53832a5dae9652f91c1e8c14402991e38836813604dcaf272fc552e7682a6eaa7aacfd4ed1c7107b0232cdee00aef865c5577f2391937b76e34810f9d49fe31e54425b6f5e1d0e436e1366e9762d8295877e27ae495ace18fccfaafd850544c9be949d15d421cf6f4bb180225f7f86ca64480975c486df0eeb4fa80a4632cff28d36585cb5dc534553454ea810260983d02060caf6b1eb2b9443b1552ff73d243fecc9779635ed137a3bc8c04ef13f0329a7a5a54b2af0738218cc91be0ee63512f009435d8623ff4e8cdaf743818510b22e42b586a7e5e75525bb61dd2deb96adc95e07998a265d58fe4df4b9ead5b5f15b9daee510558fbdfae7a56931a6f4c729c18e0d29c467fed504810b7d9dfa0613d1657d9bfa5887e3f327cf46d7059a8a0fd654c60cb9c683c55439cd5186d1615f45f7108f261aff77791cf24c975120acf2b357dfbd2defafac0016525cff9400e0feeddff27910fbf2fa84c35fcaaec90863b605db5adbad0593601447605d68b943249861f8cd33c6419c7611403376a6bb438ee857ced2e6842f99ed1b4a9dc79f835813a4f8d07c14f1ef98773286e79cec1c9ce8c26e00418f1b27c7ef104fc96ea2b2ddefb46e2fec4feef2771a1d7e2643586b6fb97094a8d298de12a6f8f78d88e5d67442ed3310fb40aa6439b89c834e43ecd4a80c0a1d74ce6a90a67bcc996a7e93b6f397fe7ab2fa43711a72b84f8c94bd1e4ac62657b98a4b814d8ef2bb469165464a90d5353aa95d09b6ef4ffef081cab5e9dc12d743364f06d4118a585f7d455fd6e3b01434a728a768987c181409eb939e9396666560d394fb151fc67cb9cddea0a94d3e33382bd0617c95304da97994f110eafaaaff6eecb54421e01dc850dc73d77df18bbf68ecc8b37ee2fff7b6f88c139f7d88d763248deb8b4e16a8fab216c0ce88faea030f3a5c994c6e4ef6a9a68cbc9310787232198b020a7c014a1fa32c1736885603dd4921cd360bfb7dca7aafcbe81d7621dbeb4e5c094c2584c339ce70176d7fd2a6cfc4bbea6b433377eff7320d412947ac774688010369b197ec4d0471b9cc73cf9a3e71bd10901beefb10ca1c53428b89ea63427aae9ede5ba104d3fb54d0447458dd9780cd4e925f1edad33f6f0884cc47da562a3c6e2f5a958a8d8723919c4b88d067343a246c6722b6f9f82018d5213648792f38fa8ea1e635b3983dc1f941630fb3762ef1814ee3f41691b24583ddca585289568b4e64f82448b54797d382916e562b3f4795e2d726facea988249e2c3f72d44ec7197b6f783c6c7a133004d5e131b7b4d6a9557c56942ca4bd1f070a2b46c3a6b81bb9a4d570ac6afea75de65ecd331dff1e0252e0f9095f974f47b2d340d67704343b2e8832232210d2f79665bebccab528745c1dc3b28a78aafa3785c29ce2eb6a8403e4d8eded1cc2554ece0a542aa2febd711164f7d7e3a492a87b01d6b4206e593b3aa6d431e908282fcfee0d14dae4b99176a16fa32f730c2d336dcfe7eff84a7aaab1fc32ac8c2e9ab6ebb72c0306bc6998ec22d6cf20c2b6660cfbbeb064b3047c1cf650df12bd153cd7eec5dc181e46575f07c8e292cc191117cd28302d1f9c72d79b1f4062dd683ca95c3a744ac310764e56b2f02a0c2850a2f24c1b298e712374e9adfe68e5414386d7671bd52f6f472eebfdf51677ce379afe7b8085459fb1e6966f5cef45b256489b7ec8a8939cd931009c8a26642f1ff78cab06a5d25522a922cd5e4541dcdbde4848177a42476b141ce9ea035d28742cee0e5e85eb78ceb2b720e112aeb76cd0eb3fc34574c7476110b3b9dff5c19fceae816715b31fc289c0e7149e8488a59e075ac6683f237886a63a25ad23bf903480b9acf3f724d5ace0ca3a842939d4828910cc735e6513dfc4055624d68a048a626fab6b910eaf558c1b43daf1cf26338bca68b5e308b734b61624c97bf70a82430d586a6c3cf59e1bab2532fd9fa1f6fe4f757c7ede0cabea52f2cbf00cc88ca7db4ccc0ff92c0836e7405ebef2ad2e4b7d3b455d8e4d9ae575d884347bdadb67f5e24058a44ae1335280b671ec3bb9d8247e28fecedf5c151fe892bb0f6e67351752e4b1bf75dcd5af3e62ab4aedc5aa32a1606b4a0de3156b356b0fe74e898065d1e720b81663453fc97f935da3b5755a0629f38d6ae5f8e5e77eb64bbef5fc70d4081ebee7a9f7169df4f0e11796f7a79e9128ec996b6fbd8f6fa56e11f17db4925c27f4cd3ddbdee8a50e0b0d4d8f6e527302cbc4dbeef4b0338e6ac7515c1e796b39c8e83f457b50925c39d405f4cd3c1aaf3188c5ac62bf1dd362bc8c9d4e49d3d2b7c2dd2291fa4bb22d7cbe7963b654d92643b789366d1dce842f47919a1cf5073da8916701f907c4d2f8a710c58e85b59f590123d3f8e57cdc14df41a1481a893b9f9505dc0637ba9b27657b0ceab87b0e4bc742924e6d8bf895b407c54df8622018417f9e543fe49f5b10a7a5fc66e5589304af33a20ea108ddf63facebcb20d22eac2fdf4a97285ae6d3f87865fae1331d00e631dfe5366345e0d78bb39a8077484a941176bc63f469f001cfd230347580b6226d6adff5ab112dcd53e7118925296b1a05978a703e383e6ffa5158fc36781f74501564992ab244d3475e1ee8e7146033da2dc116489b84c378e4a750947eb9ccb982a197f13976bb105c81624618c697f32a5b9e03f3675b2315fe773e4922c2e3da7f68ac225107405ece58dc6bbe2bd8947f3e4269ce245589497cd892c750f9ace0440f48057090c8a6cbd5046d3d982d634b4ad6ba41c7a38b7b8b0f91cb6898e769479fc3c7e7d2010b7fb38ef13c17db705a36455a34969803323806009a4e141a5c42da0f7a5e4760d07250d7e483ca6274e57cc2885e5728c24c8b5102845e8bb74b1c394fa7a206ec052c953967380d64c148ca480ab0edbc5da1a7a1e649c2ebfd19fefc52d81aeed7cd83f3c1d2128bd66feb99d5d8fbced01383d2abbf9be47f3390dd336c22b533a731d1c59c3bc5361d781ca15430d84f3c67d6981ab99100f53b6b5623df9d8eecc99d24e02d9301d636c2d5988e98a54339d5b516379a67d50dd9994a28fae5b806c56b353a84cb31729487a6d9851960b83ebc5178be689720a80c5c412e67f8ed55724534c92ab15c3bbc5bf13dfbff02d41ce4c9bc112746b62dea2b21d034e9a31e276eacfeeafc672b95e701ec0fc7ebd4b020a73fc37361b3f136246a0e3a8378442eb5e60abd7da2032dca9b5556aa22e5007c901f438c5e1baeb5d3ec6128a84d310363c6ec17d4ffece27f502b5c63d20cb1d11d0cfc316074faa820a03e6c577389e5e82ebe5f0976b6f5266618f5eb56986714d5cc75fe87176e92dcf01c58029d2b838022c0812c933db17dc4566d233720075065fda26f44b0ed3a46b6143fe180b7a1e6c1558f87b875aedf8c2fa968e2c925f0c08c7e0f23a9cf1b46f7955d9f1db300dab801f5672e2a7231bb2b622b0dc0dd9f2ec64a5f10c239e613247f8685369ed60b2d262c038fcc43924c5aca318385c12412b10d89753f9dfca43eff5f2be7d7d7b2788b877efa8b46ec5c9e99f922839bef71c613cd44cba597cf68de366eaa8874032c14d8012b41e72fd66422f7031d26be0dc4fef8f36a3c124e4ae767a665a94233812984c4466f5bd698b5fc22153c9c2f4110d9defb23c00e722692983b32ee0e84514169910bb21b14066d048960b29b3ff4c090dd5723ca4dcdebd207d4f88da831f0ee7de4aa302a06589a4aba3ca696e7d3c3e9a93af79db91f7a06b0ad825a8652f74bdb72f580e9afb31aae58807e24067f08dd719abb4e6e458bc8aa272d7a5bbd00710c43a1fea220b9022a26b574997517d04573786a4c3e09d30f3ec32f328462e26d4f7ff015121758ce1a2fd51e7f419eb6d8ac04497ab812aa6ba2e981a312ca16c38ed887b2342b0a91348198797919671a23e2b0634b523f931e48ce0d8eb840c54045d9193afec069803901e5ec1108782503cabd0f43373a85acacfa8af44ef2b1d09e4589d2dd4fdcefbf435cb61254f189ad433fa6a4e190627732ae4ef2b0c85cfcbbbaa0137033034e70a3906112dc76ec101f3198e25fb38aad46261d6019690dbf059d66c44e7ada244589c55edfc2e7d18c0ddfcd2d3841bd54d8502763cd0f4696d44686ae3be29ba3063ff6e7aee14de126dc43302f7c0b57d59eb4fdfc4903ccbd3f7309225dd90b5f25c5ade49c14334c0e00fd18b1dc611b10fbbb98c560ad4908842e765c661b9bce005aeede6461254338b8dad3203ee1b58bac1062c7e02e2aa6d420283ed81525839f2c8ff54ac71cc105042c594fb7fd7b55c14cd1247347a197ea8f93c1bbeada1dbf3e59b798c9b15765ab23f856fcf4eeaa5892c3857646bcfd8ad2bf0a15607e0d6696a8548da32955f1f8476f8a20fe4f59b3e9bf4468730b8d46c824a370d37695d1bdcac521032804c5cc66505637701e653ccbddb052f4ecf185b3605d0ba3a4fd99161973e36a35bf79571841ef7506db822dd2a5c959f36418a8dd8acb5b3ecbf3e7918a73695501ef8f440aba43c6e4575880ba3bb83e0a839254fd8d8c6b979d79337a68d218565a5dcb1518c6c82aa73ce7f54a9434ceb5f5fd503137164d74a230e46ce298b98576fea88806bc51e393acdb2abac1da23219b4dbcfba366d834d40dd8e616d214c3478136050555539eba776bf506870c3d20c4a4645b9a7c4ffa976534068009840aadae71f578ef1a325717f64dff840b9dda81b123086a47a172e6793e68af6140b1492058fecd68c4c23db1cc13d2b57f52d0cba89cd4c26d1bd580dd2a054a1d934a80b9eda8ffb503b7e3e62d00a3d075235410149e976529d8029595e4daaae1aa685f3cbdac9b26916320e75b0846d2de8673600212bb648b26e3f1709df425136f33f46129afc90839d24de1e9fee51c685db8a280a5dd4c3ac1539664cc36ffd4537af480d4082146e7395cd6de1f8b652bca8853ec742366702afd6ed79a5920e4ad1317545266f6dbb796ace0fdc731997cd94e1bd8e6689c856adcf153909cfe882b9b02650f4f9eb8620983f0c6b95b3558682d8134a9ec8fa97e174173041115b2eae21fa0b72d0a3c7c2bf9b022fa141a8b495de8321c152b0a9a942c5baf290a234ade4e8b579238a627196fa5621b196ecbe31583517ec4ed82e8d3fb21a892dfd65ccfccd2d36c5d32afa4d4bf201d684c4b1c8c1207db455dede5b908ac63d5fc0bd2b36e11df53bd52e5ce27a9af9444a8cc4391ccc82914b79ba2971ef4ea5d5c30372e7cdbe9bedfcea9ccc8140f8c3ad1bcda29d11fe51affc74f17c9832798e10222701e0d6e93fd109cc9a12df4ee5d38c531574d39a9f4357a60f8150ee509c68e469b4eb0e9be2e6ef9099f1bb949f738fa801d223316fbb1e179b74445228c8b3c40440306e4821077860c37d6b8c17230fcf7ea48d0bb0d98fd3f1f00655e11a8b2e0a7d5da8427784a8fc6d1a2d4d1d3adcc02030b50a700788ce4078c199fc733e2ad469dd9c775d7a8025b4db9b960619f0263b7f09d038cdf85045ac2a1cc5a18364048bf242af713ac4db889489d781ff16b1dcdf66acd89bd6c7651f25a17ce751b67697739dc4d1a125fdd5a8ecbb0cfaf31cd4179249e91171ef3e628dda697afed9d09b53260ae475d59ccb45a6ffd85a2c4241fd134462cf2ec21b51422439aac77954d1b2396761f16e1c6e3242b538f23f584b95cd4b811e35a526748050a7eaa02cebdf8887d94287c99500bf9c2afb7f36ff47e17906534097b02f10620958e889d2392d30660e513c22f580a505314eea4a865d97adb9136c495403e321f425348b56ce8f8e8e91ccd702ade0bbd1efdebef8344bb9defd471ef4b214976556f59f679e0fa39a2007bb9902f5a60ba044c4316c27f6b634241acdc3ce437c4fad599aabba291bfd71c05eca6d9df49abc33ae7709f6622e516c22418e7ab86144f6baf3697bfeeee65294175e5dc9ce5ec82da64537f5f5b83f5a938e41fa8f6f97f9102fda8bcbfb6a5c58f79648b97e948a074e459b9b75a1793cf7d9ca5d7ab27cf7035ece0612d348a23c0fed509c5e18d19b1e659af237c3b9aba4fa8477de805c5f8ccd0cbf3846b6ee1bc9ef76a190952115bd08a5108c8bba76d8d762184c122d081c6dc8b4c49a7f0e16ad4cbed86c6818d4f22c03a100c9afe3675a2f354bf1c2cde1f5e5a63b95761e10d27c9482539387e3aeeaadaeab59faaa20cf595d4d8c57509c751446282581ed28cc55736211e6fabb63d0f299e39ac1cd2af1431bfb03f86e5e59691dffad4e275d4611cb2d7d3be3defcb77907c94db86d989a2ca7e19729e3454eef23b0d58bff8203b08f41b40913f2d2dd2e8c98af09e5aaee76030d8201640d78e7bcfc6c1171e04cb39a6bd060ca41ebbfd090883d8b3569c39fc19cb5d87c15062c9f09138d4e3d3f3421227fb2ac48b224438b12702cb67e2db161a3c771d866c3cc55d15a094f72fe314092e846256e44a1dc513b02bbdd976321f470f81f36e719b9acf22179855d36ad0c50dab79da662e9ea7f9685ec0b44817271ffe2b7254ab7f3ddc389847e17edbd33fbf789bcd604ccca0c01c60deca286858b16dfa17c5875916e0159dfd4f0495c08bf6de51365e2175e47325d5ee71c96ea8ce24c4541886e0854bf7dd8a980aea1aba9add0316f3d052a2eea95c02c241523f3274ee62c883c4ac440d7626cdb4f0aba7a4ea686b2778cd7d7be220357de63cce55a3928aab4c200a2cd65b04d831ba0b54dc91cd6ea410359512130d2a0122f3c9752ba6210ea3b115caf891f0a0a7ef210d1988324a9af926cea8487640a473aefb2e3b4b9259ca4da66089d7f7800f87cb2bd068b8c268dfac897b9a2dd1ff4ac2b19a48b7e95a39ebc6afa2dceca7928ed8e43630d673e5c7ba1fb4afbbd40243ed411b6519420e738c24ab183f900872f10248190358636c789b842f156987d0593fa7cb813f5c688652f871aada7cb5a9c2e15ddedac147151b4d5a7bc4b33cecac961a3487984918868515ca73ebc647945fd9044f3c085b184b3f9d333a7b74927fbbe4a0d846744e0fd6bc36f9381f76422633946fe79e64c3fd63e30096ef400df8cd8c884bad1955b82c013c1a190db92699d39217e46d3db284f35b18b782e791d722d12b85c8a26ac98e9dea8356f9d3ca58833aef4ffd883953f24c96f5351438dccf33693230db5d72389905b49d7308cc30b805fa968532a976009a527bfce9ea921ff4ea9723be5b5972ace8553441a4dac7f0b2114edd3a25666d70c4f94131a63f4521dbd004309157bb32f9fc649058ffbe747bc3addc523f805f1b34787b0f446c9ed1d1966550c7d0c10e342316c6b34899064d0d2dcbb09087ac20572103ee01193a3eab06c06e3206cd60bdbe367af81dee5ab3e5dde9836c558e54c9bb6aa306a609225cf25a65b575fa97d9c962b72b798e9a7fd8192ba879964cedf623d544c8929af5c8dea56721d25578434e2b234289895c697c9c1bc4556e4f6df479a837d1e9132c011e47f9e23fd27b70e7601fdd24f28937efb9e46673b9f56914638c793f5c3b625664f2b221afb3fce5aee92a84d45bab5cda58c49777f82b2b1c8293d727fec90dd73581b087367add474dc7b4cad75cea1e43619ef3fa1b35175f5f0889c031c2083e764b0f4389fffeb307831b73763e73d2c3112adff579d4dcfa1c09d3f2c5927568a70027242e6bec83c5e2cf7e125d8b5e4ad2ec339fb79bb15b8b9a6db0ea9408fc6fb8ca6efe9ae0c8c25900d859b17fc44c4a262c7a5e06ae9e2083fc6dc36bd08d648e9a1a3d8fcbedf12777d690ff15dc7096e7c8b33e71b19005c9e1b20d2c2b6f5c7c1204edc691b389b6ad04f896ed297922bb92b9e6d10a2df2a83dc71c15d2010b595c72d5677017d6d7938ca3538d671e13b8496583b4f9fa59fd481f1f438f92b01a6c5f7169d44b93c0b6863c1a183e871e7f50e26e6d41243a1c509d423309dc886dbb9ac245263ae9d6024456e72b57e17cb08ef00f4fa4dd9fd27de0685c4c6c680ad654e3d81dbb450f0a5e7821412d442c2034093e3fb10234e6a51b98fd388eafd0eec66b42c275a3547f72c7f3d16ed81395e9a2664faacdf99bb22327280e518e4ff047451e6f7420b562c68877c96e129d0cbe18896aff48d49da028dc97aa0108da9b29c540c5238d676dccafdf463694aea34ad4f513b6c7a58d071c335ff1313d41b7cdd902904b8c9fbea2ed34878b407ebb8144f603683ce4ce61eb0690a00d492978aac3a0f3010b7479667811c3332c06553c14809c723316c84d084530e93a63bf0b7658f7bf367d29577236e23ab658a685f2612f0216a932a24aa4f70b8d0609aa9ca14e4d91b8ed9fb62864ded646012ef675ea359117c07f528d7dfb742aab9ac892851e97c94f72d5c34d4feebc7f67e09fdc6f633f050833192f15a7acf4f8c8beb3adf3860fb26fee39a416ec362e4b6d9ced09fa57b3d5b7fb7de018e4fd93eb65634c08f6d4f1e2f490c2a8b1be2794a27de0dbecc9949fd1d5eefa0fc6f0033a2bdecfcaa267280b445e92385d2edd4c2b31bdc5d54ddd6cb30b3c370a893c217945d346d1c5b8b98ac754a01afeba6f5526939ccfe9f2432461a99c7b9b44a3983eb65fb064c32f8c72e18b8f6e42e72a1bac21b3cf94526f81089b235794412d1aed20f48324d742d4079e9546f495248cf7f42839852d604598ca2079fe44b125ae9970973b57c156e83fabe6d64c9aaab5c243d1dc71520d45317b913205979fe5bc075b0068d8a5ceb7c8ff9149c763c22b08d35a09feb8156bf7d8eda212a102906e251efcef1ebed894556f18444a0938b4c050f2b873505bdce97cd4fe539a944b94e281292f38850dec9e9f108d3b2d5a83837d114bcb3d6e6511629f310d194328eb05a7b88e7a053e97dd92881c89a1169e7d23a4fa1ebf532eed2579fc4482b9c93da2b5e9619f289f346160996cc61a3f380ea71b25e777af37dce79039cf90a2bf16ddd46733fe9c1cddbe7a42fc5faa7869c96ec463e9817495bc24a23cd9968213927522ddb0d6ba5db92f5736a5723135305a6c083a9bb54da7e43da3ebb07066ad94e597706062118fef17e9e65363f71d8859d30527a495f06bb025c1d26c6fc80e9b140c7108c57ee5583063bd8d2a7efe6a3026a79f2294e09ce980be8ce1a017132ccf48a63eb32454b12506a6099d4e310f07612e77da46aa0caed8fb0446fd6091140db2cb1432bb93cbf681cefae9d849fee6b0d87898d52d31a209ca6f168b6305011e2c9a55fc5ad2237d7c2d06b98e0703ff2a89fc7af8471aecd2a6cc0a4745082db863bc8d46209d51135333a03b328345b86d6cfc23d6d7384fae5d8546f05725ab139e2c25b0dd9b2113b2774391aa058cf90915bc97a94e74ca0ff6785243122f12decdc48aaa8ff27200007f35e928e62269f7f07407802c9a10648a91180d559c5c37cf3f425c9949b9e38ce4c99b71810babe45344d929906776a66fab175e20bc5930f1dc4b5b888301028b6e0f92293e468d0c6b191f0840ed822c036e6257bbd4f0db8e931463826c0be855add67bff5fdc6d4de7347fa07e63d68f4b6876774a39dff1ae927614f8a879f128713e24b263850f1ab3176ed0e9ca9369af947bb8e862e927cf803ea7b53b68eb8c5f87f1cde2399122b7892ccd4071610f0873981ece2ed719bebb0d508037e46b95610d14e9a826549cfedecea1d32074aa439592929873b49d9434f35646adeabc8b52e323ec2dd6d0d6e27b530361fd8bf9e4e3a0a58e3079dc63156a684bd5cde53ba8c9c51da274bd61cdab187a3fc0a84d5005319f05fc7ddbda575f73f3178336413f8ba0b99cbfdd5c350a3a925260284d75fe06371716f951d76078df7cbe6f25beab46b8f4222c74f68822d6747314b688839540d3bb9bd0f45a028e780fe2b5c78e28dbce66680f1e57b68d6088101146aa9f976bad10933e4f5481444a46d40413ae5d00044a29dd3760c712c04771976280f793ac5bf8cc1187976096e4620d646358f207a9166b9d27030721fc00688a0df926e6f4944ba6e78dc862a8e55e3d1a20d2993d8c8410548e9bf1b6efa181daf8bc060bd1af3dbd8853d6d3f54bdd1f6270b20fcf7f90310109b98f6b366a4ebc6f717962e408bf865d0128fc9ed607f848d376ab1c50e66152f74916a28539a762c75387d144bdaf4a0b8b0e7baec532e8d531501674a8727547916fbcb2e45f9c7d41063bcfec3de1b0adee000e555397ab16fb0977a8c3ac1385dfc89eb7db5cceb9109077d36ca9ff5fcf9feed6b985693746a95ba34f7d2875f61ee8606302b6470f8ad17b781daab036e288e5ee083a3a36eb116a34f5ad97e1675181818289f514efe868feeec3b48b1a574b9405668aa536e572f0e2b46fdfccaea5b2f65285f6a9a05c020bf440f5db912c8ac289c67b9d724225eff88366992f08711f35112e66b765872d39b54cdb5c4c0719b2c17dfade7e2f19281e6ae7885708ee8a8f6f90ce79387e6e47b33f15f212c5b386a5aa5f93cb597698dae4b5999ccb4d652a08c41ed27c45d2ecbd112a679374ddd6606ca76ceca9ab08f7f648d248622ddd633dfc121f9470930ae058cfa9455ddbd25a38aaf48f242ab6e0dc895c5b2af0d9ab0c996df526f144cce6297af5f3ac5fa1d159f52e072b827dbd273afcc6e3b8fa1151acaaca5965a4b6cf5b0ea6275da3208159c6bd6d716eb61309eb4ddfe1bbc4ef8d013d477668cb3506ebb4724ccc72affdab79dcdfaaee55a5946b4a3f768dae9fedddedc6c5712296f26c025ed2ee299cd15b1e692c616094f500fc53fcd9838401c0ea6b6ccb883c149a52d875501ec2e647b1d6720a8227e33cbc1f429ef60103f3334e3de2e40ed4a59d811b8cc51a695de25ebc66eca519222dafa22dbca634220097b1d3f9aeddc91d11019d7215629122b4dc6e3211ad842288b581c31e44fa79e1f7855d8fa77e7a224cf571aa3c16b5f4fe5feb16d7d1bdecc543b0e8ff01c677ec6801e87241ddaa02a5c83bbfd1d84c62e269f6ce8a708e693b86d8e5439f129431a4c1c0bc6ad47784c38e1cacf6c523da23f65a76c264b96aabb50aa9e299be6abd1c9d078ac3b2c5f2c3986b5707f143513b4ea91a2052731ef5b48780dd0cc6626a0f0c358454f6eb36df7caee6f8dfb3ea19a0ae79c0d1587140147be3efb2a0da1305d5fe056010c518e3471572d889304c4ce00acc78fed04a4b888d5e7e57d6cb5cf4e5cf1f8782e1b25ad948eb3e443db75af9233aaaf6659adbe0ef33d4b3ba5214b85e656719df2eba42235b2e268f80e3c5971d28957f8e93f5b04a3d5eaa607fd4bb838ae48661bd093342762cfd1ed60b21f04f5b95c3e5426ca6127b04810e2ee25bb56ae81d7840328d8d4f7d1bd341ed58b102d9860806f4a4d117c044f472c85ba422eab084faf8994cfe0a880bc46dc9c1a8c11995610756e2ac50c5fea8ebbcb53dcc76b1944ce364f8878f42310fe0f8cc211c62f627d12b20527dfd84b78c98b1122050cbcbdb70e08010f68294a6a805d3fab97e76cd695f918e73763ac2c3dfe4a8d75db87dc37e2399fd854f3284d29c7bae3d3e31c4375ad9e047f03a5204c2ba93b6025c112ea2c9fcd731e380a8aaa42860c859c2e2cfd333f0bee741e21f78776defea86e862711f0d0bbf64003ee848a8d1a12dd00c024cbee343d1093e653555c033c198401caeb951860392b5b1eed6200828aa310ed466e41d855dc4231464adc2b6b6fd66e03fd42736fb791387efec28b37d0686272a6bb181a621aae7be06866bdc1c4be69e94642c8d3782f5ab7cc8c890699008b52a11b149a517771b93bc2ae597dedaf0237ea8d9674e26fc75c3b468e04e2fc317d03484a75fb274f7ba1617bbb72ec16da1fd4109952d052e9de7c00761736dd17e70db0976692626ccf8bc9e88ad6c25ed88a2f7c2750add4ceb95744f690ee5f2fa423a2b62ae57c1105958bd8e81025c9412fa71f5d1e81bd6cffa01f489fab7e90ab8a3c8aaffc8e3d594beb254c460347196473117ec2a416dea464eaff95da6cec26b5535954901298f11932ebeca52aded139f2d5aa2c24174e2f6c701ce1f4564c60861ce3b9cdac1cfecf071295c5ec581f0f075096fa457373c124b6c8cae3aaf915e4701ad94ec9c01e5ca0552019bd7f107a7d5afab9e4a5e7cc7b4c5416656ad064f4a0f89afbf7c5b884b69a12fbce8aa73a49b2e5c5728c67a7396bb8341afdf52213b2f7f8e84962cccbeaea63a3c7b24881ecdde39cc57b4f211cd57c6f982217758042f61b648496e62b612b7b8bbe1b9f15d237aeac42b54d15166b5c71eb27ccca1fc9e050adc62a267eb82ca2144ba323a73aa11e2fdaa87695c70316754faf7aec44a49b668362b0b35e884019227e7b9a35e8841e64e0009c713d7f3e4a74cc3feaecf4c99b8d0ecd85c8ff89771b63a38e3af990641f28fa7e4ea560577d600f43ccd467d6a347fef04d392d42f8e97659348c68b41299f94db4b713d61868adbd20a4db74f61bd0d1e7846bfc8b8f8bb50bf50c2fbfdaa87328933741aa2b1ca50cb759c1276f1a7930952ed656921f5ce5569ed16b31b2a1b6009c784199ae60ce2e35d573808a195974536f220cd14dd634bd06800435cf1219047f6246c2d9bdea5e489ab4862f0cb0f01439ad2ad1e2042b3f63b8611a87efbe842613c21761de4c79291a8491092c20134252b8e900e5d3cc70e75d32cc41452c5c33b66087213c34f67ae73fd56a183be858f1c3bcd73d814bb9e3f78cd18992b0ea401d8f25c3b60c055df8e6430b62899bc86167d0b5e2bbf16d75bf3f2b94c26542202bbfa0abe99be1a07c78140f42c12f51576007bb5439966a47cadf5c4ea624a75e7a4f01d8733aee57e3497c013de4a33cf54a94acad9b1aad837865a6881db9a725310eed49581d2223f2b0984757bf3fc5122c5dd572ecc781b48fc508122775779d2b2849e11684a585ce844d21352f8d35ea53f0f34d772bd9ca76cc4dc33aa3f2e72418c097614fa5260eaf3c2d724d3599dfa0991a9c0eec9c4d550886c85e1ab2541e9868a36afbe0d9c07c93e44c4c73c66f88e770e5d4e4ac331fafc6870c928fca85756c444c6e8f6cf75865859abf0cfecc8e89b8c806a2e6af7cb752215bec6201eeb41759b27d599931dc2ae75d605b3e387bf263ebfd09ce2154b81479675555ec74ad85150f8eb8c1b3c4f31f6409648f9c1b4678c82e8e2afa9c887f3210afffed160d1634ab0259e1bf5565d8598605a435bd289afbbc12034f67199b67bb0fddb4b9180908c483ae5a8eed16221687e1f524d010ce5db78d1b999069f225479fd6bf0681c7ee95d4665925bc96399989b85284087e67d5a070f2713feb78bcb91bc019f3f19bf3abb7cf36ebb98f09fd64b61e2bddc9ae6335da48ba85b62562726e142bb9d9e5c8f278dbaa0657dfe3e410f03211a072555624d98790aefe8e7b0281ff6af3de79dd5a414632f9d4913a480e9cd6990f94350304f853ba5679a4cb3a647b98bf1eee6cf70f77581a1ff82a9ffd7296e8fd172d37b1b0d1621692cbfeff8de18658f04af5d5be08bce66e5dfec5989b674219f9ceb6a1037c80a8febdfac63d482debd34c3057a677420f0bdd66e2c2b25a9c1d34b76b4a998ad3ee21d1e49f812422c83016c12c201ac2b0f07ddc00638846f215bfa6c575cbfd577178eb0282ade2c459a13386f5dee8a7502321292a7de077f4fd12967b8c8055596e7a43287639843b6ebee58d463fa044562ec2da7f9c2a7f28cce685178eddd3b9fe7b10202997b6b170555a71555cfebd06cba6bb019f8cfac2ec5db3b1d1ca88acef9accf76b6a74600e590a0eba1c839d6a577d3877e7d6d010b04fc58e160ec9733bf200a9e0b24fe8ef32613cf2c7b1515008b8833e34d3967ccbc8bbe30fd1810f23bb153b814392eb37d8917e96260b3cb16895ef13b96d72c81a14b908224571680dd56d04a59a6583a232ec58e8cff16f6428b5e3dd19f362992608aba912b642aac9950777627ffa4eadfe9f31b73c3fbca11d2abb623b732f3d7c296806151257c9f2306dee1c84eb05d586e7a82a8750905716b3e51600250a1e3b4bf274130a1bfa47117cc8b6db3741ba04d977015b8ee250c3ffaf859fdf0372b88fec188830b5870f251889584333547f3436a548801fd3236da2ccb2b504f85ef1d259bc3e00f0ced934a4b297ecce0d668fb3ecb524d3ff4380a7856c7060006de31931d0b26ec1d084e0dce3b9a123741cdc326b441131d777799623c6340410c331c7e8a4a8175d7d250274cc4ffebd5d46d855bf90842888893c348f0a447998e3aaffc81c9b65e3a772eca5c2f0907ee13ab6a2babe99f388755fa3ac9dc79a2ba4ad7a869a876448ed1d4dd6a8c678065cfc90df8470b29c83719bfcbec7c5e3244a665a28593ad42ab84663bccf570a8e8b783565f909b5e6e8cd69ed6f79fc945ce5d845c998f25b9dc118c96dd2c0f592a73497dbd9e050632c8d82656a71460d0ae7f5f38636692a78083b2fffaa517dc2dfe18ae020e6a5562be54ed9046c7129b3a57dcbd1917efb0579fa9a3978690fded8e52e4860db75b2a93c77316a6e84df4965291a7531e2abc0fcc0d0016acc29680baa575cb7be1a03206236310eb5120ab4069e0f8f0cc3f6bd188ca91963eafc2bc66b1a42f8c49359cf3171a72eef94eddd8aab03f770cb2f489aece4e09a85fe6b9790ced5feced19e4cfe6bcafd1a5d99fe56b78f7a14fdea11fd5e331e23191a3f74b32d8ff2740409f346aedf469eb8aca16b43dcc44c400ae3e6d1c4717ae1f18a2f70830aa0c4d5734922374dad8c006ab97e02a4263999ecad0b1e9f24ed0b599467c962932ec610e63c0b3ac845f5d4d10979c92bd884669908696172609e0da039728baa1f0dca8885d5439ca420e87f5c449908b2a5f69b65b60adbf5d74b21eb1f4e0d79558c59b4499c245a9952de8d3a51021f2e77c44e06a489df3b72d28e5d03ddd358ced4f5a1fe057e58b86f9e717cb9001cec6d6665cc0f5b9cf89873e6e7d10355746e99494766c937683684312b630337d1c411f3f2eddc52a8267e19d38ee12c810cc4e33193e26790b13d1847c56282ac86697996daa386b06ec2ceaa97fac9c018baf644622c74546177267b053a82292c1a1cf194909beba3f2670acf1d095b0caed4b8da2fe48c9da3dc61969d938707a62ce9cf55b89ceaa04a9069d38f4e89db794a335933c5b45fe215976e76dc71b7719c2ef29d06d2dbcfce0470007331a221dbce6baa3f418f989d7dd927d343152ee310d084799300e8d3801f9d464d9bbd5687e3203cfb8e589fbab39ad4851b07bd13b29d7f4b767858d13c5937a482207470f673593aa9abe339b3d63b7ea4ad60e51e7f9080381eb07213ad1996ba7bd28f8b44b7ea037e0bf9716f56820f908fd4027249df11aea06df25b3860cb18b68a7df5ed0d14730035291346049e1e5cbdefb30719548fde4f986bd9871a71b5bc7f6e03ea4fcf1c6ddfecb06413832ac27b08d203070acdaf432bafdb288908dfd673caddbfe41af8255ff7106d39db8d003ec1abcc3000bd7fe1daec2624bbe8417f81150f20a8a48324100ef1570a6de7c0a21e16f6991b23016671bc96ee55e99a97a5a0120af8ecb816137d5f40b9e71d56cbecf61569dcd2f850ede77437be06fd85b54d7220b9bcd13e682a8227c7a05a4efc8d258b0331b0f47cf45ec370b491d6b2e4e601e50483480d9437fdf570b6be69b28b964972fac047f8aaecbe567c8ee3d583a46d5b58fa3c361dd3ad73c91727e4d0594f428acfa977206c20995612834497928d507eb62aca1752a8f3048c932b9f0f80f7c627a87f2b50d581961b8739bddfe2afabb1c757f366acd1e639de808409f598755dad254c60b5aefbbdcbad52f72c756e5e4b286a6866af769593f66256fadc939d3d23d1db9096038b40ed224ace023f2e3ea84fb4092c974cb44ffbe489f0ddbdd79e66281ef9c44e81781b849b0d3101c17e54ebf8bd69393b9220c75c7d3c564862ef35d7dfedc855e2ea15a6159c6c2bd01d2c4f3c316ddc43f937cc295fe35365a69ffe68a2a3bfa7eff90c2fe8563f6438117c31ab48cbd5a3ef1c7a03a03a048be4a9fe0de1d6a86feb144731f4e84f1b509db65d35b1b8ec3d0f462392da10694b207ef1d9fa2581b572f9c45012151f039ebed848b3fc211b2b4d6d48266e8bf800e68cb1165cfb17cb14af4fff107e57bc90b9e32006dd090ae12ff39b000c474f77da32549f51d07bb23d233485be9143c55849b5fa241337c050d48d88e4723f7f1032120cb609c584cb10cd777404556df84cd095c4a9668d392cb9a6197ce04e4234d48b47f8deaad83ee95292c9a9e9d42838c12e34046483ebd821284ac349fddb3d89c0e9a85716ca5f2c60569686d3580c6c7bce0a0ec4183fea724ad02763f66f85992fedf49c67a54c8ecc5b47d6e00cfeaf23b2425b795be93d65d92fe0ac761cca8b2feb4fd7a4bd21bc98a7328f178a61aabc2edf843e23ee94c757a457d448f3588b4e39cb14d855c35372c2060966df0e3382afe2d18988ee7676511e43afae09d6e16b50bfd290c1202c5c82520bfadb7b9eff22c2e9d202e7606f23182c08f0d405cfda6e8bf4b222a14a96015602cd77b2e0af5027938348075115b146166990bdccdaefa94626e140f8ea6fe6b51fb38fbf7ec39b89e68174db08d243a5da08a573545993db451bcd7462ba2c308849e6f54fd68eac003dff1971d19a00ae1d326d9db706197ce15397066ca114645ee39bb1a950c068908be503b2cf3ee74048dd92808e07172ba1362b3ad4103953c990e19b4581c54b5a240d90ec56150fdd5d9d1e497090941b541a9fa202d09f2790bd29f53fcf2adeddd4b4ecbff252921feca36cbe51e5185234641c8df314dec556280e408ad6605cb82f9fa5cbec32b2d478e876b4c3bc5019c344ee2f0bc33d26ae3b69e349771a8069f38f879d82e1c68f84d44516db921ca606b6e310e9ef0729b9fc76eaff94d3e44f865a6943eecc5ea1dc097e69e91344f7b287223fdf25ed3512e1fa34b0879ade1a2786571435e71d3fab19a6ba93b5d83e20f05afba10ab48ddee2c6feee813635318ac35bece3a339fb5c2278df5b9a6b7859343ff5530a2dbeda669a47a5eb0efc46c148ab00165563023536cf71f189c6b855ca6aaa056233ba82edf29e82d96c6118a0e6bf37d2ab2945ed1904f1dfd19ede3dfcf257aea6d560e3776159ffc384b3540deb1cc38d1022e530c2d46557a21eeb744ed5c00843f7b6d5953f1ff4770d26dde34c4cfbd308074e0df53264afc5a3a7ab8a57dae296c39bd72b88ad988319ba9e13ea529783d5c926d2f48599720695fd174f8873d0f660f002d8d0ee134271450c12e9dddb641b240795c2c09b958778e16081bc9180442c45fa916de16c83f16c50092eef58a56191bbcd906eb475b97d37b7f5cb00a79a9ad66a636e1052f9dd1e75d02a5af4840dfda7eac68c749bb857675e67b450a484d3e7b13a77fdabff0e97dfb705e5f4f6cf1e95a5f6cc38e099634a020087f868580ce2ec0837525b8c58f08444d7fd4333a589c0356de22568b4fad8766ee3325cbd65843f2c713ecdb44c96411ea871c039915b546ed6fbafbd51805ac48d06c6924d3f7036e1814250f50f27342c8c4ded3e68b6b3f161d46379c1088a7a123f48f0e7cb5a348f472eb155956fe232fd301e64f341041683ce3b25bba7f290a10282a8dba3a2a3da24461a5be148c2241d627889adca5acad981583fac81d0ee4ef77038c1f80db9dfe740720904512691a9c8545a9d173c08c2e8599010c972c2c34287d91ac7803a5700a0d6e29b7774f8f487b70cf8d0ec9474443e2c0c051116b16aef491c3945a65e6ddcd7931a7259e56902a2866b95d3c0bb7a3ea61b1f3b54ae56e6a7366ea895056ea0d1c251cd74f7b82b0d47464826f4aca77434df3d909271a825b57890cd830011981d95229cc0427cdc97758ddbc76d6cc77ba06c92d19daac8bbecbf55535e98bd4754ec06a6e632225c43bc46068baa688636eaba53926ca093a7addcd6a696a902ac35631aa43d9d66f77270cc7bf66140dac239034ba304e1aa0a265131e9fb2b7f079861b0e4cb9c911ce82ef0b685002476baf26401dc8cc444543129f82ac6b103881c596b19d9eba8ed6b230c17914d5c34a0040c18dc54d8c4b637ee683637fc5a82ac1cf12691bb28fc0bbb307fc032ec3d2b06eaec56ed769b5e892816c7350dce89551e87918f67a117c39f256a368586c78c2e9614e9658161511a8dad53afe8cb9eebe67c6596a90eeea1d3d2466a4d77a1129c0a4409b98d8ac0b925c4b2b3500665a3cf4ceb82cb0b6732eea8a796f9b79d2ea49be97066bc1f606d9f1f59f41d2acbb878a0783093fc4ab0ef866ff60a6a1a58d3cee90307f09247b5212f8709856251ff5d8fb77657110bbb3f3aeff07898f049c821a82c11e27b0c176a9feb12de5d08498018f7607156c5065cb56bf9d6867a4495f26a07e0f01312c2ee897b82d8eba0cbc473da402814dba727521cfec6afac2cc59cdd6a75e1f8f40585e5cda51a7434a81ccf4b7de33c663dc174ba973cebc5a56831005d231c719ea34ce42999c471fccfdbdbaf1acd2f9c16f258e32c70511c475ab264173246ebf31459a05ecb4df443066b61a243903e80ff907af17a96d7afd9763df8f8c4fc49775bc805e2dc165bd6f1c4e06688521557ed9ddb6860fbed1e32957bea1174b3a9aa809d7fa6301fbbb6b3774cd856095f14c6378cfe98f05d4f06fae91769165dd0adfc51bf8f57d701ef14a99d608db0a104ea78fe5b13794cb8529afa5352d1dbc8235d96148c8f9c2e29d6e2359a8dbeba56c9376b26f8384c66548979f4d982fe0652cd86bb60e6f2463ec63dcdd5f93d4bfaefe48f8012c63b32ad3c02ec9088896f6a0c8b1097c1ad911ada7a2d6f0d201a28b70752182885464dd688535bdfc045e8dafbe34b20eca00848e757b4a37de219be5a5fe7a4bc5cfaad29ed92e9eda2bed08407e0d0f53caf6b3590210067d8b9ef16f9a8f5612315dfa415f1efc8d7349394143a149480ce3ccd60ccaff0d9a8a797820f41b431ce3afc4adb2e07cde16015087e09e08bd13471dee960db35cbc3b53c187a5bca7ed50017e09b2ae2c837b1f6557753c7f5b004332ffa2b52d8a2269e7cf9cc397c6079aa5add61d7a560a894e71510e104f52a93622e34037b1db70a05bcfc546ea2ec7153e69a8df18fa9eadaae2c1438710477a9a23e0f7092c310c5288e2d39d362a0a33f9e3d8d9792b51a71d9014abcff66ee509baa3dad341b1e4b6c601a2966f77172a4df0f32170f3386a6600b0b63699fe21e26eeb475507e99f666e0ac349b9e23463450f4fa4498356887d9e1c5f7d18ade51e526d27ccae799d6775336ca9ca8e54d707639ecb0618a3c675533494e2435c0b3780a66defddd217d2cc464014bef8a051d8f292abf9e5cafa78c600c21ed3d40ede937b1e162a1e14757d39d77d4fad8711b6b46ae707b82ced0739f9fb6bcd9b557982e89bb3af5f3fb5448ea960f454f4475ee78970acda37501a8825a04cecf3e544651eea8933379da3c3e7de0a875d689003c00d276470fda3b6ed6473cf8094ab91784d1c0f9468379e8e9729dc1032a5ca14378f8147409f13cd6994de961e2245b35c814596087625d3d3267fc0c1e5614a4af94993091ead40bc9e1d3093228b70c188855ae9e914b15aacfd4f83fde83072af92b2cc968c93cac74e15322eaff32a7bbbb982fb725aeb71f34bf16323d9c0a11dbaf3ab676a9cd1dcfc3f8a0c66d1f082f23806133002c50b59d4513dbe3419d5002263287ff47abdba0862341effe669f26b375337170c8e0742113e1063e8141c4aa9eb4970471f3187f581b71e6f7fe2f8043d065620da8a066d112fedeb33525eb1061c0d0fe9fb415bddae8ed2eb5c3ae6aa0549230e436afacaddc389b2c66499d7fdec2090e7e13560ca0a64803554c7cd9cfcc1cb48427cf9ccd954bb7446c887e2756db2882ff12eaa64efae3a24b35d1d0402922efe90319510495420301d3360f4486d3f87e3dc4f9337bf3fb4e3c6a82850a840153a1936e7cf74086757b72a8db19d33a62a29f3dd4fdef454d9222031aa0958af21851b66aebc09a5c08efd204f3ff18cb1055e8181d6630309fcc91c0d6daef19e618a3ee23e817a586d02364710cfab0b9f2cf18502a34e67d112f1730d44ccae54dc221d7f3877bb828e7109878109f8e95e2e1407df4e588801d25d9c2a1c501e74890631e9a92d823ebbe6b5635488f7d48788ef77658e3bbaf287536b37d3a7ab1ec1749656f2ebfe562765e71dd3e1b895d9b5c315fcf2b3a063c57e74ad1e7586b293ede4c77732f38d316c14210a121153fc50007f78ed64a8e207e9d04b312ae7f97a946c74d2a1181b67e845c3ac6e340b2428c8a5546679707fded3406fc221900b118a3279e13b74926c793e27fc4cc32ae478b4421d6eef75d3a273ff61d0e95b4981e8dd57e16bb00e09bfbbc2ce60cd844a9abb839b8b671fabddfd6e86a30c0a24e73c3c17770f34641951e5dc73ca11d8f8419a7407d483e0f5f1714df0a1775574b5500e8a5a28c655dbc28d7a1ca4b83fd4ebcc7ef2e4994c97c87659681acebe7417328c8612e8570e7ade7ead7f4fc711c9c539362779e6be525bdf5ec037f670b5235c06a1acd89b4ffc21668a7269cc73bf6d1399852eebb8b1dde8ef072e8d80832ba32c8e9480da2c4f5c3209c557f31beef41c00d22ee7c7e2c1bf9952ba8a03c1afae9b4aa63135d2b131f2b2804afcdcc762e1bcec8c8151f471572888933ce97dd787121ced446aa9718bf3766bb6d8a752692c59489d5b565e1693aa0f67b352f915808e415cba13a9864bbd33ebc97dfdc0d357d6769f2f545cc6529c0f634da901ae63bfcbab0a3896bc43faed6a6c23bb4e92f3d669d2e0ff485287cce322b98d02866f026cc556ec8aba6608ac2b5dbc29e104ef2e28d7b51ce63110025bdbfc5d44e8aa7a04ecece07b9860618a162e7289e8d672bb9b15b6ffc87f738b0c7a2b733c5794afe58b1beee4b6780ed453bf2ef2b584dcf32bf732c98fe359abced05fc115e531b088c61b0d5d5058af10120581d7db192e13a5b7b17874f000343aecc8d5005b91b13720bc831de5f1de5e3ddce27ba05213cd126a7cda0afa9745f498200269a5736f63b0faec36bbd646a868100c17cb7f6639f2f14b6c52198fab04c1645bed8763799acf8fef62b82fda1825a3379c000255002788d686695b4c17be3931e69db8980d0216024e9b7b0588cdf8c8102d11f55f971b3163c392cfaa796e0b85dd0bbacd6ca50b3ab80c2e90fa0c18d3526e05b2a46c2eab823c0511b43c71122d533e27ee6d6e34706fc411c67a3b87440a3429df3009996743ed3e4dc244fac98a789f17818a926a0aae81ecde260982b80acc299f57a570a86ee28d0414edc91fb6d5f9a88aeb31bf22270bf3517aefe1140b05be97123cc43df6e8e8e4df96803fdd59715c87afcf0189fb5448663eb35d2c4e5b13dd0233a95f8d6187bf0d5d3ba35adba59e162e877d5a0397d9495ebfc771ae68283be15d883e91b81b1bb0cd8da6c300df7e2bc8a21094cadc974c8270d8ee37fc7e7501a57eaecbc244ed61cfc8d556e38c0611a5269c3b930ee5f37a9771f0c152a5e28df07a104360c973b9a83d3ec5c0aa012bff141842e9b68222647c7d022753dbaae024877f421ff36b3721c26a39b3009683c8c510ba0ba8b5dc1033f9b56e9a43b3141a92599378622a2ca8136f5f1f51cf7b7dce7d043f65f8562b33c4864adc30e7d4c808b10abbbd92f94272b68b063f7d7baf7fd6eb31cc76690042233bc8dee7253f89ce23de7a535af022dae95ac321694d6ce311744d9c152e4424a0a502d221b2e602ada71c60a2f15b7086d75867476b0633063297681fbb0a3e154efe552cdbd9d3203f2e447b60b643b823ea12f504f33f6b6c3bd20e54cf38e3c45c5d472814db60741687894e6cc3c78196d5e722499d202334fb742f14dc2ccb7d114ae0c4cd61ce2ed0cc7fe25a395d6b73c1dfee9174e59d129e7f3c42f93a246d918028d4e2dc804438799 +").unwrap(); + let signature = manager.sign_transaction(&address, &huge_tx); + println!("Got {:?}", signature); + assert!(signature.is_ok()); + } } diff --git a/hw/src/lib.rs b/hw/src/lib.rs index f51be356ae1730f8a8fd1d36e408fbbf7b977ddd..98e682a305bcb6e35970b6fae547e1b5782f387e 100644 --- a/hw/src/lib.rs +++ b/hw/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -16,8 +16,8 @@ //! Hardware wallet management. -#[warn(missing_docs)] -#[warn(warnings)] +#![warn(missing_docs)] +#![warn(warnings)] extern crate ethereum_types; extern crate ethkey; @@ -25,30 +25,33 @@ extern crate hidapi; extern crate libusb; extern crate parking_lot; extern crate protobuf; +extern crate semver; extern crate trezor_sys; + #[macro_use] extern crate log; #[cfg(test)] extern crate rustc_hex; mod ledger; mod trezor; -use ethkey::{Address, Signature}; +use std::sync::{Arc, atomic, atomic::AtomicBool}; +use std::{fmt, time::Duration}; -use parking_lot::Mutex; -use std::fmt; -use std::sync::Arc; -use std::sync::atomic; -use std::sync::atomic::AtomicBool; use ethereum_types::U256; +use ethkey::{Address, Signature}; +use parking_lot::Mutex; const USB_DEVICE_CLASS_DEVICE: u8 = 0; +const POLLING_DURATION: Duration = Duration::from_millis(500); +/// `HardwareWallet` device #[derive(Debug)] pub struct Device { path: String, info: WalletInfo, } +/// `Wallet` trait pub trait Wallet<'a> { /// Error type Error; @@ -57,13 +60,13 @@ pub trait Wallet<'a> { /// Sign transaction data with wallet managing `address`. fn sign_transaction(&self, address: &Address, transaction: Self::Transaction) -> Result; - + /// Set key derivation path for a chain. fn set_key_path(&self, key_path: KeyPath); /// Re-populate device list /// Note, this assumes all devices are iterated over and updated - fn update_devices(&self) -> Result; + fn update_devices(&self, device_direction: DeviceDirection) -> Result; /// Read device info fn read_device(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result; @@ -92,7 +95,6 @@ pub trait Wallet<'a> { where F: Fn() -> Result; } - /// Hardware wallet error. #[derive(Debug)] pub enum Error { @@ -109,7 +111,7 @@ pub enum Error { } /// This is the transaction info we need to supply to Trezor message. It's more -/// or less a duplicate of ethcore::transaction::Transaction, but we can't +/// or less a duplicate of `ethcore::transaction::Transaction`, but we can't /// import ethcore here as that would be a circular dependency. pub struct TransactionInfo { /// Nonce @@ -163,7 +165,7 @@ impl fmt::Display for Error { } impl From for Error { - fn from(err: ledger::Error) -> Error { + fn from(err: ledger::Error) -> Self { match err { ledger::Error::KeyNotFound => Error::KeyNotFound, _ => Error::LedgerDevice(err), @@ -172,7 +174,7 @@ impl From for Error { } impl From for Error { - fn from(err: trezor::Error) -> Error { + fn from(err: trezor::Error) -> Self { match err { trezor::Error::KeyNotFound => Error::KeyNotFound, _ => Error::TrezorDevice(err), @@ -181,11 +183,29 @@ impl From for Error { } impl From for Error { - fn from(err: libusb::Error) -> Error { + fn from(err: libusb::Error) -> Self { Error::Usb(err) } } +/// Specifies the direction of the `HardwareWallet` i.e, whether it arrived or left +#[derive(Debug, Copy, Clone)] +pub enum DeviceDirection { + /// Device arrived + Arrived, + /// Device left + Left, +} + +impl fmt::Display for DeviceDirection { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + DeviceDirection::Arrived => write!(f, "arrived"), + DeviceDirection::Left => write!(f, "left"), + } + } +} + /// Hardware wallet management interface. pub struct HardwareWalletManager { exiting: Arc, @@ -195,16 +215,16 @@ pub struct HardwareWalletManager { impl HardwareWalletManager { /// Hardware wallet constructor - pub fn new() -> Result { + pub fn new() -> Result { let exiting = Arc::new(AtomicBool::new(false)); let hidapi = Arc::new(Mutex::new(hidapi::HidApi::new().map_err(|e| Error::Hid(e.to_string().clone()))?)); let ledger = ledger::Manager::new(hidapi.clone(), exiting.clone())?; let trezor = trezor::Manager::new(hidapi.clone(), exiting.clone())?; - Ok(HardwareWalletManager { - exiting: exiting, - ledger: ledger, - trezor: trezor, + Ok(Self { + exiting, + ledger, + trezor, }) } @@ -240,6 +260,17 @@ impl HardwareWalletManager { } } + /// Sign a message with the wallet (only supported by Ledger) + pub fn sign_message(&self, address: &Address, msg: &[u8]) -> Result { + if self.ledger.get_wallet(address).is_some() { + Ok(self.ledger.sign_message(address, msg)?) + } else if self.trezor.get_wallet(address).is_some() { + Err(Error::TrezorDevice(trezor::Error::NoSigningMessage)) + } else { + Err(Error::KeyNotFound) + } + } + /// Sign transaction data with wallet managing `address`. pub fn sign_transaction(&self, address: &Address, t_info: &TransactionInfo, encoded_transaction: &[u8]) -> Result { if self.ledger.get_wallet(address).is_some() { diff --git a/hw/src/trezor.rs b/hw/src/trezor.rs index 044e5487b40a9269abb08280af04ff5b68302156..efd259d7806f456a8bbbb04b6ebc10f1759b9b01 100644 --- a/hw/src/trezor.rs +++ b/hw/src/trezor.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -15,28 +15,22 @@ // along with Parity. If not, see . //! Trezor hardware wallet module. Supports Trezor v1. -//! See http://doc.satoshilabs.com/trezor-tech/api-protobuf.html -//! and https://github.com/trezor/trezor-common/blob/master/protob/protocol.md +//! See +//! and //! for protocol details. -use super::{WalletInfo, TransactionInfo, KeyPath, Wallet, Device, USB_DEVICE_CLASS_DEVICE}; - use std::cmp::{min, max}; -use std::fmt; -use std::sync::{Arc, Weak}; -use std::sync::atomic; -use std::sync::atomic::AtomicBool; +use std::sync::{atomic, atomic::AtomicBool, Arc, Weak}; use std::time::{Duration, Instant}; -use std::thread; +use std::{fmt, thread}; use ethereum_types::{U256, H256, Address}; use ethkey::Signature; use hidapi; use libusb; use parking_lot::{Mutex, RwLock}; -use protobuf; -use protobuf::{Message, ProtobufEnum}; - +use protobuf::{self, Message, ProtobufEnum}; +use super::{DeviceDirection, WalletInfo, TransactionInfo, KeyPath, Wallet, Device, USB_DEVICE_CLASS_DEVICE, POLLING_DURATION}; use trezor_sys::messages::{EthereumAddress, PinMatrixAck, MessageType, EthereumTxRequest, EthereumSignTx, EthereumGetAddress, EthereumTxAck, ButtonAck}; /// Trezor v1 vendor ID @@ -44,8 +38,8 @@ const TREZOR_VID: u16 = 0x534c; /// Trezor product IDs const TREZOR_PIDS: [u16; 1] = [0x0001]; -const ETH_DERIVATION_PATH: [u32; 5] = [0x8000002C, 0x8000003C, 0x80000000, 0, 0]; // m/44'/60'/0'/0/0 -const ETC_DERIVATION_PATH: [u32; 5] = [0x8000002C, 0x8000003D, 0x80000000, 0, 0]; // m/44'/61'/0'/0/0 +const ETH_DERIVATION_PATH: [u32; 5] = [0x8000_002C, 0x8000_003C, 0x8000_0000, 0, 0]; // m/44'/60'/0'/0/0 +const ETC_DERIVATION_PATH: [u32; 5] = [0x8000_002C, 0x8000_003D, 0x8000_0000, 0, 0]; // m/44'/61'/0'/0/0 /// Hardware wallet error. #[derive(Debug)] @@ -62,6 +56,12 @@ pub enum Error { BadMessageType, /// Trying to read from a closed device at the given path LockedDevice(String), + /// Signing messages are not supported by Trezor + NoSigningMessage, + /// No device arrived + NoDeviceArrived, + /// No device left + NoDeviceLeft, } impl fmt::Display for Error { @@ -73,24 +73,27 @@ impl fmt::Display for Error { Error::UserCancel => write!(f, "Operation has been cancelled"), Error::BadMessageType => write!(f, "Bad Message Type in RPC call"), Error::LockedDevice(ref s) => write!(f, "Device is locked, needs PIN to perform operations: {}", s), + Error::NoSigningMessage=> write!(f, "Signing messages are not supported by Trezor"), + Error::NoDeviceArrived => write!(f, "No device arrived"), + Error::NoDeviceLeft=> write!(f, "No device left"), } } } impl From for Error { - fn from(err: hidapi::HidError) -> Error { + fn from(err: hidapi::HidError) -> Self { Error::Usb(err) } } impl From for Error { - fn from(_: protobuf::ProtobufError) -> Error { + fn from(_: protobuf::ProtobufError) -> Self { Error::Protocol(&"Could not read response from Trezor Device") } } -/// Ledger device manager -pub struct Manager { +/// Trezor device manager +pub (crate) struct Manager { usb: Arc>, devices: RwLock>, locked_devices: RwLock>, @@ -105,8 +108,8 @@ enum HidVersion { impl Manager { /// Create a new instance. - pub fn new(hidapi: Arc>, exiting: Arc) -> Result, libusb::Error> { - let manager = Arc::new(Manager { + pub fn new(hidapi: Arc>, exiting: Arc) -> Result, libusb::Error> { + let manager = Arc::new(Self { usb: hidapi, devices: RwLock::new(Vec::new()), locked_devices: RwLock::new(Vec::new()), @@ -127,12 +130,12 @@ impl Manager { thread::Builder::new() .name("hw_wallet_trezor".to_string()) .spawn(move || { - if let Err(e) = m.update_devices() { + if let Err(e) = m.update_devices(DeviceDirection::Arrived) { debug!(target: "hw", "Trezor couldn't connect at startup, error: {}", e); } loop { usb_context.handle_events(Some(Duration::from_millis(500))) - .unwrap_or_else(|e| debug!(target: "hw", "Trezor event handler error: {}", e)); + .unwrap_or_else(|e| debug!(target: "hw", "Trezor event handler error: {}", e)); if exiting.load(atomic::Ordering::Acquire) { break; } @@ -160,13 +163,12 @@ impl Manager { } }; - self.update_devices()?; + self.update_devices(DeviceDirection::Arrived)?; unlocked } - fn u256_to_be_vec(&self, val: &U256) -> Vec { - let mut buf = [0u8; 32]; + let mut buf = [0_u8; 32]; val.to_big_endian(&mut buf); buf.iter().skip_while(|x| **x == 0).cloned().collect() } @@ -221,8 +223,8 @@ impl Manager { let mut data = Vec::new(); let hid_version = self.probe_hid_version(device)?; // Magic constants - data.push('#' as u8); - data.push('#' as u8); + data.push(b'#'); + data.push(b'#'); // Convert msg_id to BE and split into bytes data.push(((msg_id >> 8) & 0xFF) as u8); data.push((msg_id & 0xFF) as u8); @@ -238,8 +240,8 @@ impl Manager { let mut total_written = 0; for chunk in data.chunks(63) { let mut padded_chunk = match hid_version { - HidVersion::V1 => vec!['?' as u8], - HidVersion::V2 => vec![0, '?' as u8], + HidVersion::V1 => vec![b'?'], + HidVersion::V2 => vec![0, b'?'], }; padded_chunk.extend_from_slice(&chunk); total_written += device.write(&padded_chunk)?; @@ -248,10 +250,10 @@ impl Manager { } fn probe_hid_version(&self, device: &hidapi::HidDevice) -> Result { - let mut buf2 = [0xFFu8; 65]; + let mut buf2 = [0xFF_u8; 65]; buf2[0] = 0; buf2[1] = 63; - let mut buf1 = [0xFFu8; 64]; + let mut buf1 = [0xFF_u8; 64]; buf1[0] = 63; if device.write(&buf2)? == 65 { Ok(HidVersion::V2) @@ -267,7 +269,7 @@ impl Manager { let mut buf = vec![0; 64]; let first_chunk = device.read_timeout(&mut buf, 300_000)?; - if first_chunk < 9 || buf[0] != '?' as u8 || buf[1] != '#' as u8 || buf[2] != '#' as u8 { + if first_chunk < 9 || buf[0] != b'?' || buf[1] != b'#' || buf[2] != b'#' { return Err(protocol_err); } let msg_type = MessageType::from_i32(((buf[3] as i32 & 0xFF) << 8) + (buf[4] as i32 & 0xFF)).ok_or(protocol_err)?; @@ -303,11 +305,8 @@ impl <'a>Wallet<'a> for Manager { message.set_gas_price(self.u256_to_be_vec(&t_info.gas_price)); message.set_value(self.u256_to_be_vec(&t_info.value)); - match t_info.to { - Some(addr) => { - message.set_to(addr.to_vec()) - } - None => (), + if let Some(addr) = t_info.to { + message.set_to(addr.to_vec()) } let first_chunk_length = min(t_info.data.len(), 1024); let chunk = &t_info.data[0..first_chunk_length]; @@ -326,60 +325,65 @@ impl <'a>Wallet<'a> for Manager { *self.key_path.write() = key_path; } - fn update_devices(&self) -> Result { + fn update_devices(&self, device_direction: DeviceDirection) -> Result { let mut usb = self.usb.lock(); usb.refresh_devices(); let devices = usb.devices(); - let mut new_devices = Vec::new(); - let mut locked_devices = Vec::new(); - let mut error = None; - for usb_device in devices { - let is_trezor = usb_device.vendor_id == TREZOR_VID; - let is_supported_product = TREZOR_PIDS.contains(&usb_device.product_id); - let is_valid = usb_device.usage_page == 0xFF00 || usb_device.interface_number == 0; - - trace!( - "Checking device: {:?}, trezor: {:?}, prod: {:?}, valid: {:?}", - usb_device, - is_trezor, - is_supported_product, - is_valid, - ); - if !is_trezor || !is_supported_product || !is_valid { - continue; + let num_prev_devices = self.devices.read().len(); + + let detected_devices = devices.iter() + .filter(|&d| { + let is_trezor = d.vendor_id == TREZOR_VID; + let is_supported_product = TREZOR_PIDS.contains(&d.product_id); + let is_valid = d.usage_page == 0xFF00 || d.interface_number == 0; + + is_trezor && is_supported_product && is_valid + }) + .fold(Vec::new(), |mut v, d| { + match self.read_device(&usb, &d) { + Ok(info) => { + trace!(target: "hw", "Found device: {:?}", info); + v.push(info); + } + Err(e) => trace!(target: "hw", "Error reading device info: {}", e), + }; + v + }); + + let num_curr_devices = detected_devices.len(); + *self.devices.write() = detected_devices; + + match device_direction { + DeviceDirection::Arrived => { + if num_curr_devices > num_prev_devices { + Ok(num_curr_devices - num_prev_devices) + } else { + Err(Error::NoDeviceArrived) + } } - match self.read_device(&usb, &usb_device) { - Ok(device) => new_devices.push(device), - Err(Error::LockedDevice(path)) => locked_devices.push(path.to_string()), - Err(e) => { - warn!("Error reading device: {:?}", e); - error = Some(e); + DeviceDirection::Left => { + if num_prev_devices > num_curr_devices { + Ok(num_prev_devices- num_curr_devices) + } else { + Err(Error::NoDeviceLeft) } } } - let count = new_devices.len(); - trace!("Got devices: {:?}, closed: {:?}", new_devices, locked_devices); - *self.devices.write() = new_devices; - *self.locked_devices.write() = locked_devices; - match error { - Some(e) => Err(e), - None => Ok(count), - } } fn read_device(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result { let handle = self.open_path(|| usb.open_path(&dev_info.path))?; - let manufacturer = dev_info.manufacturer_string.clone().unwrap_or("Unknown".to_owned()); - let name = dev_info.product_string.clone().unwrap_or("Unknown".to_owned()); - let serial = dev_info.serial_number.clone().unwrap_or("Unknown".to_owned()); + let manufacturer = dev_info.manufacturer_string.clone().unwrap_or_else(|| "Unknown".to_owned()); + let name = dev_info.product_string.clone().unwrap_or_else(|| "Unknown".to_owned()); + let serial = dev_info.serial_number.clone().unwrap_or_else(|| "Unknown".to_owned()); match self.get_address(&handle) { Ok(Some(addr)) => { Ok(Device { path: dev_info.path.clone(), info: WalletInfo { - name: name, - manufacturer: manufacturer, - serial: serial, + name, + manufacturer, + serial, address: addr, }, }) @@ -429,10 +433,11 @@ impl <'a>Wallet<'a> for Manager { } // Try to connect to the device using polling in at most the time specified by the `timeout` -fn try_connect_polling(trezor: Arc, duration: Duration) -> bool { +fn try_connect_polling(trezor: &Manager, duration: &Duration, dir: DeviceDirection) -> bool { let start_time = Instant::now(); - while start_time.elapsed() <= duration { - if let Ok(_) = trezor.update_devices() { + while start_time.elapsed() <= *duration { + if let Ok(num_devices) = trezor.update_devices(dir) { + trace!(target: "hw", "{} Trezor devices {}", num_devices, dir); return true } } @@ -451,7 +456,7 @@ struct EventHandler { impl EventHandler { /// Trezor event handler constructor pub fn new(trezor: Weak) -> Self { - Self { trezor: trezor } + Self { trezor } } } @@ -459,8 +464,8 @@ impl libusb::Hotplug for EventHandler { fn device_arrived(&mut self, _device: libusb::Device) { debug!(target: "hw", "Trezor V1 arrived"); if let Some(trezor) = self.trezor.upgrade() { - if try_connect_polling(trezor, Duration::from_millis(500)) != true { - debug!(target: "hw", "Ledger connect timeout"); + if try_connect_polling(&trezor, &POLLING_DURATION, DeviceDirection::Arrived) != true { + trace!(target: "hw", "No Trezor connected"); } } } @@ -468,8 +473,8 @@ impl libusb::Hotplug for EventHandler { fn device_left(&mut self, _device: libusb::Device) { debug!(target: "hw", "Trezor V1 left"); if let Some(trezor) = self.trezor.upgrade() { - if try_connect_polling(trezor, Duration::from_millis(500)) != true { - debug!(target: "hw", "Ledger disconnect timeout"); + if try_connect_polling(&trezor, &POLLING_DURATION, DeviceDirection::Left) != true { + trace!(target: "hw", "No Trezor disconnected"); } } } @@ -482,11 +487,14 @@ impl libusb::Hotplug for EventHandler { fn test_signature() { use ethereum_types::{H160, H256, U256}; - let hidapi = Arc::new(Mutex::new(hidapi::HidApi::new().unwrap())); - let manager = Manager::new(hidapi.clone(), Arc::new(AtomicBool::new(false))).unwrap(); + let manager = Manager::new( + Arc::new(Mutex::new(hidapi::HidApi::new().expect("HidApi"))), + Arc::new(AtomicBool::new(false)) + ).expect("HardwareWalletManager"); + let addr: Address = H160::from("some_addr"); - assert_eq!(try_connect_polling(manager.clone(), Duration::from_millis(500)), true); + assert_eq!(try_connect_polling(&manager.clone(), &POLLING_DURATION, DeviceDirection::Arrived), true); let t_info = TransactionInfo { nonce: U256::from(1), diff --git a/ipfs/Cargo.toml b/ipfs/Cargo.toml index 9c7b5f3b003793cd05f1954bed6a841fabc9e84b..968aef67bf9be1fc873d9097fce6ecafba76a48a 100644 --- a/ipfs/Cargo.toml +++ b/ipfs/Cargo.toml @@ -7,11 +7,14 @@ authors = ["Parity Technologies "] [dependencies] ethcore = { path = "../ethcore" } -ethcore-bytes = { path = "../util/bytes" } +parity-bytes = { git = "https://github.com/paritytech/parity-common" } ethereum-types = "0.3" jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } -rlp = { path = "../util/rlp" } +rlp = { git = "https://github.com/paritytech/parity-common" } cid = "0.2" multihash = "0.7" unicase = "2.0" + +[dev-dependencies] +ethcore = { path = "../ethcore", features = ["test-helpers"] } diff --git a/ipfs/src/error.rs b/ipfs/src/error.rs index fadd75b9b4ab0bfc0ce0d978278b3a01178a5380..1ff2829553d59151eefe4536e355a3fb94ee2901 100644 --- a/ipfs/src/error.rs +++ b/ipfs/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ipfs/src/lib.rs b/ipfs/src/lib.rs index bb7d0c3897c923fb0518199de4cabb7f1796387f..ac0871b6452d5ee72939fe518ad9e082f20a23e8 100644 --- a/ipfs/src/lib.rs +++ b/ipfs/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -20,7 +20,7 @@ extern crate unicase; extern crate rlp; extern crate ethcore; -extern crate ethcore_bytes as bytes; +extern crate parity_bytes as bytes; extern crate ethereum_types; extern crate jsonrpc_core as core; extern crate jsonrpc_http_server as http; diff --git a/ipfs/src/route.rs b/ipfs/src/route.rs index 2beb4ccc3716d03c30ee715148074c83cfdba46b..8f57fc4d1022de072371e38ac13917b7c170c35e 100644 --- a/ipfs/src/route.rs +++ b/ipfs/src/route.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/blockchain/account.rs b/json/src/blockchain/account.rs index 66b5f9b8446c9a35846f5a6a566aa5eeff59f5d2..38a0b1fa9cdf71bc7ce0b03c16738986ca262195 100644 --- a/json/src/blockchain/account.rs +++ b/json/src/blockchain/account.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/blockchain/block.rs b/json/src/blockchain/block.rs index 503230f09e61c139f080ff3af938d22f241fa5b1..5a6c995658ffb6a32c4334685f1ab7b5e4060bbe 100644 --- a/json/src/blockchain/block.rs +++ b/json/src/blockchain/block.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/blockchain/blockchain.rs b/json/src/blockchain/blockchain.rs index 9edd753130a1cb6dc4a34d13a888148adb3091b7..9e4d650b85a1fcdcfcb16fee6a581979b0c0b58d 100644 --- a/json/src/blockchain/blockchain.rs +++ b/json/src/blockchain/blockchain.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/blockchain/header.rs b/json/src/blockchain/header.rs index 667a36bb1b519d2d400cafbc4a95b84afedf5371..ee79a928eab89cc08e5baca205618f911bc25051 100644 --- a/json/src/blockchain/header.rs +++ b/json/src/blockchain/header.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/blockchain/mod.rs b/json/src/blockchain/mod.rs index e1faa07880f6a4da27ef9f222c3b52bed0147b06..0d8e7ff78f27c08df2f2f448669698ef29dc584b 100644 --- a/json/src/blockchain/mod.rs +++ b/json/src/blockchain/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/blockchain/state.rs b/json/src/blockchain/state.rs index a64887572b2394c2ed7dd457d74cd8a558b2465c..e23a31efa036146484fdfe7fbb67238102f23e2e 100644 --- a/json/src/blockchain/state.rs +++ b/json/src/blockchain/state.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/blockchain/test.rs b/json/src/blockchain/test.rs index 018ae767dde3e693785206353c3dc44806979077..792303dc7e4e28c1f1e0889067db29acd45a09e7 100644 --- a/json/src/blockchain/test.rs +++ b/json/src/blockchain/test.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/blockchain/transaction.rs b/json/src/blockchain/transaction.rs index 6b3550fd78d5d17701e734b2618b0c181ff2db23..f14dd5e33635256d4de1f417f631ab9b5fcc47d8 100644 --- a/json/src/blockchain/transaction.rs +++ b/json/src/blockchain/transaction.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/bytes.rs b/json/src/bytes.rs index 79ba4f896b8c58efb4d87911abb5b8bc50917092..3eb1f54152675b92fee49781ff1d33958c8f90d0 100644 --- a/json/src/bytes.rs +++ b/json/src/bytes.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/hash.rs b/json/src/hash.rs index 54aea04365e4400560dc3045c6ac93fe9feaef59..8dac3f6e7366808ab4096d42fcca63355d7f566e 100644 --- a/json/src/hash.rs +++ b/json/src/hash.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -23,7 +23,6 @@ use serde::de::{Error, Visitor}; use rustc_hex::ToHex; use ethereum_types::{H64 as Hash64, H160 as Hash160, H256 as Hash256, H520 as Hash520, Bloom as Hash2048}; - macro_rules! impl_hash { ($name: ident, $inner: ident) => { /// Lenient hash json deserialization for test json files. diff --git a/json/src/lib.rs b/json/src/lib.rs index 3cb1e49f57d596f5fdee2e076c566c3f8339e55f..5d31cd6c97da077d0a3248c13f5a1f3c19ddd87f 100644 --- a/json/src/lib.rs +++ b/json/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/maybe.rs b/json/src/maybe.rs index 8b74b22c4830eddef46057663ceb1f127cbb6a52..1f77a98ef1d93c360758023112b80a8635d08765 100644 --- a/json/src/maybe.rs +++ b/json/src/maybe.rs @@ -1,3 +1,18 @@ +// 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 . //! Deserializer of empty string values into optionals. diff --git a/json/src/misc/account_meta.rs b/json/src/misc/account_meta.rs index 9c4d67286e8368328b6b01d077ff4e34e896a1f2..cb6ed1c877aae6c219b101a9070e67bb88e10ede 100644 --- a/json/src/misc/account_meta.rs +++ b/json/src/misc/account_meta.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/misc/dapps_settings.rs b/json/src/misc/dapps_settings.rs index 5081c62b28b5af9110c5a919482c18dea6c37f2a..f59f5f1cf6d75b3ecd8062416de3ce8d1be73b22 100644 --- a/json/src/misc/dapps_settings.rs +++ b/json/src/misc/dapps_settings.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/misc/mod.rs b/json/src/misc/mod.rs index d587f2f1578f566d4a02f3fc6d1514786846de1d..836094f0c08ded02f3b2991f5a1a5db9857bc5b1 100644 --- a/json/src/misc/mod.rs +++ b/json/src/misc/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/account.rs b/json/src/spec/account.rs index fb41137aa9c5c57f93341e1aff5ea0f1372de4c1..acc6d96b58973f5d3d7c0dd358e64131a1ff8ebe 100644 --- a/json/src/spec/account.rs +++ b/json/src/spec/account.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/authority_round.rs b/json/src/spec/authority_round.rs index 4ef9368362cf5bd2cb2e6c4c3eef0bfd6e86952b..e355c6fe951cdc032528c808e85f77aca30e5a4f 100644 --- a/json/src/spec/authority_round.rs +++ b/json/src/spec/authority_round.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/basic_authority.rs b/json/src/spec/basic_authority.rs index 0a257f134b12e9a81f78e0cdd526be6d66c83dc0..1e5c6b845619729926077d02253d391fc49eb312 100644 --- a/json/src/spec/basic_authority.rs +++ b/json/src/spec/basic_authority.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/builtin.rs b/json/src/spec/builtin.rs index 34e9a2df1c18613cde6690cafa4d6e8b6f1a4a6e..850867d0950ffa9d0de53165ea439d5b87ad9e30 100644 --- a/json/src/spec/builtin.rs +++ b/json/src/spec/builtin.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/engine.rs b/json/src/spec/engine.rs index e2545a5f90d6306ed39820bbce4f897a53786c24..55b9c1b2af2973cc6d2a88895f69737013d58fa4 100644 --- a/json/src/spec/engine.rs +++ b/json/src/spec/engine.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -142,4 +142,3 @@ mod tests { }; } } - diff --git a/json/src/spec/ethash.rs b/json/src/spec/ethash.rs index 66f6913e578abb336469eb2db4e84d5d5878fdc3..19fd09662734141efd6653f3f7857a22bc81c917 100644 --- a/json/src/spec/ethash.rs +++ b/json/src/spec/ethash.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/genesis.rs b/json/src/spec/genesis.rs index f595e7750f3031be5f9beb6b5dfa679d994b3b0f..d8e2ad53579df478abce773b0aa4752c79fa29af 100644 --- a/json/src/spec/genesis.rs +++ b/json/src/spec/genesis.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/hardcoded_sync.rs b/json/src/spec/hardcoded_sync.rs index 548fd66f0faabd724bbe2f14882aad22116ecc2c..8b00b5413b5104c5c4e2a523ede00cf5511d4a39 100644 --- a/json/src/spec/hardcoded_sync.rs +++ b/json/src/spec/hardcoded_sync.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/mod.rs b/json/src/spec/mod.rs index 285596f14a72a25f8874474b865bd9647958cdd9..26965c887d08522dc49353fbdd8b24b86df929ad 100644 --- a/json/src/spec/mod.rs +++ b/json/src/spec/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/null_engine.rs b/json/src/spec/null_engine.rs index cfd3d6ce6377eed4b057256597908b4c809198fc..87827bd5b9f4189b984e231912067396b7f36d55 100644 --- a/json/src/spec/null_engine.rs +++ b/json/src/spec/null_engine.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs index f171a88101920673984478d4b0d78a68f77c121e..a37e4f23ba80dda707b59ea127e4679cbe020f87 100644 --- a/json/src/spec/params.rs +++ b/json/src/spec/params.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -109,6 +109,9 @@ pub struct Params { #[serde(rename="eip658Transition")] pub eip658_transition: Option, /// See `CommonParams` docs. + #[serde(rename="eip1052Transition")] + pub eip1052_transition: Option, + /// See `CommonParams` docs. #[serde(rename="dustProtectionTransition")] pub dust_protection_transition: Option, /// See `CommonParams` docs. diff --git a/json/src/spec/seal.rs b/json/src/spec/seal.rs index 6654a309a307773b6d933c3eed380b2bda03da20..b61d141d641f9d3d113ea394c5769b2ba43fbbbb 100644 --- a/json/src/spec/seal.rs +++ b/json/src/spec/seal.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/spec.rs b/json/src/spec/spec.rs index 7003cb4cfc9e009525e1ed42bfc68684b0b8b54b..2be695689e48ad53aa8bb3c89fe00b95b745a641 100644 --- a/json/src/spec/spec.rs +++ b/json/src/spec/spec.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/state.rs b/json/src/spec/state.rs index ad6f2e548dc7e3a73f1b6f0953c8e80db56f9a12..d15ad540ce4ee77515c34ff66cbc775ef39d380f 100644 --- a/json/src/spec/state.rs +++ b/json/src/spec/state.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/tendermint.rs b/json/src/spec/tendermint.rs index 8f3d4c224871119ae1d3459939b19fd15fdd9ea7..e0a6568aa9c7f56aa56fc3e4e54eec87c5d54648 100644 --- a/json/src/spec/tendermint.rs +++ b/json/src/spec/tendermint.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/validator_set.rs b/json/src/spec/validator_set.rs index 9c6b4e79a1c4956662789135e932ece44ec9bb85..41fa60961a73ff9349950cf43f3c9ec569a4be29 100644 --- a/json/src/spec/validator_set.rs +++ b/json/src/spec/validator_set.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/state/log.rs b/json/src/state/log.rs index 823979f6279483b9ec5d9b93db342702ddbb5dd1..1e07d9ed1eaea44ad4222aac55a09ed79b51a33d 100644 --- a/json/src/state/log.rs +++ b/json/src/state/log.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/state/mod.rs b/json/src/state/mod.rs index 316744983c4b175d5e5c50b01c7ea7a9b8084c1b..6037ca514d04e7e7c27bdec53866496a98375943 100644 --- a/json/src/state/mod.rs +++ b/json/src/state/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/state/state.rs b/json/src/state/state.rs index 9daecaed8e361a8feb240b2292227aebc64693c7..c6837d1fd650dce360f6cf9131219e7bd5922533 100644 --- a/json/src/state/state.rs +++ b/json/src/state/state.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/state/test.rs b/json/src/state/test.rs index 3a25c007df8a6d8d360df3844dec4c560ce3d303..528a49b5a6603e7b7136f4e8653b388c56e9e7fa 100644 --- a/json/src/state/test.rs +++ b/json/src/state/test.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/state/transaction.rs b/json/src/state/transaction.rs index 606c40f21f701f65b371afd27f4382d7034f0d78..89edb08692a6256f5af1ec9befa5023b86698eac 100644 --- a/json/src/state/transaction.rs +++ b/json/src/state/transaction.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/test/mod.rs b/json/src/test/mod.rs index 1a6e4db7daf7d5d73cf06dc1c498a235a9fd1996..8f95a9aec49378c90b4cc7ac0a581bfab3fd8283 100644 --- a/json/src/test/mod.rs +++ b/json/src/test/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -64,4 +64,3 @@ impl DifficultyTest { serde_json::from_reader(reader) } } - diff --git a/json/src/transaction/mod.rs b/json/src/transaction/mod.rs index 5cde3eff409cdc1885674089ace3f3bc8fc86c30..8ebab3f1c2ba43311b9637929de455961ae65e83 100644 --- a/json/src/transaction/mod.rs +++ b/json/src/transaction/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/transaction/test.rs b/json/src/transaction/test.rs index a2ef9ad36a9f773e3b0aa38dd77dc81a3f5b91f3..e1bd588de35054a2ffd2a8cb54e99269197f5ddc 100644 --- a/json/src/transaction/test.rs +++ b/json/src/transaction/test.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/transaction/transaction.rs b/json/src/transaction/transaction.rs index d9b6abb14ec1d451fe7e7a70952d88e893d8e39e..13b342b3f6a300f11fac63872d36c165ef07da6d 100644 --- a/json/src/transaction/transaction.rs +++ b/json/src/transaction/transaction.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/transaction/txtest.rs b/json/src/transaction/txtest.rs index 33bc0152f262f47f3d0482a764fbe05e55a1685d..60d65e70d66b4b6f63457bd2c5a8e4f105739f07 100644 --- a/json/src/transaction/txtest.rs +++ b/json/src/transaction/txtest.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/trie/input.rs b/json/src/trie/input.rs index c84f1aa1e1fe432bf2b6edbad643d34db6440460..e1c46ac537e35f6a97dc14a67b90bfc7f4aded3a 100644 --- a/json/src/trie/input.rs +++ b/json/src/trie/input.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/trie/mod.rs b/json/src/trie/mod.rs index ce1992205846c05834beda8e1ea85b6e559cea74..5dc52cb21d452879b6309b8b7387abbfae6814cb 100644 --- a/json/src/trie/mod.rs +++ b/json/src/trie/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/trie/test.rs b/json/src/trie/test.rs index 30811ca66190ffd03c463113618964daa9075ef3..c6cd99c25e8c6d1c15e29cd3a26dc73ac0be2edb 100644 --- a/json/src/trie/test.rs +++ b/json/src/trie/test.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/trie/trie.rs b/json/src/trie/trie.rs index e4951f81413779e0d3f0cd1ea24b11fd7456576b..ca18de7daa5285835304751119d7886f9f1b489c 100644 --- a/json/src/trie/trie.rs +++ b/json/src/trie/trie.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/uint.rs b/json/src/uint.rs index 70e0390a34cbbf74b258f29bcfe731b15394fc4c..25c5049c45b0da6d04c2d1d4d578aefed0b311ef 100644 --- a/json/src/uint.rs +++ b/json/src/uint.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/vm/call.rs b/json/src/vm/call.rs index 39d5a828eb9e36fea46dbe1a302d881d136d9274..026951c028212805850f3d817ca91d12ce30ee49 100644 --- a/json/src/vm/call.rs +++ b/json/src/vm/call.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/vm/env.rs b/json/src/vm/env.rs index c7f0ccd725ffefb4348453c253ccd2832e24492f..f4af8119c30ebf76884feb431079320a3b819136 100644 --- a/json/src/vm/env.rs +++ b/json/src/vm/env.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/vm/mod.rs b/json/src/vm/mod.rs index a2588e37c79651130d3e524dab5f83d961db96c0..29b12d4805dd8b118a4711635ca6b39a16a542a6 100644 --- a/json/src/vm/mod.rs +++ b/json/src/vm/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/vm/test.rs b/json/src/vm/test.rs index 68112e60153f70edb14ef1c1358f02825569472c..10b4aae54f826dcad5b0f8596d37d543a8c044d9 100644 --- a/json/src/vm/test.rs +++ b/json/src/vm/test.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/vm/transaction.rs b/json/src/vm/transaction.rs index efdad0f9cc9c79ffc33172de3f9d0b62b28d8881..44b79e86226a12f11aead6f9d98b1178c759c185 100644 --- a/json/src/vm/transaction.rs +++ b/json/src/vm/transaction.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/vm/vm.rs b/json/src/vm/vm.rs index 8cc01e3bac2712842b3e8a7cc8811477c646dd1c..7fd101da83a633a0d6a6d56cc09fc063eca145db 100644 --- a/json/src/vm/vm.rs +++ b/json/src/vm/vm.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/license_header b/license_header index f90ec463dc42a4d721c3bbeac9067e7d2207d5ab..4738554f915dbe740c1b359503840181883cf565 100644 --- a/license_header +++ b/license_header @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/local-store/Cargo.toml b/local-store/Cargo.toml index 6d09eb76f69ade2ad53ce0da4cdaddbe76e75fdc..75717bed08b8d37e433bbcca74a45870446dee55 100644 --- a/local-store/Cargo.toml +++ b/local-store/Cargo.toml @@ -8,13 +8,14 @@ authors = ["Parity Technologies "] ethcore = { path = "../ethcore" } ethcore-io = { path = "../util/io" } ethcore-transaction = { path = "../ethcore/transaction" } -kvdb = { path = "../util/kvdb" } +kvdb = { git = "https://github.com/paritytech/parity-common" } log = "0.3" -rlp = { path = "../util/rlp" } +rlp = { git = "https://github.com/paritytech/parity-common" } serde = "1.0" serde_derive = "1.0" serde_json = "1.0" [dev-dependencies] +ethcore = { path = "../ethcore", features = ["test-helpers"] } ethkey = { path = "../ethkey" } -kvdb-memorydb = { path = "../util/kvdb-memorydb" } +kvdb-memorydb = { git = "https://github.com/paritytech/parity-common" } diff --git a/local-store/src/lib.rs b/local-store/src/lib.rs index 078dff36ed859ca194aed7bfe20a1414b3ab625d..13d238ed6ad58390187f9aa911683958435c2175 100644 --- a/local-store/src/lib.rs +++ b/local-store/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -56,8 +56,8 @@ const UPDATE_TIMEOUT: Duration = Duration::from_secs(15 * 60); // once every 15 /// Errors which can occur while using the local data store. #[derive(Debug)] pub enum Error { - /// Database errors: these manifest as `String`s. - Database(kvdb::Error), + /// Io and database errors: these manifest as `String`s. + Io(::std::io::Error), /// JSON errors. Json(::serde_json::Error), } @@ -65,7 +65,7 @@ pub enum Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Error::Database(ref val) => write!(f, "{}", val), + Error::Io(ref val) => write!(f, "{}", val), Error::Json(ref err) => write!(f, "{}", err), } } @@ -160,7 +160,7 @@ pub struct LocalDataStore { impl LocalDataStore { /// Attempt to read pending transactions out of the local store. pub fn pending_transactions(&self) -> Result, Error> { - if let Some(val) = self.db.get(self.col, LOCAL_TRANSACTIONS_KEY).map_err(Error::Database)? { + if let Some(val) = self.db.get(self.col, LOCAL_TRANSACTIONS_KEY).map_err(Error::Io)? { let local_txs: Vec<_> = ::serde_json::from_slice::>(&val) .map_err(Error::Json)? .into_iter() @@ -200,7 +200,7 @@ impl LocalDataStore { let json_str = format!("{}", local_json); batch.put_vec(self.col, LOCAL_TRANSACTIONS_KEY, json_str.into_bytes()); - self.db.write(batch).map_err(Error::Database) + self.db.write(batch).map_err(Error::Io) } } diff --git a/logger/Cargo.toml b/logger/Cargo.toml index a1f793769c584f34a1af80dec6ce2ed46f13cb43..3db404bf6453915fc636f7fce9e9abecd5144bcf 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 863075a0e5207c13303820873408d783a63f0665..6918397886d24d1858630bcbebac2aca5aadfccd 100644 --- a/logger/src/lib.rs +++ b/logger/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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/logger/src/rotating.rs b/logger/src/rotating.rs index e67bdfaad0adcd27e38fb4915c0e299cd3da39bf..ddc24792aecebedbe8d0020ab33627a8aa38fceb 100644 --- a/logger/src/rotating.rs +++ b/logger/src/rotating.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -121,4 +121,3 @@ mod test { assert_eq!(logs.len(), 2); } } - diff --git a/mac/Parity Ethereum.xcodeproj/project.pbxproj b/mac/Parity Ethereum.xcodeproj/project.pbxproj deleted file mode 100644 index 80bc86af8d689847f8d06ec7d5c74b6abe6796ee..0000000000000000000000000000000000000000 --- a/mac/Parity Ethereum.xcodeproj/project.pbxproj +++ /dev/null @@ -1,333 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 0A7A475D1E3D2CDD0093D1AB /* parity in CopyFiles */ = {isa = PBXBuildFile; fileRef = 0A7A475C1E3D2CDD0093D1AB /* parity */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; - 0ACF9AC21E30FAB600D5C935 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ACF9AC11E30FAB600D5C935 /* AppDelegate.swift */; }; - 0ACF9AC41E30FAB600D5C935 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0ACF9AC31E30FAB600D5C935 /* Assets.xcassets */; }; - 0ACF9AC71E30FAB600D5C935 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0ACF9AC51E30FAB600D5C935 /* MainMenu.xib */; }; - 0AE564F11E3CE42C00BD01F7 /* GetBSDProcessList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE564F01E3CE42C00BD01F7 /* GetBSDProcessList.swift */; }; - 0AED4DA01E3E22F800BF87C0 /* ethstore in CopyFiles */ = {isa = PBXBuildFile; fileRef = 0AED4D9F1E3E22F800BF87C0 /* ethstore */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; - 84CF92B3200E559900AD6E78 /* parity-evm in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84CF92B2200E559900AD6E78 /* parity-evm */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; - 84CF92B6200E56AE00AD6E78 /* ethkey in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84CF92B5200E56AE00AD6E78 /* ethkey */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 0A7A475B1E3D2C800093D1AB /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 6; - files = ( - 84CF92B6200E56AE00AD6E78 /* ethkey in CopyFiles */, - 84CF92B3200E559900AD6E78 /* parity-evm in CopyFiles */, - 0AED4DA01E3E22F800BF87C0 /* ethstore in CopyFiles */, - 0A7A475D1E3D2CDD0093D1AB /* parity in CopyFiles */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 0A7A475C1E3D2CDD0093D1AB /* parity */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = parity; path = ../artifacts/parity; sourceTree = ""; }; - 0ACF9ABE1E30FAB600D5C935 /* Parity Ethereum.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Parity Ethereum.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 0ACF9AC11E30FAB600D5C935 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 0ACF9AC31E30FAB600D5C935 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 0ACF9AC61E30FAB600D5C935 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 0ACF9AC81E30FAB600D5C935 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 0AE564F01E3CE42C00BD01F7 /* GetBSDProcessList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetBSDProcessList.swift; sourceTree = ""; }; - 0AED4D9F1E3E22F800BF87C0 /* ethstore */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = ethstore; path = ../artifacts/ethstore; sourceTree = ""; }; - 84CF92B2200E559900AD6E78 /* parity-evm */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = "parity-evm"; path = "../artifacts/parity-evm"; sourceTree = ""; }; - 84CF92B5200E56AE00AD6E78 /* ethkey */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = ethkey; path = ../artifacts/ethkey; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 0ACF9ABB1E30FAB600D5C935 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 0ACF9AB51E30FAB600D5C935 = { - isa = PBXGroup; - children = ( - 84CF92B5200E56AE00AD6E78 /* ethkey */, - 84CF92B2200E559900AD6E78 /* parity-evm */, - 0AED4D9F1E3E22F800BF87C0 /* ethstore */, - 0A7A475C1E3D2CDD0093D1AB /* parity */, - 0ACF9AC01E30FAB600D5C935 /* Parity Ethereum */, - 0ACF9ABF1E30FAB600D5C935 /* Products */, - ); - sourceTree = ""; - }; - 0ACF9ABF1E30FAB600D5C935 /* Products */ = { - isa = PBXGroup; - children = ( - 0ACF9ABE1E30FAB600D5C935 /* Parity Ethereum.app */, - ); - name = Products; - sourceTree = ""; - }; - 0ACF9AC01E30FAB600D5C935 /* Parity Ethereum */ = { - isa = PBXGroup; - children = ( - 0ACF9AC11E30FAB600D5C935 /* AppDelegate.swift */, - 0ACF9AC31E30FAB600D5C935 /* Assets.xcassets */, - 0ACF9AC51E30FAB600D5C935 /* MainMenu.xib */, - 0ACF9AC81E30FAB600D5C935 /* Info.plist */, - 0AE564F01E3CE42C00BD01F7 /* GetBSDProcessList.swift */, - ); - name = "Parity Ethereum"; - path = Parity; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 0ACF9ABD1E30FAB600D5C935 /* Parity Ethereum */ = { - isa = PBXNativeTarget; - buildConfigurationList = 0ACF9ACB1E30FAB600D5C935 /* Build configuration list for PBXNativeTarget "Parity Ethereum" */; - buildPhases = ( - 0ACF9ABA1E30FAB600D5C935 /* Sources */, - 0ACF9ABB1E30FAB600D5C935 /* Frameworks */, - 0ACF9ABC1E30FAB600D5C935 /* Resources */, - 0A7A475B1E3D2C800093D1AB /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "Parity Ethereum"; - productName = Parity; - productReference = 0ACF9ABE1E30FAB600D5C935 /* Parity Ethereum.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 0ACF9AB61E30FAB600D5C935 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0800; - LastUpgradeCheck = 0820; - ORGANIZATIONNAME = "Parity Technologies"; - TargetAttributes = { - 0ACF9ABD1E30FAB600D5C935 = { - CreatedOnToolsVersion = 8.0; - DevelopmentTeam = P2PX3JU8FT; - ProvisioningStyle = Manual; - }; - }; - }; - buildConfigurationList = 0ACF9AB91E30FAB600D5C935 /* Build configuration list for PBXProject "Parity Ethereum" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 0ACF9AB51E30FAB600D5C935; - productRefGroup = 0ACF9ABF1E30FAB600D5C935 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 0ACF9ABD1E30FAB600D5C935 /* Parity Ethereum */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 0ACF9ABC1E30FAB600D5C935 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 0ACF9AC41E30FAB600D5C935 /* Assets.xcassets in Resources */, - 0ACF9AC71E30FAB600D5C935 /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 0ACF9ABA1E30FAB600D5C935 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 0AE564F11E3CE42C00BD01F7 /* GetBSDProcessList.swift in Sources */, - 0ACF9AC21E30FAB600D5C935 /* AppDelegate.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 0ACF9AC51E30FAB600D5C935 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 0ACF9AC61E30FAB600D5C935 /* Base */, - ); - name = MainMenu.xib; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 0ACF9AC91E30FAB600D5C935 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.12; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 0ACF9ACA1E30FAB600D5C935 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.12; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - }; - name = Release; - }; - 0ACF9ACC1E30FAB600D5C935 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_IDENTITY = "Mac Developer"; - COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = P2PX3JU8FT; - GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; - INFOPLIST_FILE = Parity/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = io.parity.ethereum; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; - }; - name = Debug; - }; - 0ACF9ACD1E30FAB600D5C935 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_IDENTITY = "Developer ID Application"; - COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = P2PX3JU8FT; - GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; - INFOPLIST_FILE = Parity/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = io.parity.ethereum; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 0ACF9AB91E30FAB600D5C935 /* Build configuration list for PBXProject "Parity Ethereum" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 0ACF9AC91E30FAB600D5C935 /* Debug */, - 0ACF9ACA1E30FAB600D5C935 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 0ACF9ACB1E30FAB600D5C935 /* Build configuration list for PBXNativeTarget "Parity Ethereum" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 0ACF9ACC1E30FAB600D5C935 /* Debug */, - 0ACF9ACD1E30FAB600D5C935 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 0ACF9AB61E30FAB600D5C935 /* Project object */; -} diff --git a/mac/Parity Ethereum.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/mac/Parity Ethereum.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 8297038e3bb1baca69c4fbafe833dd5e3693a0bf..0000000000000000000000000000000000000000 --- a/mac/Parity Ethereum.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/mac/Parity.pkgproj b/mac/Parity.pkgproj deleted file mode 100755 index 1d12f5fd6d48e803a39d18a76b172a9740652dd4..0000000000000000000000000000000000000000 --- a/mac/Parity.pkgproj +++ /dev/null @@ -1,810 +0,0 @@ - - - - - PACKAGES - - - PACKAGE_FILES - - DEFAULT_INSTALL_LOCATION - / - HIERARCHY - - CHILDREN - - - CHILDREN - - - CHILDREN - - GID - 80 - PATH - build/release/Parity Ethereum.app - PATH_TYPE - 3 - PERMISSIONS - 493 - TYPE - 3 - UID - 0 - - - GID - 80 - PATH - Applications - PATH_TYPE - 0 - PERMISSIONS - 509 - TYPE - 1 - UID - 0 - - - CHILDREN - - - CHILDREN - - GID - 80 - PATH - Application Support - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Automator - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Documentation - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Extensions - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Filesystems - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Frameworks - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Input Methods - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Internet Plug-Ins - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - LaunchAgents - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - LaunchDaemons - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - PreferencePanes - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Preferences - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 80 - PATH - Printers - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - PrivilegedHelperTools - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - QuickLook - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - QuickTime - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Screen Savers - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Scripts - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Services - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Widgets - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - GID - 0 - PATH - Library - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - - CHILDREN - - GID - 0 - PATH - Shared - PATH_TYPE - 0 - PERMISSIONS - 1023 - TYPE - 1 - UID - 0 - - - GID - 80 - PATH - Users - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - GID - 0 - PATH - / - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - PAYLOAD_TYPE - 0 - SPLIT_FORKS - - VERSION - 4 - - PACKAGE_SCRIPTS - - POSTINSTALL_PATH - - PATH - post-install.sh - PATH_TYPE - 3 - - RESOURCES - - - PACKAGE_SETTINGS - - AUTHENTICATION - - CONCLUSION_ACTION - 0 - IDENTIFIER - io.parity.ethereum - NAME - Parity - OVERWRITE_PERMISSIONS - - VERSION - 1.12.0 - - UUID - 2DCD5B81-7BAF-4DA1-9251-6274B089FD36 - - - PROJECT - - PROJECT_COMMENTS - - NOTES - - PCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBIVE1M - IDQuMDEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvVFIvaHRtbDQv - c3RyaWN0LmR0ZCI+CjxodG1sPgo8aGVhZD4KPG1ldGEgaHR0cC1l - cXVpdj0iQ29udGVudC1UeXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7 - IGNoYXJzZXQ9VVRGLTgiPgo8bWV0YSBodHRwLWVxdWl2PSJDb250 - ZW50LVN0eWxlLVR5cGUiIGNvbnRlbnQ9InRleHQvY3NzIj4KPHRp - dGxlPjwvdGl0bGU+CjxtZXRhIG5hbWU9IkdlbmVyYXRvciIgY29u - dGVudD0iQ29jb2EgSFRNTCBXcml0ZXIiPgo8bWV0YSBuYW1lPSJD - b2NvYVZlcnNpb24iIGNvbnRlbnQ9IjE0MDQuNDciPgo8c3R5bGUg - dHlwZT0idGV4dC9jc3MiPgo8L3N0eWxlPgo8L2hlYWQ+Cjxib2R5 - Pgo8L2JvZHk+CjwvaHRtbD4K - - - PROJECT_PRESENTATION - - INSTALLATION_STEPS - - - ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS - ICPresentationViewIntroductionController - INSTALLER_PLUGIN - Introduction - LIST_TITLE_KEY - InstallerSectionTitle - - - ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS - ICPresentationViewReadMeController - INSTALLER_PLUGIN - ReadMe - LIST_TITLE_KEY - InstallerSectionTitle - - - ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS - ICPresentationViewLicenseController - INSTALLER_PLUGIN - License - LIST_TITLE_KEY - InstallerSectionTitle - - - ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS - ICPresentationViewDestinationSelectController - INSTALLER_PLUGIN - TargetSelect - LIST_TITLE_KEY - InstallerSectionTitle - - - ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS - ICPresentationViewInstallationTypeController - INSTALLER_PLUGIN - PackageSelection - LIST_TITLE_KEY - InstallerSectionTitle - - - ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS - ICPresentationViewInstallationController - INSTALLER_PLUGIN - Install - LIST_TITLE_KEY - InstallerSectionTitle - - - ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS - ICPresentationViewSummaryController - INSTALLER_PLUGIN - Summary - LIST_TITLE_KEY - InstallerSectionTitle - - - INTRODUCTION - - LOCALIZATIONS - - - LICENSE - - KEYWORDS - - LOCALIZATIONS - - - LANGUAGE - English - VALUE - - PATH - install-licence.txt - PATH_TYPE - 3 - - - - MODE - 0 - - README - - LOCALIZATIONS - - - LANGUAGE - English - VALUE - - PATH - install-readme.txt - PATH_TYPE - 3 - - - - - TITLE - - LOCALIZATIONS - - - LANGUAGE - English - VALUE - Parity - - - - - PROJECT_REQUIREMENTS - - LIST - - POSTINSTALL_PATH - - PREINSTALL_PATH - - RESOURCES - - ROOT_VOLUME_ONLY - - - PROJECT_SETTINGS - - ADVANCED_OPTIONS - - BUILD_FORMAT - 0 - BUILD_PATH - - PATH - .. - PATH_TYPE - 1 - - EXCLUDED_FILES - - - PATTERNS_ARRAY - - - REGULAR_EXPRESSION - - STRING - .DS_Store - TYPE - 0 - - - PROTECTED - - PROXY_NAME - Remove .DS_Store files - PROXY_TOOLTIP - Remove ".DS_Store" files created by the Finder. - STATE - - - - PATTERNS_ARRAY - - - REGULAR_EXPRESSION - - STRING - .pbdevelopment - TYPE - 0 - - - PROTECTED - - PROXY_NAME - Remove .pbdevelopment files - PROXY_TOOLTIP - Remove ".pbdevelopment" files created by ProjectBuilder or Xcode. - STATE - - - - PATTERNS_ARRAY - - - REGULAR_EXPRESSION - - STRING - CVS - TYPE - 1 - - - REGULAR_EXPRESSION - - STRING - .cvsignore - TYPE - 0 - - - REGULAR_EXPRESSION - - STRING - .cvspass - TYPE - 0 - - - REGULAR_EXPRESSION - - STRING - .svn - TYPE - 1 - - - REGULAR_EXPRESSION - - STRING - .git - TYPE - 1 - - - REGULAR_EXPRESSION - - STRING - .gitignore - TYPE - 0 - - - PROTECTED - - PROXY_NAME - Remove SCM metadata - PROXY_TOOLTIP - Remove helper files and folders used by the CVS, SVN or Git Source Code Management systems. - STATE - - - - PATTERNS_ARRAY - - - REGULAR_EXPRESSION - - STRING - classes.nib - TYPE - 0 - - - REGULAR_EXPRESSION - - STRING - designable.db - TYPE - 0 - - - REGULAR_EXPRESSION - - STRING - info.nib - TYPE - 0 - - - PROTECTED - - PROXY_NAME - Optimize nib files - PROXY_TOOLTIP - Remove "classes.nib", "info.nib" and "designable.nib" files within .nib bundles. - STATE - - - - PATTERNS_ARRAY - - - REGULAR_EXPRESSION - - STRING - Resources Disabled - TYPE - 1 - - - PROTECTED - - PROXY_NAME - Remove Resources Disabled folders - PROXY_TOOLTIP - Remove "Resources Disabled" folders. - STATE - - - - SEPARATOR - - - - NAME - Parity Ethereum - - - TYPE - 0 - VERSION - 2 - - diff --git a/mac/Parity/AppDelegate.swift b/mac/Parity/AppDelegate.swift deleted file mode 100644 index d65c1d601fab4187cb6b4216b3c1ba0efe63f117..0000000000000000000000000000000000000000 --- a/mac/Parity/AppDelegate.swift +++ /dev/null @@ -1,223 +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 . - -import Cocoa - -@NSApplicationMain -@available(macOS, deprecated: 10.11) - -class AppDelegate: NSObject, NSApplicationDelegate { - @IBOutlet weak var statusMenu: NSMenu! - @IBOutlet weak var startAtLogonMenuItem: NSMenuItem! - - let statusItem = NSStatusBar.system().statusItem(withLength: NSVariableStatusItemLength) - var parityPid: Int32? = nil - var commandLine: [String] = [] - let defaultDefaults = "{\"fat_db\":false,\"mode\":\"passive\",\"mode.alarm\":3600,\"mode.timeout\":300,\"pruning\":\"fast\",\"tracing\":false}" - - func menuAppPath() -> String { - return Bundle.main.executablePath! - } - - func parityPath() -> String { - return Bundle.main.bundlePath + "/Contents/MacOS/parity" - } - - func isAlreadyRunning() -> Bool { - return NSRunningApplication.runningApplications(withBundleIdentifier: Bundle.main.bundleIdentifier!).count > 1 - - } - - func isParityRunning() -> Bool { - if let pid = self.parityPid { - return kill(pid, 0) == 0 - } - return false - } - - func killParity() { - if let pid = self.parityPid { - kill(pid, SIGKILL) - } - } - - func openUI() { - let parity = Process() - parity.launchPath = self.parityPath() - parity.arguments = self.commandLine - parity.arguments!.append("ui") - parity.launch() - } - - func writeConfigFiles() { - let basePath = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first? - .appendingPathComponent(Bundle.main.bundleIdentifier!, isDirectory: true) - - if FileManager.default.fileExists(atPath: basePath!.path) { - return - } - - do { - let defaultsFileDir = basePath?.appendingPathComponent("chains").appendingPathComponent("ethereum") - let defaultsFile = defaultsFileDir?.appendingPathComponent("user_defaults") - - try FileManager.default.createDirectory(atPath: (defaultsFileDir?.path)!, withIntermediateDirectories: true, attributes: nil) - if !FileManager.default.fileExists(atPath: defaultsFile!.path) { - try defaultDefaults.write(to: defaultsFile!, atomically: false, encoding: String.Encoding.utf8) - } - - let configFile = basePath?.appendingPathComponent("config.toml") - } - catch {} - } - - func autostartEnabled() -> Bool { - return itemReferencesInLoginItems().existingReference != nil - } - - func itemReferencesInLoginItems() -> (existingReference: LSSharedFileListItem?, lastReference: LSSharedFileListItem?) { - let itemUrl: UnsafeMutablePointer?> = UnsafeMutablePointer?>.allocate(capacity: 1) - if let appUrl: NSURL = NSURL.fileURL(withPath: Bundle.main.bundlePath) as NSURL? { - let loginItemsRef = LSSharedFileListCreate( - nil, - kLSSharedFileListSessionLoginItems.takeRetainedValue(), - nil - ).takeRetainedValue() as LSSharedFileList? - if loginItemsRef != nil { - let loginItems: NSArray = LSSharedFileListCopySnapshot(loginItemsRef, nil).takeRetainedValue() as NSArray - if(loginItems.count > 0) - { - let lastItemRef: LSSharedFileListItem = loginItems.lastObject as! LSSharedFileListItem - for i in 0 ..< loginItems.count { - let currentItemRef: LSSharedFileListItem = loginItems.object(at: i) as! LSSharedFileListItem - if LSSharedFileListItemResolve(currentItemRef, 0, itemUrl, nil) == noErr { - if let urlRef: NSURL = itemUrl.pointee?.takeRetainedValue() { - if urlRef.isEqual(appUrl) { - return (currentItemRef, lastItemRef) - } - } - } - } - //The application was not found in the startup list - return (nil, lastItemRef) - } - else - { - let addAtStart: LSSharedFileListItem = kLSSharedFileListItemBeforeFirst.takeRetainedValue() - return(nil, addAtStart) - } - } - } - return (nil, nil) - } - - func toggleLaunchAtStartup() { - let itemReferences = itemReferencesInLoginItems() - let shouldBeToggled = (itemReferences.existingReference == nil) - let loginItemsRef = LSSharedFileListCreate( - nil, - kLSSharedFileListSessionLoginItems.takeRetainedValue(), - nil - ).takeRetainedValue() as LSSharedFileList? - if loginItemsRef != nil { - if shouldBeToggled { - if let appUrl : CFURL = NSURL.fileURL(withPath: Bundle.main.bundlePath) as CFURL? { - LSSharedFileListInsertItemURL( - loginItemsRef, - itemReferences.lastReference, - nil, - nil, - appUrl, - nil, - nil - ) - } - } else { - if let itemRef = itemReferences.existingReference { - LSSharedFileListItemRemove(loginItemsRef,itemRef) - } - } - } - } - - func launchParity() { - self.commandLine = CommandLine.arguments.dropFirst().filter({ $0 != "ui"}) - - let processes = GetBSDProcessList()! - let parityProcess = processes.index(where: { - var name = $0.kp_proc.p_comm - let str = withUnsafePointer(to: &name) { - $0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: name)) { - String(cString: $0) - } - } - return str == "parity" - }) - - if parityProcess == nil { - let parity = Process() - let p = self.parityPath() - parity.launchPath = p//self.parityPath() - parity.arguments = self.commandLine - parity.launch() - self.parityPid = parity.processIdentifier - } else { - self.parityPid = processes[parityProcess!].kp_proc.p_pid - } - } - - func applicationDidFinishLaunching(_ aNotification: Notification) { - if self.isAlreadyRunning() { - openUI() - NSApplication.shared().terminate(self) - return - } - - self.writeConfigFiles() - self.launchParity() - Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: {_ in - if !self.isParityRunning() { - NSApplication.shared().terminate(self) - } - }) - - let icon = NSImage(named: "statusIcon") - icon?.isTemplate = true // best for dark mode - statusItem.image = icon - statusItem.menu = statusMenu - } - - override func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { - if menuItem == self.startAtLogonMenuItem! { - menuItem.state = self.autostartEnabled() ? NSOnState : NSOffState - } - return true - } - - @IBAction func quitClicked(_ sender: NSMenuItem) { - self.killParity() - NSApplication.shared().terminate(self) - } - - @IBAction func openClicked(_ sender: NSMenuItem) { - self.openUI() - } - - @IBAction func startAtLogonClicked(_ sender: NSMenuItem) { - self.toggleLaunchAtStartup() - } - -} diff --git a/mac/Parity/Assets.xcassets/AppIcon.appiconset/Contents.json b/mac/Parity/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 9d59e8b3a56f792f47af2d5deea7d467ff6c2e9f..0000000000000000000000000000000000000000 --- a/mac/Parity/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "images" : [ - { - "idiom" : "mac", - "size" : "16x16", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "16x16", - "scale" : "2x" - }, - { - "idiom" : "mac", - "size" : "32x32", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "32x32", - "scale" : "2x" - }, - { - "idiom" : "mac", - "size" : "128x128", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "128x128", - "scale" : "2x" - }, - { - "idiom" : "mac", - "size" : "256x256", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "256x256", - "scale" : "2x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "Parity.png", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "512x512", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/mac/Parity/Assets.xcassets/AppIcon.appiconset/Parity.png b/mac/Parity/Assets.xcassets/AppIcon.appiconset/Parity.png deleted file mode 100644 index a7f085dab7a3db0028b50aa965f0ddb690affcff..0000000000000000000000000000000000000000 Binary files a/mac/Parity/Assets.xcassets/AppIcon.appiconset/Parity.png and /dev/null differ diff --git a/mac/Parity/Assets.xcassets/Contents.json b/mac/Parity/Assets.xcassets/Contents.json deleted file mode 100644 index da4a164c918651cdd1e11dca5cc62c333f097601..0000000000000000000000000000000000000000 --- a/mac/Parity/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/mac/Parity/Assets.xcassets/statusIcon.imageset/Contents.json b/mac/Parity/Assets.xcassets/statusIcon.imageset/Contents.json deleted file mode 100644 index b709bf58b25c78056da7646498c0b0bad4c6990b..0000000000000000000000000000000000000000 --- a/mac/Parity/Assets.xcassets/statusIcon.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "Parity-1.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "Parity.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "Parity-2.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/mac/Parity/Assets.xcassets/statusIcon.imageset/Parity-1.png b/mac/Parity/Assets.xcassets/statusIcon.imageset/Parity-1.png deleted file mode 100644 index 75767ebd7d6fe6b52b9edc86cd76c7528a3b3ee8..0000000000000000000000000000000000000000 Binary files a/mac/Parity/Assets.xcassets/statusIcon.imageset/Parity-1.png and /dev/null differ diff --git a/mac/Parity/Assets.xcassets/statusIcon.imageset/Parity-2.png b/mac/Parity/Assets.xcassets/statusIcon.imageset/Parity-2.png deleted file mode 100644 index 6a1106f5f1a9e3d7c94c74cd194513ff1a5813d9..0000000000000000000000000000000000000000 Binary files a/mac/Parity/Assets.xcassets/statusIcon.imageset/Parity-2.png and /dev/null differ diff --git a/mac/Parity/Assets.xcassets/statusIcon.imageset/Parity.png b/mac/Parity/Assets.xcassets/statusIcon.imageset/Parity.png deleted file mode 100644 index dfbda8ea3cf35f955d256a20fb65e5a80c9c89fb..0000000000000000000000000000000000000000 Binary files a/mac/Parity/Assets.xcassets/statusIcon.imageset/Parity.png and /dev/null differ diff --git a/mac/Parity/Base.lproj/MainMenu.xib b/mac/Parity/Base.lproj/MainMenu.xib deleted file mode 100644 index 2f52c80ad26832f8ba32b94c5d40db6b64d1fbaa..0000000000000000000000000000000000000000 --- a/mac/Parity/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mac/Parity/GetBSDProcessList.swift b/mac/Parity/GetBSDProcessList.swift deleted file mode 100644 index 6737787be8c37c22e3989e4773574f198b1bfe00..0000000000000000000000000000000000000000 --- a/mac/Parity/GetBSDProcessList.swift +++ /dev/null @@ -1,59 +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 . - - -// Based on https://github.com/soh335/GetBSDProcessList - -import Foundation -import Darwin - -public func GetBSDProcessList() -> ([kinfo_proc]?) { - - var done = false - var result: [kinfo_proc]? - var err: Int32 - - repeat { - let name = [CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0]; - let namePointer = name.withUnsafeBufferPointer { UnsafeMutablePointer(mutating: $0.baseAddress) } - var length: Int = 0 - - err = sysctl(namePointer, u_int(name.count), nil, &length, nil, 0) - if err == -1 { - err = errno - } - - if err == 0 { - let count = length / MemoryLayout.stride - result = [kinfo_proc](repeating: kinfo_proc(), count: count) - err = result!.withUnsafeMutableBufferPointer({ ( p: inout UnsafeMutableBufferPointer) -> Int32 in - return sysctl(namePointer, u_int(name.count), p.baseAddress, &length, nil, 0) - }) - switch err { - case 0: - done = true - case -1: - err = errno - case ENOMEM: - err = 0 - default: - fatalError() - } - } - } while err == 0 && !done - - return result -} diff --git a/mac/Parity/Info.plist b/mac/Parity/Info.plist deleted file mode 100644 index e0bdc21e695aa88bd4671d1b03689bd035046d74..0000000000000000000000000000000000000000 --- a/mac/Parity/Info.plist +++ /dev/null @@ -1,36 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.12 - CFBundleVersion - 1 - LSApplicationCategoryType - public.app-category.finance - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - LSUIElement - - NSHumanReadableCopyright - Copyright © 2017 Parity Technologies. All rights reserved. - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/mac/install-licence.txt b/mac/install-licence.txt deleted file mode 100644 index 733c072369ca77331f392c40da7404c85c36542c..0000000000000000000000000000000000000000 --- a/mac/install-licence.txt +++ /dev/null @@ -1,675 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - {one line to give the program's name and a brief idea of what it does.} - Copyright (C) {year} {name of author} - - This program 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. - - This program 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 this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - {project} Copyright (C) {year} {fullname} - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. - diff --git a/mac/install-readme.txt b/mac/install-readme.txt deleted file mode 100644 index 51f0330bbd65fbef3c9d8bb30e0a5fb4e0733fba..0000000000000000000000000000000000000000 --- a/mac/install-readme.txt +++ /dev/null @@ -1,8 +0,0 @@ -Parity Wallet -============= - -Welcome to Parity Wallet, your all-in-one Ethereum node and wallet. - -If you continue, Parity will be installed as a user service. You will be able to use the Parity Wallet through your browser by using the menu bar icon, following the shortcut in the Launchpad or navigating to http://localhost:8180/ in your browser. - -Parity is distributed under the terms of the GPL. diff --git a/mac/post-install.sh b/mac/post-install.sh deleted file mode 100755 index fc71ee1de6d4b3f6e492a9fffcbd989c0c1af557..0000000000000000000000000000000000000000 --- a/mac/post-install.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -# uninstall any ancient version -test -f /usr/local/libexec/uninstall-parity.sh && /usr/local/libexec/uninstall-parity.sh || true -killall -9 parity && sleep 5 -su $USER -c "open /Applications/Parity\ Ethereum.app" -exit 0 diff --git a/mac/uninstall-parity.sh b/mac/uninstall-parity.sh deleted file mode 100755 index 840dba1f6091e5d2b6fa3b7664c3636c11a92334..0000000000000000000000000000000000000000 --- a/mac/uninstall-parity.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -if [[ "$SUDO_USER" == "" ]] ; then - echo "This script requires elevated privileges." - sudo $0 - exit; -fi - -PLIST=~/Library/LaunchAgents/io.parity.ethereum.plist -su $SUDO_USER -c "launchctl stop io.parity.ethereum" -su $SUDO_USER -c "launchctl unload $PLIST" -rm -f /usr/local/libexec/parity /usr/local/libexec/uninstall-parity.sh /usr/local/bin/ethstore /usr/local/bin/ethkey /usr/local/bin/parity-evm $PLIST diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 075a42d7319ba9fd4df8f5132c65749a2597cc3c..a3f640fe57713e13bb4154fbd49dd8bff37aedeb 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -95,22 +95,6 @@ pub trait Transactions: LiveBlock { fn transactions(&self) -> &[Self::Transaction]; } -/// Trait for blocks which have finalized information. -pub trait Finalizable: LiveBlock { - /// Get whether the block is finalized. - fn is_finalized(&self) -> bool; - /// Mark the block as finalized. - fn mark_finalized(&mut self); -} - -/// A state machine with block metadata. -pub trait WithMetadata: LiveBlock { - /// Get the current live block metadata. - fn metadata(&self) -> Option<&[u8]>; - /// Set the current live block metadata. - fn set_metadata(&mut self, value: Option>); -} - /// Generalization of types surrounding blockchain-suitable state machines. pub trait Machine: for<'a> LocalizedMachine<'a> { /// The block header type. diff --git a/miner/Cargo.toml b/miner/Cargo.toml index 707352484e2da2ba05a51f07b9b6aaf9a981dfa8..0f4c2c2dba76288055f25548395712eccfac29bd 100644 --- a/miner/Cargo.toml +++ b/miner/Cargo.toml @@ -8,27 +8,26 @@ 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" -error-chain = "0.11" +error-chain = "0.12" ethcore-transaction = { path = "../ethcore/transaction" } ethereum-types = "0.3" futures = "0.1" futures-cpupool = "0.1" heapsize = "0.4" -keccak-hash = { path = "../util/hash" } +keccak-hash = { git = "https://github.com/paritytech/parity-common" } linked-hash-map = "0.5" log = "0.3" -parking_lot = "0.5" -price-info = { path = "../price-info" } -rayon = "1.0" -rlp = { path = "../util/rlp" } +parking_lot = "0.6" +price-info = { path = "../price-info", optional = true } +rlp = { git = "https://github.com/paritytech/parity-common" } trace-time = { path = "../util/trace-time" } transaction-pool = { path = "../transaction-pool" } @@ -36,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/external.rs b/miner/src/external.rs index b49a9a4e2c35c9f5fa58906a134c72a1a2d11907..a56be42f02125b0c24a4c5fa3399bc70f58531e7 100644 --- a/miner/src/external.rs +++ b/miner/src/external.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -106,7 +106,6 @@ mod tests { m.submit_hashrate(U256::from(15), H256::from(1)); m.submit_hashrate(U256::from(20), H256::from(2)); - // then assert_eq!(m.hashrate(), U256::from(35)); } diff --git a/miner/src/gas_price_calibrator.rs b/miner/src/gas_price_calibrator.rs new file mode 100644 index 0000000000000000000000000000000000000000..d2978220a6a15049e572ea7fc5bc06789779235d --- /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 f826ccf77d5f25840d4768f06ea165a05e728b2a..3287783652958c06b14660350eb1bf6e865cac2b 100644 --- a/miner/src/gas_pricer.rs +++ b/miner/src/gas_pricer.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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 08ea7d204fb520d7e79f6a88d282ff8e3f0549b0..e1ae0a9e05c3d8e0123f287288f4772c6450d10a 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -28,16 +28,17 @@ 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 rayon; extern crate rlp; -extern crate trace_time; extern crate transaction_pool as txpool; #[macro_use] extern crate error_chain; #[macro_use] extern crate log; +#[macro_use] +extern crate trace_time; #[cfg(test)] extern crate rustc_hex; @@ -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/client.rs b/miner/src/pool/client.rs index 622e9a84927e39367e1f21cf09864f505dc2f056..bdf57312eecc8cdb801765788ea0837e304e6eb2 100644 --- a/miner/src/pool/client.rs +++ b/miner/src/pool/client.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/miner/src/pool/listener.rs b/miner/src/pool/listener.rs index 3f42372e840836d072cde190e13be467c4121333..e881a2ba29d9cf84043eec69f656f0c1a7269ac7 100644 --- a/miner/src/pool/listener.rs +++ b/miner/src/pool/listener.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -64,7 +64,6 @@ impl txpool::Listener for Notifier { } } - /// Transaction pool logger. #[derive(Default, Debug)] pub struct Logger; @@ -113,7 +112,6 @@ impl txpool::Listener for Logger { } } - #[cfg(test)] mod tests { use super::*; diff --git a/miner/src/pool/local_transactions.rs b/miner/src/pool/local_transactions.rs index 12ffa84c19b60e20a6bc4a83a3447edd6e8d8df9..d69da3347acfd49ee6404778236ede98d2c6dbb0 100644 --- a/miner/src/pool/local_transactions.rs +++ b/miner/src/pool/local_transactions.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -190,7 +190,6 @@ impl txpool::Listener for LocalTransactionsList { self.clear_old(); } - /// The transaction has been mined. fn mined(&mut self, tx: &Arc) { if !tx.priority().is_local() { diff --git a/miner/src/pool/mod.rs b/miner/src/pool/mod.rs index 45d28f3c1217b02aaf4b6362cdf1f10991a61789..4a1223226d488b31da149973277c23b54aee7808 100644 --- a/miner/src/pool/mod.rs +++ b/miner/src/pool/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -16,7 +16,7 @@ //! Transaction Pool -use ethereum_types::{H256, Address}; +use ethereum_types::{U256, H256, Address}; use heapsize::HeapSizeOf; use transaction; use txpool; @@ -45,21 +45,58 @@ pub enum PrioritizationStrategy { GasPriceOnly, } -/// Transaction priority. +/// Transaction ordering when requesting pending set. #[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum PendingOrdering { + /// Get pending transactions ordered by their priority (potentially expensive) + Priority, + /// Get pending transactions without any care of particular ordering (cheaper). + Unordered, +} + +/// Pending set query settings +#[derive(Debug, Clone)] +pub struct PendingSettings { + /// Current block number (affects readiness of some transactions). + pub block_number: u64, + /// Current timestamp (affects readiness of some transactions). + pub current_timestamp: u64, + /// Nonce cap (for dust protection; EIP-168) + pub nonce_cap: Option, + /// Maximal number of transactions in pending the set. + pub max_len: usize, + /// Ordering of transactions. + pub ordering: PendingOrdering, +} + +impl PendingSettings { + /// Get all transactions (no cap or len limit) prioritized. + pub fn all_prioritized(block_number: u64, current_timestamp: u64) -> Self { + PendingSettings { + block_number, + current_timestamp, + nonce_cap: None, + max_len: usize::max_value(), + ordering: PendingOrdering::Priority, + } + } +} + +/// Transaction priority. +#[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Copy)] pub(crate) enum Priority { - /// Local transactions (high priority) - /// - /// Transactions either from a local account or - /// submitted over local RPC connection via `eth_sendRawTransaction` - Local, + /// Regular transactions received over the network. (no priority boost) + Regular, /// Transactions from retracted blocks (medium priority) /// /// When block becomes non-canonical we re-import the transactions it contains /// to the queue and boost their priority. Retracted, - /// Regular transactions received over the network. (no priority boost) - Regular, + /// Local transactions (high priority) + /// + /// Transactions either from a local account or + /// submitted over local RPC connection via `eth_sendRawTransaction` + Local, } impl Priority { diff --git a/miner/src/pool/queue.rs b/miner/src/pool/queue.rs index 8cf4534b7633029dd5203758a0e697cd46cd9069..d11052108446da4f5d90a455172bda089aa8a736 100644 --- a/miner/src/pool/queue.rs +++ b/miner/src/pool/queue.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -19,15 +19,17 @@ 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; -use rayon::prelude::*; use transaction; use txpool::{self, Verifier}; -use pool::{self, scoring, verifier, client, ready, listener, PrioritizationStrategy}; +use pool::{ + self, scoring, verifier, client, ready, listener, + PrioritizationStrategy, PendingOrdering, PendingSettings, +}; use pool::local_transactions::LocalTransactionsList; type Listener = (LocalTransactionsList, (listener::Notifier, listener::Logger)); @@ -41,6 +43,14 @@ type Pool = txpool::Pool, has_local_pending: bool, pending: Option>>, + max_len: usize, } impl CachedPending { @@ -86,6 +97,7 @@ impl CachedPending { has_local_pending: false, pending: None, nonce_cap: None, + max_len: 0, } } @@ -100,6 +112,7 @@ impl CachedPending { block_number: u64, current_timestamp: u64, nonce_cap: Option<&U256>, + max_len: usize, ) -> Option>> { // First check if we have anything in cache. let pending = self.pending.as_ref()?; @@ -124,10 +137,59 @@ impl CachedPending { return None; } - Some(pending.clone()) + // It's fine to just take a smaller subset, but not other way around. + if max_len > self.max_len { + return None; + } + + Some(pending.iter().take(max_len).cloned().collect()) + } +} + +#[derive(Debug)] +struct RecentlyRejected { + inner: RwLock>, + 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: @@ -140,6 +202,7 @@ pub struct TransactionQueue { pool: RwLock, options: RwLock, cached_pending: RwLock, + recently_rejected: RecentlyRejected, } impl TransactionQueue { @@ -149,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)), } } @@ -174,18 +239,57 @@ impl TransactionQueue { transactions: Vec, ) -> Vec> { // Run verification - let _timer = ::trace_time::PerfTimer::new("queue::verifyAndImport"); + trace_time!("pool::verify_and_import"); let options = self.options.read().clone(); - let verifier = verifier::Verifier::new(client, options, self.insertion_id.clone()); + let transaction_to_replace = { + if options.no_early_reject { + None + } else { + let pool = self.pool.read(); + if pool.is_full() { + pool.worst_transaction().map(|worst| (pool.scoring().clone(), worst)) + } else { + None + } + } + }; + + let verifier = verifier::Verifier::new( + client, + options, + self.insertion_id.clone(), + transaction_to_replace, + ); + let results = transactions - .into_par_iter() - .map(|transaction| verifier.verify_transaction(transaction)) - .map(|result| result.and_then(|verified| { - self.pool.write().import(verified) - .map(|_imported| ()) - .map_err(convert_error) - })) + .into_iter() + .map(|transaction| { + 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); + } + + 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) + }, + } + }) .collect::>(); // Notify about imported transactions. @@ -198,13 +302,26 @@ impl TransactionQueue { results } - /// Returns all transactions in the queue ordered by priority. + /// Returns all transactions in the queue without explicit ordering. pub fn all_transactions(&self) -> Vec> { let ready = |_tx: &pool::VerifiedTransaction| txpool::Readiness::Ready; - self.pool.read().pending(ready).collect() + self.pool.read().unordered_pending(ready).collect() } - /// Returns current pneding transactions. + /// 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. /// Re-computing the pending set is possible with `#collect_pending` method, @@ -212,24 +329,31 @@ impl TransactionQueue { pub fn pending( &self, client: C, - block_number: u64, - current_timestamp: u64, - nonce_cap: Option, + settings: PendingSettings, ) -> Vec> where C: client::NonceClient, { - - if let Some(pending) = self.cached_pending.read().pending(block_number, current_timestamp, nonce_cap.as_ref()) { + let PendingSettings { block_number, current_timestamp, nonce_cap, max_len, ordering } = settings; + if let Some(pending) = self.cached_pending.read().pending(block_number, current_timestamp, nonce_cap.as_ref(), max_len) { return pending; } // Double check after acquiring write lock let mut cached_pending = self.cached_pending.write(); - if let Some(pending) = cached_pending.pending(block_number, current_timestamp, nonce_cap.as_ref()) { + if let Some(pending) = cached_pending.pending(block_number, current_timestamp, nonce_cap.as_ref(), max_len) { return pending; } - let pending: Vec<_> = self.collect_pending(client, block_number, current_timestamp, nonce_cap, |i| i.collect()); + // In case we don't have a cached set, but we don't care about order + // just return the unordered set. + if let PendingOrdering::Unordered = ordering { + let ready = Self::ready(client, block_number, current_timestamp, nonce_cap); + return self.pool.read().unordered_pending(ready).take(max_len).collect(); + } + + let pending: Vec<_> = self.collect_pending(client, block_number, current_timestamp, nonce_cap, |i| { + i.take(max_len).collect() + }); *cached_pending = CachedPending { block_number, @@ -237,6 +361,7 @@ impl TransactionQueue { nonce_cap, has_local_pending: self.has_local_pending_transactions(), pending: Some(pending.clone()), + max_len, }; pending @@ -261,22 +386,35 @@ impl TransactionQueue { scoring::NonceAndGasPrice, Listener, >) -> T, + { + debug!(target: "txqueue", "Re-computing pending set for block: {}", block_number); + trace_time!("pool::collect_pending"); + let ready = Self::ready(client, block_number, current_timestamp, nonce_cap); + collect(self.pool.read().pending(ready)) + } + + fn ready( + client: C, + block_number: u64, + current_timestamp: u64, + nonce_cap: Option, + ) -> (ready::Condition, ready::State) where + C: client::NonceClient, { let pending_readiness = ready::Condition::new(block_number, current_timestamp); // don't mark any transactions as stale at this point. let stale_id = None; let state_readiness = ready::State::new(client, stale_id, nonce_cap); - let ready = (pending_readiness, state_readiness); - - collect(self.pool.read().pending(ready)) + (pending_readiness, state_readiness) } /// 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. @@ -291,9 +429,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()); } @@ -410,8 +558,13 @@ impl TransactionQueue { let mut pool = self.pool.write(); (pool.listener_mut().1).0.add(f); } -} + /// Check if pending set is cached. + #[cfg(test)] + pub fn is_pending_cached(&self) -> bool { + self.cached_pending.read().pending.is_some() + } +} fn convert_error(err: txpool::Error) -> transaction::Error { use self::txpool::ErrorKind; @@ -436,7 +589,7 @@ mod tests { fn should_get_pending_transactions() { let queue = TransactionQueue::new(txpool::Options::default(), verifier::Options::default(), PrioritizationStrategy::GasPriceOnly); - let pending: Vec<_> = queue.pending(TestClient::default(), 0, 0, None); + let pending: Vec<_> = queue.pending(TestClient::default(), PendingSettings::all_prioritized(0, 0)); for tx in pending { assert!(tx.signed().nonce > 0.into()); diff --git a/miner/src/pool/ready.rs b/miner/src/pool/ready.rs index c2829b34a9ac75394b1e488ca8ece666e49f598a..4ad7f05ee665f3113d78844743be27865c1530cc 100644 --- a/miner/src/pool/ready.rs +++ b/miner/src/pool/ready.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -83,7 +83,6 @@ impl txpool::Ready for State { _ => {}, } - let sender = tx.sender(); let state = &self.state; let state_nonce = || state.account_nonce(sender); @@ -130,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 aedc40e1f2cc879867a0b6bdf49ab6daa0a214e8..dbe3c08f4533feb25a83c15ab4e848c8d3b0b6db 100644 --- a/miner/src/pool/scoring.rs +++ b/miner/src/pool/scoring.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -30,20 +30,43 @@ use std::cmp; use ethereum_types::U256; -use txpool; -use super::{PrioritizationStrategy, VerifiedTransaction}; +use txpool::{self, scoring}; +use super::{verifier, PrioritizationStrategy, VerifiedTransaction}; /// Transaction with the same (sender, nonce) can be replaced only if /// `new_gas_price > old_gas_price + old_gas_price >> SHIFT` const GAS_PRICE_BUMP_SHIFT: usize = 3; // 2 = 25%, 3 = 12.5%, 4 = 6.25% +/// Calculate minimal gas price requirement. +#[inline] +fn bump_gas_price(old_gp: U256) -> U256 { + old_gp.saturating_add(old_gp >> GAS_PRICE_BUMP_SHIFT) +} + /// Simple, gas-price based scoring for transactions. /// /// NOTE: Currently penalization does not apply to new transactions that enter the pool. /// We might want to store penalization status in some persistent state. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct NonceAndGasPrice(pub PrioritizationStrategy); +impl NonceAndGasPrice { + /// Decide if the transaction should even be considered into the pool (if the pool is full). + /// + /// Used by Verifier to quickly reject transactions that don't have any chance to get into the pool later on, + /// and save time on more expensive checks like sender recovery, etc. + /// + /// NOTE The method is never called for zero-gas-price transactions or local transactions + /// (such transactions are always considered to the pool and potentially rejected later on) + pub fn should_reject_early(&self, old: &VerifiedTransaction, new: &verifier::Transaction) -> bool { + if old.priority().is_local() { + return true + } + + &old.transaction.gas_price > new.gas_price() + } +} + impl txpool::Scoring for NonceAndGasPrice { type Score = U256; type Event = (); @@ -52,24 +75,24 @@ 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; let new_gp = new.transaction.gas_price; - let min_required_gp = old_gp + (old_gp >> GAS_PRICE_BUMP_SHIFT); + 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(_) => {}, @@ -99,24 +122,30 @@ 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 - if new.transaction.nonce < old.transaction.nonce { - return true + match new.transaction.nonce.cmp(&old.transaction.nonce) { + cmp::Ordering::Less => scoring::Choice::ReplaceOld, + cmp::Ordering::Greater => scoring::Choice::RejectNew, + cmp::Ordering::Equal => self.choose(old, new), } - } - - // Always kick out non-local transactions in favour of local ones. - if new.priority().is_local() && !old.priority().is_local() { - return true; - } - // And never kick out local transactions in favour of external ones. - if !new.priority().is_local() && old.priority.is_local() { - return false; - } + } 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); + if new_score > old_score { + scoring::Choice::ReplaceOld + } else { + scoring::Choice::RejectNew + } + } + } - self.choose(old, new) == txpool::scoring::Choice::ReplaceOld + fn should_ignore_sender_limit(&self, new: &VerifiedTransaction) -> bool { + new.priority().is_local() } } @@ -125,31 +154,118 @@ mod tests { use super::*; use std::sync::Arc; + use ethkey::{Random, Generator}; use pool::tests::tx::{Tx, TxExt}; use txpool::Scoring; + use txpool::scoring::Choice::*; #[test] - fn should_replace_non_local_transaction_with_local_one() { + fn should_replace_same_sender_by_nonce() { + let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly); + + let tx1 = Tx { + nonce: 1, + gas_price: 1, + ..Default::default() + }; + let tx2 = Tx { + nonce: 2, + gas_price: 100, + ..Default::default() + }; + let tx3 = Tx { + nonce: 2, + gas_price: 110, + ..Default::default() + }; + let tx4 = Tx { + nonce: 2, + gas_price: 130, + ..Default::default() + }; + + let keypair = Random.generate().unwrap(); + let txs = vec![tx1, tx2, tx3, tx4].into_iter().enumerate().map(|(i, tx)| { + let verified = tx.unsigned().sign(keypair.secret(), None).verified(); + txpool::Transaction { + insertion_id: i as u64, + transaction: Arc::new(verified), + } + }).collect::>(); + + assert_eq!(scoring.should_replace(&txs[0], &txs[1]), RejectNew); + assert_eq!(scoring.should_replace(&txs[1], &txs[0]), ReplaceOld); + + assert_eq!(scoring.should_replace(&txs[1], &txs[2]), RejectNew); + assert_eq!(scoring.should_replace(&txs[2], &txs[1]), RejectNew); + + assert_eq!(scoring.should_replace(&txs[1], &txs[3]), ReplaceOld); + assert_eq!(scoring.should_replace(&txs[3], &txs[1]), RejectNew); + } + + #[test] + fn should_replace_different_sender_by_priority_and_gas_price() { // given let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly); - let tx1 = { - let tx = Tx::default().signed().verified(); + let tx_regular_low_gas = { + let tx = Tx { + nonce: 1, + gas_price: 1, + ..Default::default() + }; + let verified_tx = tx.signed().verified(); txpool::Transaction { insertion_id: 0, - transaction: Arc::new(tx), + transaction: Arc::new(verified_tx), } }; - let tx2 = { - let mut tx = Tx::default().signed().verified(); - tx.priority = ::pool::Priority::Local; + let tx_regular_high_gas = { + let tx = Tx { + nonce: 2, + gas_price: 10, + ..Default::default() + }; + let verified_tx = tx.signed().verified(); txpool::Transaction { - insertion_id: 0, - transaction: Arc::new(tx), + insertion_id: 1, + transaction: Arc::new(verified_tx), } }; + let tx_local_low_gas = { + let tx = Tx { + nonce: 2, + gas_price: 1, + ..Default::default() + }; + let mut verified_tx = tx.signed().verified(); + verified_tx.priority = ::pool::Priority::Local; + txpool::Transaction { + insertion_id: 2, + transaction: Arc::new(verified_tx), + } + }; + let tx_local_high_gas = { + let tx = Tx { + nonce: 1, + gas_price: 10, + ..Default::default() + }; + let mut verified_tx = tx.signed().verified(); + verified_tx.priority = ::pool::Priority::Local; + txpool::Transaction { + insertion_id: 3, + transaction: Arc::new(verified_tx), + } + }; + + 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_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(&tx1, &tx2)); - assert!(!scoring.should_replace(&tx2, &tx1)); + 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] @@ -173,35 +289,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/client.rs b/miner/src/pool/tests/client.rs index a00cc541ebc036a7046288c63cce07b379048ecc..08b43f12adf0f76a9b4a40b1187054c383b21a6d 100644 --- a/miner/src/pool/tests/client.rs +++ b/miner/src/pool/tests/client.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::sync::{atomic, Arc}; + use ethereum_types::{U256, H256, Address}; use rlp::Rlp; use transaction::{self, Transaction, SignedTransaction, UnverifiedTransaction}; @@ -25,6 +27,7 @@ const MAX_TRANSACTION_SIZE: usize = 15 * 1024; #[derive(Debug, Clone)] pub struct TestClient { + verification_invoked: Arc, account_details: AccountDetails, gas_required: U256, is_service_transaction: bool, @@ -35,6 +38,7 @@ pub struct TestClient { impl Default for TestClient { fn default() -> Self { TestClient { + verification_invoked: Default::default(), account_details: AccountDetails { nonce: 123.into(), balance: 63_100.into(), @@ -88,6 +92,10 @@ impl TestClient { insertion_id: 1, } } + + pub fn was_verification_triggered(&self) -> bool { + self.verification_invoked.load(atomic::Ordering::SeqCst) + } } impl pool::client::Client for TestClient { @@ -98,6 +106,7 @@ impl pool::client::Client for TestClient { fn verify_transaction(&self, tx: UnverifiedTransaction) -> Result { + self.verification_invoked.store(true, atomic::Ordering::SeqCst); Ok(SignedTransaction::new(tx)?) } diff --git a/miner/src/pool/tests/mod.rs b/miner/src/pool/tests/mod.rs index 85dedaaa45bf96e492a119b1313ecd1f565621a2..7fd486b0f67f55a365a8c3d3dc13e56a5c031885 100644 --- a/miner/src/pool/tests/mod.rs +++ b/miner/src/pool/tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -18,7 +18,7 @@ use ethereum_types::U256; use transaction::{self, PendingTransaction}; use txpool; -use pool::{verifier, TransactionQueue, PrioritizationStrategy}; +use pool::{verifier, TransactionQueue, PrioritizationStrategy, PendingSettings, PendingOrdering}; pub mod tx; pub mod client; @@ -37,11 +37,11 @@ fn new_queue() -> TransactionQueue { minimal_gas_price: 1.into(), block_gas_limit: 1_000_000.into(), tx_gas_limit: 1_000_000.into(), + no_early_reject: false, }, PrioritizationStrategy::GasPriceOnly, ) } - #[test] fn should_return_correct_nonces_when_dropped_because_of_limit() { // given @@ -55,6 +55,7 @@ fn should_return_correct_nonces_when_dropped_because_of_limit() { minimal_gas_price: 1.into(), block_gas_limit: 1_000_000.into(), tx_gas_limit: 1_000_000.into(), + no_early_reject: false, }, PrioritizationStrategy::GasPriceOnly, ); @@ -63,8 +64,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 +78,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(), + no_early_reject: false, + }, + 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(())]); + assert_eq!(r2, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 2); + + // then + assert_eq!(txq.next_nonce(TestClient::new(), &sender), Some(nonce + 2.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, 6); + assert_eq!(txq.next_nonce(TestClient::new(), &sender), Some(nonce + 2.into())); +} + #[test] fn should_handle_same_transaction_imported_twice_with_different_state_nonces() { // given @@ -108,7 +160,7 @@ fn should_handle_same_transaction_imported_twice_with_different_state_nonces() { // and then there should be only one transaction in current (the one with higher gas_price) assert_eq!(res, vec![Ok(())]); assert_eq!(txq.status().status.transaction_count, 1); - let top = txq.pending(TestClient::new(), 0, 0, None); + let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)); assert_eq!(top[0].hash, hash); } @@ -133,7 +185,7 @@ fn should_move_all_transactions_from_future() { // then assert_eq!(res, vec![Ok(())]); assert_eq!(txq.status().status.transaction_count, 2); - let top = txq.pending(TestClient::new(), 0, 0, None); + let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)); assert_eq!(top[0].hash, hash); assert_eq!(top[1].hash, hash2); } @@ -207,7 +259,7 @@ fn should_import_txs_from_same_sender() { txq.import(TestClient::new(), txs.local().into_vec()); // then - let top = txq.pending(TestClient::new(), 0 ,0, None); + let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0 ,0)); assert_eq!(top[0].hash, hash); assert_eq!(top[1].hash, hash2); assert_eq!(top.len(), 2); @@ -229,7 +281,7 @@ fn should_prioritize_local_transactions_within_same_nonce_height() { assert_eq!(res, vec![Ok(()), Ok(())]); // then - let top = txq.pending(client, 0, 0, None); + let top = txq.pending(client, PendingSettings::all_prioritized(0, 0)); assert_eq!(top[0].hash, hash); // local should be first assert_eq!(top[1].hash, hash2); assert_eq!(top.len(), 2); @@ -251,7 +303,7 @@ fn should_prioritize_reimported_transactions_within_same_nonce_height() { assert_eq!(res, vec![Ok(()), Ok(())]); // then - let top = txq.pending(TestClient::new(), 0, 0, None); + let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)); assert_eq!(top[0].hash, hash); // retracted should be first assert_eq!(top[1].hash, hash2); assert_eq!(top.len(), 2); @@ -270,7 +322,7 @@ fn should_not_prioritize_local_transactions_with_different_nonce_height() { assert_eq!(res, vec![Ok(()), Ok(())]); // then - let top = txq.pending(TestClient::new(), 0, 0, None); + let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)); assert_eq!(top[0].hash, hash); assert_eq!(top[1].hash, hash2); assert_eq!(top.len(), 2); @@ -288,7 +340,7 @@ fn should_put_transaction_to_futures_if_gap_detected() { // then assert_eq!(res, vec![Ok(()), Ok(())]); - let top = txq.pending(TestClient::new(), 0, 0, None); + let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)); assert_eq!(top.len(), 1); assert_eq!(top[0].hash, hash); } @@ -308,9 +360,9 @@ fn should_handle_min_block() { assert_eq!(res, vec![Ok(()), Ok(())]); // then - let top = txq.pending(TestClient::new(), 0, 0, None); + let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)); assert_eq!(top.len(), 0); - let top = txq.pending(TestClient::new(), 1, 0, None); + let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(1, 0)); assert_eq!(top.len(), 2); } @@ -341,7 +393,7 @@ fn should_move_transactions_if_gap_filled() { let res = txq.import(TestClient::new(), vec![tx, tx2].local()); assert_eq!(res, vec![Ok(()), Ok(())]); assert_eq!(txq.status().status.transaction_count, 2); - assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 1); // when let res = txq.import(TestClient::new(), vec![tx1.local()]); @@ -349,7 +401,7 @@ fn should_move_transactions_if_gap_filled() { // then assert_eq!(txq.status().status.transaction_count, 3); - assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 3); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 3); } #[test] @@ -361,12 +413,12 @@ fn should_remove_transaction() { let res = txq.import(TestClient::default(), vec![tx, tx2].local()); assert_eq!(res, vec![Ok(()), Ok(())]); assert_eq!(txq.status().status.transaction_count, 2); - assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 1); // when txq.cull(TestClient::new().with_nonce(124)); assert_eq!(txq.status().status.transaction_count, 1); - assert_eq!(txq.pending(TestClient::new().with_nonce(125), 0, 0, None).len(), 1); + assert_eq!(txq.pending(TestClient::new().with_nonce(125), PendingSettings::all_prioritized(0, 0)).len(), 1); txq.cull(TestClient::new().with_nonce(126)); // then @@ -384,19 +436,19 @@ fn should_move_transactions_to_future_if_gap_introduced() { let res = txq.import(TestClient::new(), vec![tx3, tx2].local()); assert_eq!(res, vec![Ok(()), Ok(())]); assert_eq!(txq.status().status.transaction_count, 2); - assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 1); let res = txq.import(TestClient::new(), vec![tx].local()); assert_eq!(res, vec![Ok(())]); assert_eq!(txq.status().status.transaction_count, 3); - assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 3); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 3); // when txq.remove(vec![&hash], true); // then assert_eq!(txq.status().status.transaction_count, 2); - assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 1); } #[test] @@ -429,6 +481,7 @@ fn should_prefer_current_transactions_when_hitting_the_limit() { minimal_gas_price: 1.into(), block_gas_limit: 1_000_000.into(), tx_gas_limit: 1_000_000.into(), + no_early_reject: false, }, PrioritizationStrategy::GasPriceOnly, ); @@ -447,7 +500,7 @@ fn should_prefer_current_transactions_when_hitting_the_limit() { assert_eq!(res, vec![Ok(())]); assert_eq!(txq.status().status.transaction_count, 1); - let top = txq.pending(TestClient::new(), 0, 0, None); + let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)); assert_eq!(top.len(), 1); assert_eq!(top[0].hash, hash); assert_eq!(txq.next_nonce(TestClient::new(), &sender), Some(124.into())); @@ -491,23 +544,22 @@ fn should_accept_same_transaction_twice_if_removed() { let (tx1, _) = txs.clone(); let (hash, _) = txs.hash(); - let res = txq.import(TestClient::new(), txs.local().into_vec()); assert_eq!(res, vec![Ok(()), Ok(())]); assert_eq!(txq.status().status.transaction_count, 2); - assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 2); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 2); // when txq.remove(vec![&hash], true); assert_eq!(txq.status().status.transaction_count, 1); - assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 0); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 0); let res = txq.import(TestClient::new(), vec![tx1].local()); assert_eq!(res, vec![Ok(())]); // then assert_eq!(txq.status().status.transaction_count, 2); - assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 2); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 2); } #[test] @@ -527,8 +579,8 @@ fn should_not_replace_same_transaction_if_the_fee_is_less_than_minimal_bump() { // then assert_eq!(res, vec![Err(transaction::Error::TooCheapToReplace), Ok(())]); assert_eq!(txq.status().status.transaction_count, 2); - assert_eq!(txq.pending(client.clone(), 0, 0, None)[0].signed().gas_price, U256::from(20)); - assert_eq!(txq.pending(client.clone(), 0, 0, None)[1].signed().gas_price, U256::from(2)); + assert_eq!(txq.pending(client.clone(), PendingSettings::all_prioritized(0, 0))[0].signed().gas_price, U256::from(20)); + assert_eq!(txq.pending(client.clone(), PendingSettings::all_prioritized(0, 0))[1].signed().gas_price, U256::from(2)); } #[test] @@ -570,7 +622,7 @@ fn should_return_valid_last_nonce_after_cull() { let client = TestClient::new().with_nonce(124); txq.cull(client.clone()); // tx2 should be not be promoted to current - assert_eq!(txq.pending(client.clone(), 0, 0, None).len(), 0); + assert_eq!(txq.pending(client.clone(), PendingSettings::all_prioritized(0, 0)).len(), 0); // then assert_eq!(txq.next_nonce(client.clone(), &sender), None); @@ -668,7 +720,7 @@ fn should_accept_local_transactions_below_min_gas_price() { assert_eq!(res, vec![Ok(())]); // then - assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 1); } #[test] @@ -686,7 +738,7 @@ fn should_accept_local_service_transaction() { assert_eq!(res, vec![Ok(())]); // then - assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 1); } #[test] @@ -727,16 +779,77 @@ fn should_not_return_transactions_over_nonce_cap() { assert_eq!(res, vec![Ok(()), Ok(()), Ok(())]); // when - let all = txq.pending(TestClient::new(), 0, 0, None); + let all = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)); // This should invalidate the cache! - let limited = txq.pending(TestClient::new(), 0, 0, Some(123.into())); - + let limited = txq.pending(TestClient::new(), PendingSettings { + block_number: 0, + current_timestamp: 0, + nonce_cap: Some(123.into()), + max_len: usize::max_value(), + ordering: PendingOrdering::Priority, + }); // then assert_eq!(all.len(), 3); assert_eq!(limited.len(), 1); } +#[test] +fn should_return_cached_pending_even_if_unordered_is_requested() { + // given + let txq = new_queue(); + let tx1 = Tx::default().signed(); + let (tx2_1, tx2_2)= Tx::default().signed_pair(); + let tx2_1_hash = tx2_1.hash(); + let res = txq.import(TestClient::new(), vec![tx1].unverified()); + assert_eq!(res, vec![Ok(())]); + let res = txq.import(TestClient::new(), vec![tx2_1, tx2_2].local()); + assert_eq!(res, vec![Ok(()), Ok(())]); + + // when + let all = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)); + assert_eq!(all[0].hash, tx2_1_hash); + assert_eq!(all.len(), 3); + + // This should not invalidate the cache! + let limited = txq.pending(TestClient::new(), PendingSettings { + block_number: 0, + current_timestamp: 0, + nonce_cap: None, + max_len: 3, + ordering: PendingOrdering::Unordered, + }); + + // then + assert_eq!(all, limited); +} + +#[test] +fn should_return_unordered_and_not_populate_the_cache() { + // given + let txq = new_queue(); + let tx1 = Tx::default().signed(); + let (tx2_1, tx2_2)= Tx::default().signed_pair(); + let res = txq.import(TestClient::new(), vec![tx1].unverified()); + assert_eq!(res, vec![Ok(())]); + let res = txq.import(TestClient::new(), vec![tx2_1, tx2_2].local()); + assert_eq!(res, vec![Ok(()), Ok(())]); + + // when + // This should not invalidate the cache! + let limited = txq.pending(TestClient::new(), PendingSettings { + block_number: 0, + current_timestamp: 0, + nonce_cap: None, + max_len: usize::max_value(), + ordering: PendingOrdering::Unordered, + }); + + // then + assert_eq!(limited.len(), 3); + assert!(!txq.is_pending_cached()); +} + #[test] fn should_clear_cache_after_timeout_for_local() { // given @@ -750,12 +863,12 @@ fn should_clear_cache_after_timeout_for_local() { // This should populate cache and set timestamp to 1 // when - assert_eq!(txq.pending(TestClient::new(), 0, 1, None).len(), 0); - assert_eq!(txq.pending(TestClient::new(), 0, 1000, None).len(), 0); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 1)).len(), 0); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 1000)).len(), 0); // This should invalidate the cache and trigger transaction ready. // then - assert_eq!(txq.pending(TestClient::new(), 0, 1002, None).len(), 2); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 1002)).len(), 2); } #[test] @@ -781,6 +894,7 @@ fn should_include_local_transaction_to_a_full_pool() { minimal_gas_price: 1.into(), block_gas_limit: 1_000_000.into(), tx_gas_limit: 1_000_000.into(), + no_early_reject: false, }, PrioritizationStrategy::GasPriceOnly, ); @@ -798,3 +912,158 @@ fn should_include_local_transaction_to_a_full_pool() { // then assert_eq!(txq.status().status.transaction_count, 1); } + +#[test] +fn should_avoid_verifying_transaction_already_in_pool() { + // 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(), + no_early_reject: false, + }, + PrioritizationStrategy::GasPriceOnly, + ); + let client = TestClient::new().with_balance(1_000_000_000); + let tx1 = Tx::gas_price(2).signed().unverified(); + + let res = txq.import(client.clone(), vec![tx1.clone()]); + assert_eq!(res, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 1); + 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::AlreadyImported)]); + assert!(!client.was_verification_triggered()); + + // then + 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(), + no_early_reject: false, + }, + 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 + 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(), + no_early_reject: false, + }, + PrioritizationStrategy::GasPriceOnly, + ); + let client = TestClient::new().with_balance(1_000_000_000); + let tx1 = Tx::gas_price(2).signed().unverified(); + + let res = txq.import(client.clone(), vec![tx1]); + assert_eq!(res, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 1); + assert!(client.was_verification_triggered()); + + // when + let client = TestClient::new(); + let tx1 = Tx::default().signed().unverified(); + let res = txq.import(client.clone(), vec![tx1]); + assert_eq!(res, vec![Err(transaction::Error::InsufficientGasPrice { + minimal: 2.into(), + got: 1.into(), + })]); + assert!(!client.was_verification_triggered()); + + // then + assert_eq!(txq.status().status.transaction_count, 1); +} + + +#[test] +fn should_not_reject_early_in_case_gas_price_is_less_than_min_effective() { + // 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(), + no_early_reject: true, + }, + PrioritizationStrategy::GasPriceOnly, + ); + // when + let tx1 = Tx::gas_price(2).signed(); + let client = TestClient::new().with_local(&tx1.sender()); + let res = txq.import(client.clone(), vec![tx1.unverified()]); + + // then + assert_eq!(res, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 1); + assert!(client.was_verification_triggered()); + + // when + let tx1 = Tx::gas_price(1).signed(); + let client = TestClient::new().with_local(&tx1.sender()); + let res = txq.import(client.clone(), vec![tx1.unverified()]); + + // then + assert_eq!(res, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 2); + assert!(client.was_verification_triggered()); +} diff --git a/miner/src/pool/tests/tx.rs b/miner/src/pool/tests/tx.rs index c0f8751ebba8d9c6b76733f36702ced10c3a3b85..78cd85024565b18a78727f42601de43e0fc13db7 100644 --- a/miner/src/pool/tests/tx.rs +++ b/miner/src/pool/tests/tx.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -23,9 +23,9 @@ use pool::{verifier, VerifiedTransaction}; #[derive(Clone)] pub struct Tx { - nonce: u64, - gas: u64, - gas_price: u64, + pub nonce: u64, + pub gas: u64, + pub gas_price: u64, } impl Default for Tx { @@ -64,7 +64,6 @@ impl Tx { self.nonce += 1; let tx3 = self.unsigned().sign(keypair.secret(), None); - (tx1, tx2, tx3) } diff --git a/miner/src/pool/verifier.rs b/miner/src/pool/verifier.rs index 0a89a784b11177ac0bf325f3c63ffcb451149105..eaa13b3da1fb54c5e37de9f0fedc6a91da6d33e7 100644 --- a/miner/src/pool/verifier.rs +++ b/miner/src/pool/verifier.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -43,6 +43,8 @@ pub struct Options { pub block_gas_limit: U256, /// Maximal gas limit for a single transaction. pub tx_gas_limit: U256, + /// Skip checks for early rejection, to make sure that local transactions are always imported. + pub no_early_reject: bool, } #[cfg(test)] @@ -52,11 +54,13 @@ impl Default for Options { minimal_gas_price: 0.into(), block_gas_limit: U256::max_value(), tx_gas_limit: U256::max_value(), + no_early_reject: false, } } } /// Transaction to verify. +#[cfg_attr(test, derive(Clone))] pub enum Transaction { /// Fresh, never verified transaction. /// @@ -75,7 +79,8 @@ pub enum Transaction { } impl Transaction { - fn hash(&self) -> H256 { + /// Return transaction hash + pub fn hash(&self) -> H256 { match *self { Transaction::Unverified(ref tx) => tx.hash(), Transaction::Retracted(ref tx) => tx.hash(), @@ -83,20 +88,20 @@ impl Transaction { } } - fn gas(&self) -> &U256 { + /// Return transaction gas price + pub fn gas_price(&self) -> &U256 { match *self { - Transaction::Unverified(ref tx) => &tx.gas, - Transaction::Retracted(ref tx) => &tx.gas, - Transaction::Local(ref tx) => &tx.gas, + Transaction::Unverified(ref tx) => &tx.gas_price, + Transaction::Retracted(ref tx) => &tx.gas_price, + Transaction::Local(ref tx) => &tx.gas_price, } } - - fn gas_price(&self) -> &U256 { + fn gas(&self) -> &U256 { match *self { - Transaction::Unverified(ref tx) => &tx.gas_price, - Transaction::Retracted(ref tx) => &tx.gas_price, - Transaction::Local(ref tx) => &tx.gas_price, + Transaction::Unverified(ref tx) => &tx.gas, + Transaction::Retracted(ref tx) => &tx.gas, + Transaction::Local(ref tx) => &tx.gas, } } @@ -127,24 +132,31 @@ impl Transaction { /// /// Verification can be run in parallel for all incoming transactions. #[derive(Debug)] -pub struct Verifier { +pub struct Verifier { client: C, options: Options, id: Arc, + transaction_to_replace: Option<(S, Arc)>, } -impl Verifier { +impl Verifier { /// Creates new transaction verfier with specified options. - pub fn new(client: C, options: Options, id: Arc) -> Self { + pub fn new( + client: C, + options: Options, + id: Arc, + transaction_to_replace: Option<(S, Arc)>, + ) -> Self { Verifier { client, options, id, + transaction_to_replace, } } } -impl txpool::Verifier for Verifier { +impl txpool::Verifier for Verifier { type Error = transaction::Error; type VerifiedTransaction = VerifiedTransaction; @@ -163,7 +175,7 @@ impl txpool::Verifier for Verifier { if tx.gas() > &gas_limit { debug!( target: "txqueue", - "[{:?}] Dropping transaction above gas limit: {} > min({}, {})", + "[{:?}] Rejected transaction above gas limit: {} > min({}, {})", hash, tx.gas(), self.options.block_gas_limit, @@ -178,7 +190,7 @@ impl txpool::Verifier for Verifier { let minimal_gas = self.client.required_gas(tx.transaction()); if tx.gas() < &minimal_gas { trace!(target: "txqueue", - "[{:?}] Dropping transaction with insufficient gas: {} < {}", + "[{:?}] Rejected transaction with insufficient gas: {} < {}", hash, tx.gas(), minimal_gas, @@ -191,22 +203,40 @@ impl txpool::Verifier for Verifier { } let is_own = tx.is_local(); - // Quick exit for non-service transactions - if tx.gas_price() < &self.options.minimal_gas_price - && !tx.gas_price().is_zero() - && !is_own - { - trace!( - target: "txqueue", - "[{:?}] Rejected tx below minimal gas price threshold: {} < {}", - hash, - tx.gas_price(), - self.options.minimal_gas_price, - ); - bail!(transaction::Error::InsufficientGasPrice { - minimal: self.options.minimal_gas_price, - got: *tx.gas_price(), - }); + // Quick exit for non-service and non-local transactions + // + // We're checking if the transaction is below configured minimal gas price + // or the effective minimal gas price in case the pool is full. + if !tx.gas_price().is_zero() && !is_own { + if tx.gas_price() < &self.options.minimal_gas_price { + trace!( + target: "txqueue", + "[{:?}] Rejected tx below minimal gas price threshold: {} < {}", + hash, + tx.gas_price(), + self.options.minimal_gas_price, + ); + bail!(transaction::Error::InsufficientGasPrice { + minimal: self.options.minimal_gas_price, + got: *tx.gas_price(), + }); + } + + if let Some((ref scoring, ref vtx)) = self.transaction_to_replace { + if scoring.should_reject_early(vtx, &tx) { + trace!( + target: "txqueue", + "[{:?}] Rejected tx early, cause it doesn't have any chance to get to the pool: (gas price: {} < {})", + hash, + tx.gas_price(), + vtx.transaction.gas_price, + ); + bail!(transaction::Error::InsufficientGasPrice { + minimal: vtx.transaction.gas_price, + got: *tx.gas_price(), + }); + } + } } // Some more heavy checks below. diff --git a/miner/src/work_notify.rs b/miner/src/work_notify.rs index 3436938097a6ae8d17736b17335c6deb1e7b5ca5..efae26ff114a3b200c29151b3be98f44c16a189d 100644 --- a/miner/src/work_notify.rs +++ b/miner/src/work_notify.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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/nsis/installer.nsi b/nsis/installer.nsi deleted file mode 100644 index e932d53b06de7c3ec21737fb0f3090063109a333..0000000000000000000000000000000000000000 --- a/nsis/installer.nsi +++ /dev/null @@ -1,191 +0,0 @@ -!include WinMessages.nsh - -!define WND_CLASS "Parity" -!define WND_TITLE "Parity" -!define WAIT_MS 5000 -!define SYNC_TERM 0x00100001 - -!define APPNAME "Parity" -!define COMPANYNAME "Parity Technologies" -!define DESCRIPTION "Fast, light, robust Ethereum implementation" -!define VERSIONMAJOR 1 -!define VERSIONMINOR 12 -!define VERSIONBUILD 0 -!define ARGS "" -!define FIRST_START_ARGS "--mode=passive ui" - -!addplugindir .\ - -!define HELPURL "https://paritytech.github.io/wiki/" # "Support Information" link -!define UPDATEURL "https://github.com/paritytech/parity/releases" # "Product Updates" link -!define ABOUTURL "https://github.com/paritytech/parity" # "Publisher" link -!define INSTALLSIZE 26120 - -!define termMsg "Installer cannot stop running ${WND_TITLE}.$\nDo you want to terminate process?" -!define stopMsg "Stopping ${WND_TITLE} Application" - - -RequestExecutionLevel admin ;Require admin rights on NT6+ (When UAC is turned on) - -InstallDir "$PROGRAMFILES64\${COMPANYNAME}\${APPNAME}" - -LicenseData "..\LICENSE" -Name "${COMPANYNAME} ${APPNAME}" -Icon "logo.ico" -outFile "installer.exe" - -!include LogicLib.nsh - -page license -page directory -page instfiles - -!macro VerifyUserIsAdmin -UserInfo::GetAccountType -pop $0 -${If} $0 != "admin" ;Require admin rights on NT4+ - messageBox mb_iconstop "Administrator rights required!" - setErrorLevel 740 ;ERROR_ELEVATION_REQUIRED - quit -${EndIf} -!macroend - -!macro TerminateApp - Push $0 ; window handle - Push $1 - Push $2 ; process handle - DetailPrint "$(stopMsg)" - FindWindow $0 '${WND_CLASS}' '' - IntCmp $0 0 done - System::Call 'user32.dll::GetWindowThreadProcessId(i r0, *i .r1) i .r2' - System::Call 'kernel32.dll::OpenProcess(i ${SYNC_TERM}, i 0, i r1) i .r2' - SendMessage $0 ${WM_CLOSE} 0 0 /TIMEOUT=${TO_MS} - System::Call 'kernel32.dll::WaitForSingleObject(i r2, i ${WAIT_MS}) i .r1' - IntCmp $1 0 close - MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION "$(termMsg)" /SD IDYES IDYES terminate IDNO close - System::Call 'kernel32.dll::CloseHandle(i r2) i .r1' - Quit - terminate: - System::Call 'kernel32.dll::TerminateProcess(i r2, i 0) i .r1' - close: - System::Call 'kernel32.dll::CloseHandle(i r2) i .r1' - done: - Pop $2 - Pop $1 - Pop $0 -!macroend - -function .onInit - setShellVarContext all - !insertmacro VerifyUserIsAdmin -functionEnd - -section "install" - # Files for the install directory - to build the installer, these should be in the same directory as the install script (this file) - setOutPath $INSTDIR - - # Close parity if running - !insertmacro TerminateApp - - # Files added here should be removed by the uninstaller (see section "uninstall") - file /oname=parity.exe ..\artifacts\parity.exe - file /oname=parity-evm.exe ..\artifacts\parity-evm.exe - file /oname=ethstore.exe ..\artifacts\ethstore.exe - file /oname=ethkey.exe ..\artifacts\ethkey.exe - file /oname=ptray.exe ..\windows\ptray\x64\Release\ptray.exe - - file "logo.ico" - # Add any other files for the install directory (license files, app data, etc) here - - # Uninstaller - See function un.onInit and section "uninstall" for configuration - writeUninstaller "$INSTDIR\uninstall.exe" - - # Start Menu - createDirectory "$SMPROGRAMS\${COMPANYNAME}" - delete "$SMPROGRAMS\${COMPANYNAME}\${APPNAME}.lnk" - createShortCut "$SMPROGRAMS\${COMPANYNAME}\${APPNAME} Ethereum.lnk" "$INSTDIR\ptray.exe" "ui" "$INSTDIR\logo.ico" - createShortCut "$DESKTOP\${APPNAME} Ethereum.lnk" "$INSTDIR\ptray.exe" "ui" "$INSTDIR\logo.ico" - - # Firewall remove rules if exists - SimpleFC::AdvRemoveRule "Parity incoming peers (TCP:30303)" - SimpleFC::AdvRemoveRule "Parity outgoing peers (TCP:30303)" - SimpleFC::AdvRemoveRule "Parity web queries (TCP:80)" - SimpleFC::AdvRemoveRule "Parity UDP discovery (UDP:30303)" - - # Firewall exception rules - SimpleFC::AdvAddRule "Parity incoming peers (TCP:30303)" "" 6 1 1 2147483647 1 "$INSTDIR\parity.exe" "" "" "Parity" 30303 "" "" "" - SimpleFC::AdvAddRule "Parity outgoing peers (TCP:30303)" "" 6 2 1 2147483647 1 "$INSTDIR\parity.exe" "" "" "Parity" "" 30303 "" "" - SimpleFC::AdvAddRule "Parity UDP discovery (UDP:30303)" "" 17 2 1 2147483647 1 "$INSTDIR\parity.exe" "" "" "Parity" "" 30303 "" "" - - # Registry information for add/remove programs - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayName" "${APPNAME} - ${DESCRIPTION}" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "InstallLocation" "$\"$INSTDIR$\"" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayIcon" "$\"$INSTDIR\logo.ico$\"" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "Publisher" "${COMPANYNAME}" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "HelpLink" "$\"${HELPURL}$\"" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "URLUpdateInfo" "$\"${UPDATEURL}$\"" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "URLInfoAbout" "$\"${ABOUTURL}$\"" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayVersion" "${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}" - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "VersionMajor" ${VERSIONMAJOR} - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "VersionMinor" ${VERSIONMINOR} - # There is no option for modifying or repairing the install - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "NoModify" 1 - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "NoRepair" 1 - # Set the INSTALLSIZE constant (!defined at the top of this script) so Add/Remove Programs can accurately report the size - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "EstimatedSize" ${INSTALLSIZE} - - WriteRegStr HKEY_CURRENT_USER "Software\Microsoft\Windows\CurrentVersion\Run" ${APPNAME} "$INSTDIR\ptray.exe ${ARGS}" - DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "${APPNAME}" - ExecShell "" "$INSTDIR\ptray.exe" "${FIRST_START_ARGS}" -sectionEnd - -# Uninstaller - -function un.onInit - SetShellVarContext all - - #Verify the uninstaller - last chance to back out - MessageBox MB_OKCANCEL "Permanently remove ${APPNAME}?" IDOK next - Abort - - next: - !insertmacro VerifyUserIsAdmin -functionEnd - -section "uninstall" - !insertmacro TerminateApp - # Remove Start Menu launcher - delete "$SMPROGRAMS\${COMPANYNAME}\${APPNAME}.lnk" - delete "$SMPROGRAMS\${COMPANYNAME}\${APPNAME} Ethereum.lnk" - delete "$DESKTOP\${APPNAME} Ethereum.lnk" - - # Try to remove the Start Menu folder - this will only happen if it is empty - rmDir "$SMPROGRAMS\${COMPANYNAME}" - - # Remove files - delete $INSTDIR\parity.exe - delete $INSTDIR\parity-evm.exe - delete $INSTDIR\ethstore.exe - delete $INSTDIR\ethkey.exe - delete $INSTDIR\ptray.exe - delete $INSTDIR\logo.ico - - # Always delete uninstaller as the last action - delete $INSTDIR\uninstall.exe - - # Try to remove the install directory - this will only happen if it is empty - rmDir $INSTDIR - - # Firewall exception rules - SimpleFC::AdvRemoveRule "Parity incoming peers (TCP:30303)" - SimpleFC::AdvRemoveRule "Parity outgoing peers (TCP:30303)" - SimpleFC::AdvRemoveRule "Parity web queries (TCP:80)" - SimpleFC::AdvRemoveRule "Parity UDP discovery (UDP:30303)" - - # Remove uninstaller information from the registry - DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" - DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "${APPNAME}" - DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "${APPNAME}" -sectionEnd diff --git a/nsis/logo.ico b/nsis/logo.ico deleted file mode 100644 index cda99eef8b3668827befd6a13ff8268c096ceae4..0000000000000000000000000000000000000000 Binary files a/nsis/logo.ico and /dev/null differ 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 56% rename from parity-clib-example/main.cpp rename to parity-clib-examples/cpp/main.cpp index becce8598eba406b818280340fed8d16bfa99c81..c5e83d06492a3ff29a755b64a13f662ff2c711ce 100644 --- a/parity-clib-example/main.cpp +++ b/parity-clib-examples/cpp/main.cpp @@ -1,3 +1,19 @@ +// 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 . + #include #include #include diff --git a/parity-clib/Cargo.toml b/parity-clib/Cargo.toml index 001f954c211443ad13f7b5af57aba798062db978..3a1e95b5f3a1bbc61340afa56207a0cd17d1d725 100644 --- a/parity-clib/Cargo.toml +++ b/parity-clib/Cargo.toml @@ -10,8 +10,8 @@ name = "parity" crate-type = ["cdylib", "staticlib"] [dependencies] -parity = { path = "../", default-features = false } +parity-ethereum = { path = "../", default-features = false } [features] default = [] -final = ["parity/final"] +final = ["parity-ethereum/final"] diff --git a/parity-clib/src/lib.rs b/parity-clib/src/lib.rs index fe631ce8a830570e5170b22e689504953137f388..563eafd7301e9b0b315eaba718f8aed741d2a368 100644 --- a/parity-clib/src/lib.rs +++ b/parity-clib/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Note that all the structs and functions here are documented in `parity.h`, to avoid //! duplicating documentation. -extern crate parity; +extern crate parity_ethereum; use std::os::raw::{c_char, c_void, c_int}; use std::panic; @@ -56,7 +56,7 @@ pub extern fn parity_config_from_cli(args: *const *const c_char, args_lens: *con args }; - match parity::Configuration::parse_cli(&args) { + match parity_ethereum::Configuration::parse_cli(&args) { Ok(mut cfg) => { // Always disable the auto-updater when used as a library. cfg.args.arg_auto_update = "none".to_owned(); @@ -77,7 +77,7 @@ pub extern fn parity_config_from_cli(args: *const *const c_char, args_lens: *con pub extern fn parity_config_destroy(cfg: *mut c_void) { unsafe { let _ = panic::catch_unwind(|| { - let _cfg = Box::from_raw(cfg as *mut parity::Configuration); + let _cfg = Box::from_raw(cfg as *mut parity_ethereum::Configuration); }); } } @@ -89,7 +89,7 @@ pub extern fn parity_start(cfg: *const ParityParams, output: *mut *mut c_void) - *output = ptr::null_mut(); let cfg: &ParityParams = &*cfg; - let config = Box::from_raw(cfg.configuration as *mut parity::Configuration); + let config = Box::from_raw(cfg.configuration as *mut parity_ethereum::Configuration); let on_client_restart_cb = { struct Cb(Option, *mut c_void); @@ -106,16 +106,16 @@ pub extern fn parity_start(cfg: *const ParityParams, output: *mut *mut c_void) - move |new_chain: String| { cb.call(new_chain); } }; - let action = match parity::start(*config, on_client_restart_cb, || {}) { + let action = match parity_ethereum::start(*config, on_client_restart_cb, || {}) { Ok(action) => action, Err(_) => return 1, }; match action { - parity::ExecutionAction::Instant(Some(s)) => { println!("{}", s); 0 }, - parity::ExecutionAction::Instant(None) => 0, - parity::ExecutionAction::Running(client) => { - *output = Box::into_raw(Box::::new(client)) as *mut c_void; + parity_ethereum::ExecutionAction::Instant(Some(s)) => { println!("{}", s); 0 }, + parity_ethereum::ExecutionAction::Instant(None) => 0, + parity_ethereum::ExecutionAction::Running(client) => { + *output = Box::into_raw(Box::::new(client)) as *mut c_void; 0 } } @@ -127,7 +127,7 @@ pub extern fn parity_start(cfg: *const ParityParams, output: *mut *mut c_void) - pub extern fn parity_destroy(client: *mut c_void) { unsafe { let _ = panic::catch_unwind(|| { - let client = Box::from_raw(client as *mut parity::RunningClient); + let client = Box::from_raw(client as *mut parity_ethereum::RunningClient); client.shutdown(); }); } @@ -137,7 +137,7 @@ pub extern fn parity_destroy(client: *mut c_void) { pub extern fn parity_rpc(client: *mut c_void, query: *const char, len: usize, out_str: *mut c_char, out_len: *mut usize) -> c_int { unsafe { panic::catch_unwind(|| { - let client: &mut parity::RunningClient = &mut *(client as *mut parity::RunningClient); + let client: &mut parity_ethereum::RunningClient = &mut *(client as *mut parity_ethereum::RunningClient); let query_str = { let string = slice::from_raw_parts(query as *const u8, len); diff --git a/parity/account.rs b/parity/account.rs index 676cf93e7352caec4da9271301a2219907edb8b4..e09667379fa3c36bf66d06572d42f60f065d879f 100644 --- a/parity/account.rs +++ b/parity/account.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -85,7 +85,7 @@ fn secret_store(dir: Box, iterations: Option) -> Result< } fn new(n: NewAccount) -> Result { - let password: String = match n.password_file { + let password = match n.password_file { Some(file) => password_from_file(file)?, None => password_prompt()?, }; diff --git a/parity/blockchain.rs b/parity/blockchain.rs index 027814f2451a53d807c9618602c01678ed9b33cf..cc92419dabf88e5a98d3a82ce6c1700715fb3e26 100644 --- a/parity/blockchain.rs +++ b/parity/blockchain.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -30,6 +30,7 @@ use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, BlockImportError, use ethcore::error::{ImportErrorKind, BlockImportErrorKind}; use ethcore::miner::Miner; use ethcore::verification::queue::VerifierSettings; +use ethcore::verification::queue::kind::blocks::Unverified; use ethcore_service::ClientService; use cache::CacheConfig; use informant::{Informant, FullNodeInformantData, MillisecondDuration}; @@ -90,7 +91,6 @@ pub struct ImportBlockchain { pub pruning_history: u64, pub pruning_memory: usize, pub compaction: DatabaseCompactionProfile, - pub wal: bool, pub tracing: Switch, pub fat_db: Switch, pub vm_type: VMType, @@ -111,7 +111,6 @@ pub struct ExportBlockchain { pub pruning_history: u64, pub pruning_memory: usize, pub compaction: DatabaseCompactionProfile, - pub wal: bool, pub fat_db: Switch, pub tracing: Switch, pub from_block: BlockId, @@ -130,7 +129,6 @@ pub struct ExportState { pub pruning_history: u64, pub pruning_memory: usize, pub compaction: DatabaseCompactionProfile, - pub wal: bool, pub fat_db: Switch, pub tracing: Switch, pub at: BlockId, @@ -187,7 +185,7 @@ fn execute_import_light(cmd: ImportBlockchain) -> Result<(), String> { execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?; // create dirs used by parity - cmd.dirs.create_dirs(false, false, false)?; + cmd.dirs.create_dirs(false, false)?; let cache = Arc::new(Mutex::new( LightDataCache::new(Default::default(), Duration::new(0, 0)) @@ -207,8 +205,7 @@ fn execute_import_light(cmd: ImportBlockchain) -> Result<(), String> { // initialize database. let db = db::open_db(&client_path.to_str().expect("DB path could not be converted to string."), &cmd.cache_config, - &cmd.compaction, - cmd.wal)?; + &cmd.compaction).map_err(|e| format!("Failed to open database: {:?}", e))?; // TODO: could epoch signals be avilable at the end of the file? let fetch = ::light::client::fetch::unavailable(); @@ -341,7 +338,7 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> { execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?; // create dirs used by parity - cmd.dirs.create_dirs(false, false, false)?; + cmd.dirs.create_dirs(false, false)?; // prepare client config let mut client_config = to_client_config( @@ -351,19 +348,19 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> { tracing, fat_db, cmd.compaction, - cmd.wal, cmd.vm_type, "".into(), algorithm, cmd.pruning_history, cmd.pruning_memory, - cmd.check_seal + cmd.check_seal, ); client_config.queue.verifier_settings = cmd.verifier_settings; - let client_db = db::open_client_db(&client_path, &client_config)?; let restoration_db_handler = db::restoration_db_handler(&client_path, &client_config); + let client_db = restoration_db_handler.open(&client_path) + .map_err(|e| format!("Failed to open database {:?}", e))?; // build client let service = ClientService::start( @@ -421,8 +418,9 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> { service.register_io_handler(informant).map_err(|_| "Unable to register informant handler".to_owned())?; let do_import = |bytes| { + let block = Unverified::from_rlp(bytes).map_err(|_| "Invalid block rlp")?; while client.queue_info().is_full() { sleep(Duration::from_secs(1)); } - match client.import_block(bytes) { + match client.import_block(block) { Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain), _)) => { trace!("Skipping block already in chain."); } @@ -493,7 +491,6 @@ fn start_client( tracing: Switch, fat_db: Switch, compaction: DatabaseCompactionProfile, - wal: bool, cache_config: CacheConfig, require_fat_db: bool, ) -> Result { @@ -533,7 +530,7 @@ fn start_client( execute_upgrades(&dirs.base, &db_dirs, algorithm, &compaction)?; // create dirs used by parity - dirs.create_dirs(false, false, false)?; + dirs.create_dirs(false, false)?; // prepare client config let client_config = to_client_config( @@ -543,7 +540,6 @@ fn start_client( tracing, fat_db, compaction, - wal, VMType::default(), "".into(), algorithm, @@ -552,8 +548,9 @@ fn start_client( true, ); - let client_db = db::open_client_db(&client_path, &client_config)?; let restoration_db_handler = db::restoration_db_handler(&client_path, &client_config); + let client_db = restoration_db_handler.open(&client_path) + .map_err(|e| format!("Failed to open database {:?}", e))?; let service = ClientService::start( client_config, @@ -584,7 +581,6 @@ fn execute_export(cmd: ExportBlockchain) -> Result<(), String> { cmd.tracing, cmd.fat_db, cmd.compaction, - cmd.wal, cmd.cache_config, false, )?; @@ -629,7 +625,6 @@ fn execute_export_state(cmd: ExportState) -> Result<(), String> { cmd.tracing, cmd.fat_db, cmd.compaction, - cmd.wal, cmd.cache_config, true )?; diff --git a/parity/cache.rs b/parity/cache.rs index 0bf0717a30c61dd3874a7e7f2147c56b5012ccde..5848e404c2a86a0c85ad3c468f9f5047732c4935 100644 --- a/parity/cache.rs +++ b/parity/cache.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index facd01dbfb0321955289239c1ea2eb9b95bc8716..5ca5feb6797e3d3d2f726d7e0c697e59a4a82a0e 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -26,19 +26,6 @@ usage! { // Arguments must start with arg_ // Flags must start with flag_ - CMD cmd_ui { - "Manage ui", - } - - CMD cmd_dapp - { - "Manage dapps", - - ARG arg_dapp_path: (Option) = None, - "", - "Path to the dapps", - } - CMD cmd_daemon { "Use Parity as a daemon", @@ -53,16 +40,16 @@ usage! { "Manage accounts", CMD cmd_account_new { - "Create a new acount", + "Create a new account (and its associated key) for the given --chain (default: mainnet)", } CMD cmd_account_list { - "List existing accounts", + "List existing accounts of the given --chain (default: mainnet)", } CMD cmd_account_import { - "Import account", + "Import accounts from JSON UTC keystore files to the specified --chain (default mainnet)", ARG arg_account_import_path : (Option>) = None, "...", @@ -76,7 +63,7 @@ usage! { CMD cmd_wallet_import { - "Import wallet", + "Import wallet into the given --chain (default: mainnet)", ARG arg_wallet_import_path: (Option) = None, "", @@ -86,7 +73,7 @@ usage! { CMD cmd_import { - "Import blockchain", + "Import blockchain data from a file to the given --chain database (default: mainnet)", ARG arg_import_format: (Option) = None, "--format=[FORMAT]", @@ -103,7 +90,7 @@ usage! { CMD cmd_export_blocks { - "Export blocks", + "Export the blockchain blocks from the given --chain database (default: mainnet) into a file. This command requires the chain to be synced with --fat-db on.", ARG arg_export_blocks_format: (Option) = None, "--format=[FORMAT]", @@ -124,7 +111,7 @@ usage! { CMD cmd_export_state { - "Export state", + "Export the blockchain state from the given --chain (default: mainnet) into a file. This command requires the chain to be synced with --fat-db on.", FLAG flag_export_state_no_storage: (bool) = false, "--no-storage", @@ -161,11 +148,11 @@ usage! { "Manage signer", CMD cmd_signer_new_token { - "Generate new token", + "Generate a new signer-authentication token for the given --chain (default: mainnet)", } CMD cmd_signer_list { - "List", + "List the signer-authentication tokens from given --chain (default: mainnet)", } CMD cmd_signer_sign @@ -189,7 +176,7 @@ usage! { CMD cmd_snapshot { - "Make a snapshot of the database", + "Make a snapshot of the database of the given --chain (default: mainnet)", ARG arg_snapshot_at: (String) = "latest", "--at=[BLOCK]", @@ -202,7 +189,7 @@ usage! { CMD cmd_restore { - "Restore database from snapshot", + "Restore the database of the given --chain (default: mainnet) from a snapshot file", ARG arg_restore_file: (Option) = None, "[FILE]", @@ -215,7 +202,7 @@ usage! { CMD cmd_tools_hash { - "Hash a file", + "Hash a file using the Keccak-256 algorithm", ARG arg_tools_hash_file: (Option) = None, "", @@ -228,13 +215,24 @@ usage! { "Manage the database representing the state of the blockchain on this system", CMD cmd_db_kill { - "Clean the database", + "Clean the database of the given --chain (default: mainnet)", } } CMD cmd_export_hardcoded_sync { - "Export the hardcoded sync JSON file from the existing light client database", + "Print the hashed light clients headers of the given --chain (default: mainnet) in a JSON format. To be used as hardcoded headers in a genesis file.", + } + + // CMD removed in 2.0 + + CMD cmd_dapp + { + "Manage dapps", + + ARG arg_dapp_path: (Option) = None, + "", + "Path to the dapps", } } { @@ -262,7 +260,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]", @@ -290,7 +288,7 @@ usage! { ARG arg_chain: (String) = "foundation", or |c: &Config| c.parity.as_ref()?.chain.clone(), "--chain=[CHAIN]", - "Specify the blockchain type. CHAIN may be either a JSON chain specification file or olympic, frontier, homestead, mainnet, morden, ropsten, classic, expanse, musicoin, ellaism, easthub, social, testnet, kovan or dev.", + "Specify the blockchain type. CHAIN may be either a JSON chain specification file or olympic, frontier, homestead, mainnet, morden, ropsten, classic, expanse, tobalaba, musicoin, ellaism, easthub, social, testnet, kovan or dev.", ARG arg_keys_path: (String) = "$BASE/keys", or |c: &Config| c.parity.as_ref()?.keys_path.clone(), "--keys-path=[PATH]", @@ -308,7 +306,7 @@ usage! { "--db-path=[PATH]", "Specify the database directory path", - ["Convenience options"] + ["Convenience Options"] FLAG flag_unsafe_expose: (bool) = false, or |c: &Config| c.misc.as_ref()?.unsafe_expose, "--unsafe-expose", "All servers will listen on external interfaces and will be remotely accessible. It's equivalent with setting the following: --[ws,jsonrpc,ui,ipfs-api,secretstore,stratum,dapps,secretstore-http]-interface=all --*-hosts=all This option is UNSAFE and should be used with great care!", @@ -319,16 +317,16 @@ 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"] + ["Account Options"] FLAG flag_no_hardware_wallets: (bool) = false, or |c: &Config| c.account.as_ref()?.disable_hardware.clone(), "--no-hardware-wallets", "Disables hardware wallet support.", FLAG flag_fast_unlock: (bool) = false, or |c: &Config| c.account.as_ref()?.fast_unlock.clone(), "--fast-unlock", - "Use drasticly faster unlocking mode. This setting causes raw secrets to be stored unprotected in memory, so use with care.", + "Use drastically faster unlocking mode. This setting causes raw secrets to be stored unprotected in memory, so use with care.", ARG arg_keys_iterations: (u32) = 10240u32, or |c: &Config| c.account.as_ref()?.keys_iterations.clone(), "--keys-iterations=[NUM]", @@ -346,7 +344,7 @@ usage! { "--password=[FILE]...", "Provide a file containing a password for unlocking an account. Leading and trailing whitespace is trimmed.", - ["Private transactions options"] + ["Private Transactions Options"] FLAG flag_private_enabled: (bool) = false, or |c: &Config| c.private_tx.as_ref()?.enabled, "--private-tx-enabled", "Enable private transactions.", @@ -375,37 +373,12 @@ usage! { "--private-passwords=[FILE]...", "Provide a file containing passwords for unlocking accounts (signer, private account, validators).", - ["UI options"] - FLAG flag_force_ui: (bool) = false, or |c: &Config| c.ui.as_ref()?.force.clone(), - "--force-ui", - "Enable Trusted UI WebSocket endpoint, even when --unlock is in use.", - - FLAG flag_no_ui: (bool) = false, or |c: &Config| c.ui.as_ref()?.disable.clone(), - "--no-ui", - "Disable Trusted UI WebSocket endpoint.", - - // NOTE [todr] For security reasons don't put this to config files - FLAG flag_ui_no_validation: (bool) = false, or |_| None, - "--ui-no-validation", - "Disable Origin and Host headers validation for Trusted UI. WARNING: INSECURE. Used only for development.", - - ARG arg_ui_interface: (String) = "local", or |c: &Config| c.ui.as_ref()?.interface.clone(), - "--ui-interface=[IP]", - "Specify the hostname portion of the Trusted UI server, IP should be an interface's IP address, or local.", - - ARG arg_ui_hosts: (String) = "none", or |c: &Config| c.ui.as_ref()?.hosts.as_ref().map(|vec| vec.join(",")), - "--ui-hosts=[HOSTS]", - "List of allowed Host header values. This option will validate the Host header sent by the browser, it is additional security against some attack vectors. Special options: \"all\", \"none\",.", - + ["UI Options"] ARG arg_ui_path: (String) = "$BASE/signer", or |c: &Config| c.ui.as_ref()?.path.clone(), "--ui-path=[PATH]", "Specify directory where Trusted UIs tokens should be stored.", - ARG arg_ui_port: (u16) = 8180u16, or |c: &Config| c.ui.as_ref()?.port.clone(), - "--ui-port=[PORT]", - "Specify the port of Trusted UI server.", - - ["Networking options"] + ["Networking Options"] FLAG flag_no_warp: (bool) = false, or |c: &Config| c.network.as_ref()?.warp.clone().map(|w| !w), "--no-warp", "Disable syncing from the snapshot over the network.", @@ -478,22 +451,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' enables the 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]", @@ -501,32 +485,36 @@ 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 execution of cpu-heavy queries.", 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]", "Enables multiple threads handling incoming connections for HTTP JSON-RPC server.", - ["API and console options – WebSockets"] + ARG arg_jsonrpc_max_payload: (Option) = None, or |c: &Config| c.rpc.as_ref()?.max_payload, + "--jsonrpc-max-payload=[MB]", + "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' enables the 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]", @@ -538,9 +526,9 @@ 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.", + "Maximum number of allowed concurrent WebSockets JSON-RPC connections.", - ["API and console options – IPC"] + ["API and Console Options – IPC"] FLAG flag_no_ipc: (bool) = false, or |c: &Config| c.ipc.as_ref()?.disable.clone(), "--no-ipc", "Disable JSON-RPC over IPC service.", @@ -551,18 +539,9 @@ usage! { ARG arg_ipc_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,parity_accounts,private,traces,rpc,shh,shh_pubsub", or |c: &Config| c.ipc.as_ref()?.apis.as_ref().map(|vec| vec.join(",")), "--ipc-apis=[APIS]", - "Specify custom API set available via JSON-RPC over IPC 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: web3, net, eth, pubsub, parity, parity_pubsub, traces, rpc, shh, shh_pubsub", + "Specify custom API set available via JSON-RPC over IPC 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' enables the following APIs: web3, net, eth, pubsub, parity, parity_pubsub, traces, rpc, shh, shh_pubsub", - ["API and console options – Dapps"] - FLAG flag_no_dapps: (bool) = false, or |c: &Config| c.dapps.as_ref()?.disable.clone(), - "--no-dapps", - "Disable the Dapps server (e.g. status page).", - - ARG arg_dapps_path: (String) = "$BASE/dapps", or |c: &Config| c.dapps.as_ref()?.path.clone(), - "--dapps-path=[PATH]", - "Specify directory where dapps should be installed.", - - ["API and console options – IPFS"] + ["API and Console Options – IPFS"] FLAG flag_ipfs_api: (bool) = false, or |c: &Config| c.ipfs.as_ref()?.enable.clone(), "--ipfs-api", "Enable IPFS-compatible HTTP API.", @@ -583,7 +562,7 @@ usage! { "--ipfs-api-cors=[URL]", "Specify CORS header for IPFS API responses. Special options: \"all\", \"none\".", - ["Secret store options"] + ["Secret Store Options"] FLAG flag_no_secretstore: (bool) = false, or |c: &Config| c.secretstore.as_ref()?.disable.clone(), "--no-secretstore", "Disable Secret Store functionality.", @@ -592,38 +571,42 @@ usage! { "--no-secretstore-http", "Disable Secret Store HTTP API.", - FLAG flag_no_secretstore_acl_check: (bool) = false, or |c: &Config| c.secretstore.as_ref()?.disable_acl_check.clone(), - "--no-acl-check", - "Disable ACL check (useful for test environments).", - FLAG flag_no_secretstore_auto_migrate: (bool) = false, or |c: &Config| c.secretstore.as_ref()?.disable_auto_migrate.clone(), "--no-secretstore-auto-migrate", "Do not run servers set change session automatically when servers set changes. This option has no effect when servers set is read from configuration file.", - ARG arg_secretstore_contract: (String) = "none", or |c: &Config| c.secretstore.as_ref()?.service_contract.clone(), + ARG arg_secretstore_acl_contract: (Option) = Some("registry".into()), or |c: &Config| c.secretstore.as_ref()?.acl_contract.clone(), + "--secretstore-acl-contract=[SOURCE]", + "Secret Store permissioning contract address source: none, registry (contract address is read from 'secretstore_acl_checker' entry in registry) or address.", + + ARG arg_secretstore_contract: (Option) = None, or |c: &Config| c.secretstore.as_ref()?.service_contract.clone(), "--secretstore-contract=[SOURCE]", - "Secret Store Service contract address source: none, registry (contract address is read from secretstore_service entry in registry) or address.", + "Secret Store Service contract address source: none, registry (contract address is read from 'secretstore_service' entry in registry) or address.", - ARG arg_secretstore_srv_gen_contract: (String) = "none", or |c: &Config| c.secretstore.as_ref()?.service_contract_srv_gen.clone(), + ARG arg_secretstore_srv_gen_contract: (Option) = None, or |c: &Config| c.secretstore.as_ref()?.service_contract_srv_gen.clone(), "--secretstore-srv-gen-contract=[SOURCE]", - "Secret Store Service server key generation contract address source: none, registry (contract address is read from secretstore_service_srv_gen entry in registry) or address.", + "Secret Store Service server key generation contract address source: none, registry (contract address is read from 'secretstore_service_srv_gen' entry in registry) or address.", - ARG arg_secretstore_srv_retr_contract: (String) = "none", or |c: &Config| c.secretstore.as_ref()?.service_contract_srv_retr.clone(), + ARG arg_secretstore_srv_retr_contract: (Option) = None, or |c: &Config| c.secretstore.as_ref()?.service_contract_srv_retr.clone(), "--secretstore-srv-retr-contract=[SOURCE]", - "Secret Store Service server key retrieval contract address source: none, registry (contract address is read from secretstore_service_srv_retr entry in registry) or address.", + "Secret Store Service server key retrieval contract address source: none, registry (contract address is read from 'secretstore_service_srv_retr' entry in registry) or address.", - ARG arg_secretstore_doc_store_contract: (String) = "none", or |c: &Config| c.secretstore.as_ref()?.service_contract_doc_store.clone(), + ARG arg_secretstore_doc_store_contract: (Option) = None, or |c: &Config| c.secretstore.as_ref()?.service_contract_doc_store.clone(), "--secretstore-doc-store-contract=[SOURCE]", - "Secret Store Service document key store contract address source: none, registry (contract address is read from secretstore_service_doc_store entry in registry) or address.", + "Secret Store Service document key store contract address source: none, registry (contract address is read from 'secretstore_service_doc_store' entry in registry) or address.", - ARG arg_secretstore_doc_sretr_contract: (String) = "none", or |c: &Config| c.secretstore.as_ref()?.service_contract_doc_sretr.clone(), + ARG arg_secretstore_doc_sretr_contract: (Option) = None, or |c: &Config| c.secretstore.as_ref()?.service_contract_doc_sretr.clone(), "--secretstore-doc-sretr-contract=[SOURCE]", - "Secret Store Service document key shadow retrieval contract address source: none, registry (contract address is read from secretstore_service_doc_sretr entry in registry) or address.", + "Secret Store Service document key shadow retrieval contract address source: none, registry (contract address is read from 'secretstore_service_doc_sretr' entry in registry) or address.", ARG arg_secretstore_nodes: (String) = "", or |c: &Config| c.secretstore.as_ref()?.nodes.as_ref().map(|vec| vec.join(",")), "--secretstore-nodes=[NODES]", "Comma-separated list of other secret store cluster nodes in form NODE_PUBLIC_KEY_IN_HEX@NODE_IP_ADDR:NODE_PORT.", + ARG arg_secretstore_server_set_contract: (Option) = Some("registry".into()), or |c: &Config| c.secretstore.as_ref()?.server_set_contract.clone(), + "--secretstore-server-set-contract=[SOURCE]", + "Secret Store server set contract address source: none, registry (contract address is read from 'secretstore_server_set' entry in registry) or address.", + ARG arg_secretstore_interface: (String) = "local", or |c: &Config| c.secretstore.as_ref()?.interface.clone(), "--secretstore-interface=[IP]", "Specify the hostname portion for listening to Secret Store Key Server internal requests, IP should be an interface's IP address, or local.", @@ -652,7 +635,7 @@ usage! { "--secretstore-admin=[PUBLIC]", "Hex-encoded public key of secret store administrator.", - ["Sealing/Mining options"] + ["Sealing/Mining Options"] FLAG flag_force_sealing: (bool) = false, or |c: &Config| c.mining.as_ref()?.force_sealing.clone(), "--force-sealing", "Force the node to author new blocks as if it were always sealing/mining.", @@ -665,6 +648,14 @@ usage! { "--remove-solved", "Move solved blocks from the work package queue instead of cloning them. This gives a slightly faster import speed, but means that extra solutions submitted for the same work package will go unused.", + 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", + "Local transactions sent through JSON-RPC (HTTP, WebSockets, etc) will be treated as 'external' if the sending account is unknown.", + + FLAG flag_tx_queue_no_early_reject: (bool) = false, or |c: &Config| c.mining.as_ref()?.tx_queue_no_early_reject.clone(), + "--tx-queue-no-early-reject", + "Disables transaction queue optimization to early reject transactions below minimal effective gas price. This allows local transactions to always enter the pool, despite it being full, but requires additional ecrecover on every transaction.", + FLAG flag_refuse_service_transactions: (bool) = false, or |c: &Config| c.mining.as_ref()?.refuse_service_transactions.clone(), "--refuse-service-transactions", "Always refuse service transactions.", @@ -733,10 +724,6 @@ usage! { "--tx-queue-per-sender=[LIMIT]", "Maximum number of transactions per sender in the queue. By default it's 1% of the entire queue, but not less than 16.", - ARG arg_tx_queue_gas: (String) = "off", or |c: &Config| c.mining.as_ref()?.tx_queue_gas.clone(), - "--tx-queue-gas=[LIMIT]", - "Maximum amount of total gas for external transactions in the queue. LIMIT can be either an amount of gas or 'auto' or 'off'. 'auto' sets the limit to be 20x the current block gas limit.", - ARG arg_tx_queue_strategy: (String) = "gas_price", or |c: &Config| c.mining.as_ref()?.tx_queue_strategy.clone(), "--tx-queue-strategy=[S]", "Prioritization strategy used to order transactions in the queue. S may be: gas_price - Prioritize txs with high gas price", @@ -757,6 +744,10 @@ usage! { "--gas-price-percentile=[PCT]", "Set PCT percentile gas price value from last 100 blocks as default gas price when sending transactions.", + ARG arg_poll_lifetime: (u32) = 60u32, or |c: &Config| c.mining.as_ref()?.poll_lifetime.clone(), + "--poll-lifetime=[S]", + "Set the lifetime of the internal index filter to S seconds.", + ARG arg_author: (Option) = None, or |c: &Config| c.mining.as_ref()?.author.clone(), "--author=[ADDRESS]", "Specify the block author (aka \"coinbase\") address for sending block rewards from sealed blocks. NOTE: MINING WILL NOT WORK WITHOUT THIS OPTION.", // Sealing/Mining Option @@ -790,7 +781,7 @@ usage! { "--can-restart", "Executable will auto-restart if exiting with 69", - ["Miscellaneous options"] + ["Miscellaneous Options"] FLAG flag_no_color: (bool) = false, or |c: &Config| c.misc.as_ref()?.color.map(|c| !c).clone(), "--no-color", "Don't use terminal color codes in output.", @@ -803,23 +794,15 @@ usage! { "--no-config", "Don't load a configuration file.", - ARG arg_ntp_servers: (String) = "0.parity.pool.ntp.org:123,1.parity.pool.ntp.org:123,2.parity.pool.ntp.org:123,3.parity.pool.ntp.org:123", or |c: &Config| c.misc.as_ref()?.ntp_servers.clone().map(|vec| vec.join(",")), - "--ntp-servers=[HOSTS]", - "Comma separated list of NTP servers to provide current time (host:port). Used to verify node health. Parity uses pool.ntp.org NTP servers; consider joining the pool: http://www.pool.ntp.org/join.html", - ARG arg_logging: (Option) = None, or |c: &Config| c.misc.as_ref()?.logging.clone(), "-l, --logging=[LOGGING]", - "Specify the logging level. Must conform to the same format as RUST_LOG.", + "Specify the general logging level (error, warn, info, debug or trace). It can also be set for a specific module, example: '-l sync=debug,rpc=trace'", ARG arg_log_file: (Option) = None, or |c: &Config| c.misc.as_ref()?.log_file.clone(), "--log-file=[FILENAME]", "Specify a filename into which logging should be appended.", - ["Footprint options"] - FLAG flag_fast_and_loose: (bool) = false, or |c: &Config| c.footprint.as_ref()?.fast_and_loose.clone(), - "--fast-and-loose", - "Disables DB WAL, which gives a significant speed up but means an unclean exit is unrecoverable.", - + ["Footprint Options"] FLAG flag_scale_verifiers: (bool) = false, or |c: &Config| c.footprint.as_ref()?.scale_verifiers.clone(), "--scale-verifiers", "Automatically scale amount of verifier threads based on workload. Not guaranteed to be faster.", @@ -846,7 +829,7 @@ usage! { ARG arg_cache_size_blocks: (u32) = 8u32, or |c: &Config| c.footprint.as_ref()?.cache_size_blocks.clone(), "--cache-size-blocks=[MB]", - "Specify the prefered size of the blockchain cache in megabytes.", + "Specify the preferred size of the blockchain cache in megabytes.", ARG arg_cache_size_queue: (u32) = 40u32, or |c: &Config| c.footprint.as_ref()?.cache_size_queue.clone(), "--cache-size-queue=[MB]", @@ -872,17 +855,17 @@ usage! { "--num-verifiers=[INT]", "Amount of verifier threads to use or to begin with, if verifier auto-scaling is enabled.", - ["Import/export options"] + ["Import/export Options"] FLAG flag_no_seal_check: (bool) = false, or |_| None, "--no-seal-check", "Skip block seal check.", - ["Snapshot options"] + ["Snapshot Options"] FLAG flag_no_periodic_snapshot: (bool) = false, or |c: &Config| c.snapshots.as_ref()?.disable_periodic.clone(), "--no-periodic-snapshot", "Disable automated snapshots which usually occur once every 10000 blocks.", - ["Whisper options"] + ["Whisper Options"] FLAG flag_whisper: (bool) = false, or |c: &Config| c.whisper.as_ref()?.enabled, "--whisper", "Enable the Whisper network.", @@ -891,42 +874,31 @@ usage! { "--whisper-pool-size=[MB]", "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_dapps_apis_all: (bool) = false, or |_| None, - "--dapps-apis-all", - "Dapps server is merged with RPC server. Use --jsonrpc-apis.", + ["Legacy Options"] + // 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", @@ -934,43 +906,71 @@ 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", "Does nothing; Public node is removed from Parity.", - 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.", + FLAG flag_force_ui: (bool) = false, or |_| None, + "--force-ui", + "Does nothing; UI is now a separate project.", - 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.", + FLAG flag_no_ui: (bool) = false, or |_| None, + "--no-ui", + "Does nothing; UI is now a separate project.", - 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_ui_no_validation: (bool) = false, or |_| None, + "--ui-no-validation", + "Does nothing; UI is now a separate project.", - 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.", + // FLAG Removed in 2.0. - ARG arg_dapps_user: (Option) = None, or |c: &Config| c.dapps.as_ref()?.user.clone(), - "--dapps-user=[USERNAME]", - "Dapps server authentication has been removed.", + FLAG flag_fast_and_loose: (bool) = false, or |_| None, + "--fast-and-loose", + "Does nothing; DB WAL is always activated.", - ARG arg_dapps_pass: (Option) = None, or |c: &Config| c.dapps.as_ref()?.pass.clone(), - "--dapps-pass=[PASSWORD]", - "Dapps server authentication has been removed.", + FLAG flag_no_dapps: (bool) = false, or |c: &Config| c.dapps.as_ref()?._legacy_disable.clone(), + "--no-dapps", + "Disable the Dapps server (e.g. status page).", + + // ARG Removed in 1.6 or before. + + 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_datadir: (Option) = None, or |_| None, "--datadir=[PATH]", @@ -1016,25 +1016,67 @@ 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()?._legacy_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()?._legacy_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()?._legacy_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()?._legacy_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()?._legacy_user.clone(), + "--dapps-user=[USERNAME]", + "Dapps server authentication has been removed.", + + ARG arg_dapps_pass: (Option) = None, or |c: &Config| c.dapps.as_ref()?._legacy_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.", + + // ARG removed in 2.0. + + ARG arg_dapps_path: (Option) = None, or |c: &Config| c.dapps.as_ref()?._legacy_path.clone(), + "--dapps-path=[PATH]", + "Specify directory where dapps should be installed.", + + ARG arg_ntp_servers: (Option) = None, or |_| None, + "--ntp-servers=[HOSTS]", + "Does nothing; checking if clock is sync with NTP servers is now done on the UI.", } } @@ -1111,12 +1153,18 @@ struct PrivateTransactions { #[derive(Default, Debug, PartialEq, Deserialize)] #[serde(deny_unknown_fields)] struct Ui { - force: Option, - disable: Option, - port: Option, - interface: Option, - hosts: Option>, path: Option, + + #[serde(rename="force")] + _legacy_force: Option, + #[serde(rename="disable")] + _legacy_disable: Option, + #[serde(rename="port")] + _legacy_port: Option, + #[serde(rename="interface")] + _legacy_interface: Option, + #[serde(rename="hosts")] + _legacy_hosts: Option>, } #[derive(Default, Debug, PartialEq, Deserialize)] @@ -1152,6 +1200,7 @@ struct Rpc { hosts: Option>, server_threads: Option, processing_threads: Option, + max_payload: Option, } #[derive(Default, Debug, PartialEq, Deserialize)] @@ -1177,14 +1226,22 @@ struct Ipc { #[derive(Default, Debug, PartialEq, Deserialize)] #[serde(deny_unknown_fields)] struct Dapps { - disable: Option, - port: Option, - interface: Option, - hosts: Option>, - cors: Option, - path: Option, - user: Option, - pass: Option, + #[serde(rename="disable")] + _legacy_disable: Option, + #[serde(rename="port")] + _legacy_port: Option, + #[serde(rename="interface")] + _legacy_interface: Option, + #[serde(rename="hosts")] + _legacy_hosts: Option>, + #[serde(rename="cors")] + _legacy_cors: Option, + #[serde(rename="path")] + _legacy_path: Option, + #[serde(rename="user")] + _legacy_user: Option, + #[serde(rename="pass")] + _legacy_pass: Option, } #[derive(Default, Debug, PartialEq, Deserialize)] @@ -1192,8 +1249,8 @@ struct Dapps { struct SecretStore { disable: Option, disable_http: Option, - disable_acl_check: Option, disable_auto_migrate: Option, + acl_contract: Option, service_contract: Option, service_contract_srv_gen: Option, service_contract_srv_retr: Option, @@ -1202,6 +1259,7 @@ struct SecretStore { self_secret: Option, admin_public: Option, nodes: Option>, + server_set_contract: Option, interface: Option, port: Option, http_interface: Option, @@ -1235,6 +1293,7 @@ struct Mining { relay_set: Option, min_gas_price: Option, gas_price_percentile: Option, + poll_lifetime: Option, usd_per_tx: Option, usd_per_eth: Option, price_update_period: Option, @@ -1244,10 +1303,11 @@ struct Mining { tx_queue_size: Option, tx_queue_per_sender: Option, tx_queue_mem_limit: Option, - tx_queue_gas: Option, tx_queue_strategy: Option, tx_queue_ban_count: Option, tx_queue_ban_time: Option, + tx_queue_no_unfamiliar_locals: Option, + tx_queue_no_early_reject: Option, remove_solved: Option, notify_work: Option>, refuse_service_transactions: Option, @@ -1290,7 +1350,6 @@ struct Snapshots { #[derive(Default, Debug, PartialEq, Deserialize)] #[serde(deny_unknown_fields)] struct Misc { - ntp_servers: Option>, logging: Option, log_file: Option, color: Option, @@ -1404,15 +1463,13 @@ mod tests { let args = Args::parse(&["parity", "--secretstore-nodes", "abc@127.0.0.1:3333,cde@10.10.10.10:4444"]).unwrap(); assert_eq!(args.arg_secretstore_nodes, "abc@127.0.0.1:3333,cde@10.10.10.10:4444"); - let args = Args::parse(&["parity", "--password", "~/.safe/1", "--password", "~/.safe/2", "--ui-port", "8123", "ui"]).unwrap(); + 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.cmd_ui, true); + assert_eq!(args.arg_ui_port, Some(8123)); - let args = Args::parse(&["parity", "--password", "~/.safe/1,~/.safe/2", "--ui-port", "8123", "ui"]).unwrap(); + 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.cmd_ui, true); + assert_eq!(args.arg_ui_port, Some(8123)); } #[test] @@ -1476,7 +1533,6 @@ mod tests { // then assert_eq!(args, Args { // Commands - cmd_ui: false, cmd_dapp: false, cmd_daemon: false, cmd_account: false, @@ -1565,9 +1621,9 @@ mod tests { flag_force_ui: false, flag_no_ui: false, - arg_ui_port: 8180u16, - arg_ui_interface: "127.0.0.1".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, @@ -1600,6 +1656,7 @@ mod tests { arg_jsonrpc_hosts: "none".into(), arg_jsonrpc_server_threads: None, arg_jsonrpc_threads: 4, + arg_jsonrpc_max_payload: None, // WS flag_no_ws: false, @@ -1616,22 +1673,23 @@ mod tests { arg_ipc_apis: "web3,eth,net,parity,parity_accounts,personal,traces,rpc,secretstore".into(), // DAPPS - arg_dapps_path: "$HOME/.parity/dapps".into(), + arg_dapps_path: Some("$HOME/.parity/dapps".into()), flag_no_dapps: false, // SECRETSTORE flag_no_secretstore: false, flag_no_secretstore_http: false, - flag_no_secretstore_acl_check: false, flag_no_secretstore_auto_migrate: false, - arg_secretstore_contract: "none".into(), - arg_secretstore_srv_gen_contract: "none".into(), - arg_secretstore_srv_retr_contract: "none".into(), - arg_secretstore_doc_store_contract: "none".into(), - arg_secretstore_doc_sretr_contract: "none".into(), + arg_secretstore_acl_contract: Some("registry".into()), + arg_secretstore_contract: Some("none".into()), + arg_secretstore_srv_gen_contract: Some("none".into()), + arg_secretstore_srv_retr_contract: Some("none".into()), + arg_secretstore_doc_store_contract: Some("none".into()), + arg_secretstore_doc_sretr_contract: Some("none".into()), arg_secretstore_secret: None, arg_secretstore_admin_public: None, arg_secretstore_nodes: "".into(), + arg_secretstore_server_set_contract: Some("registry".into()), arg_secretstore_interface: "local".into(), arg_secretstore_port: 8083u16, arg_secretstore_http_interface: "local".into(), @@ -1660,18 +1718,20 @@ mod tests { arg_min_gas_price: Some(0u64), arg_usd_per_tx: "0.0001".into(), arg_gas_price_percentile: 50usize, + arg_poll_lifetime: 60u32, arg_usd_per_eth: "auto".into(), arg_price_update_period: "hourly".into(), arg_gas_floor_target: "4700000".into(), arg_gas_cap: "6283184".into(), arg_extra_data: Some("Parity".into()), + flag_tx_queue_no_unfamiliar_locals: false, + flag_tx_queue_no_early_reject: false, arg_tx_queue_size: 8192usize, arg_tx_queue_per_sender: None, 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, @@ -1757,7 +1817,7 @@ mod tests { flag_can_restart: false, // -- Miscellaneous Options - arg_ntp_servers: "0.parity.pool.ntp.org:123,1.parity.pool.ntp.org:123,2.parity.pool.ntp.org:123,3.parity.pool.ntp.org:123".into(), + arg_ntp_servers: None, flag_version: false, arg_logging: Some("own_tx=trace".into()), arg_log_file: Some("/var/log/parity.log".into()), @@ -1820,12 +1880,12 @@ mod tests { fast_unlock: None, }), ui: Some(Ui { - force: None, - disable: Some(true), - port: None, - interface: None, - hosts: None, path: None, + _legacy_force: None, + _legacy_disable: Some(true), + _legacy_port: None, + _legacy_interface: None, + _legacy_hosts: None, }), network: Some(Network { warp: Some(false), @@ -1864,6 +1924,7 @@ mod tests { hosts: None, server_threads: None, processing_threads: None, + max_payload: None, }), ipc: Some(Ipc { disable: None, @@ -1871,20 +1932,20 @@ mod tests { apis: Some(vec!["rpc".into(), "eth".into()]), }), dapps: Some(Dapps { - disable: None, - port: Some(8080), - path: None, - interface: None, - hosts: None, - cors: None, - user: Some("username".into()), - pass: Some("password".into()) + _legacy_disable: None, + _legacy_port: Some(8080), + _legacy_path: None, + _legacy_interface: None, + _legacy_hosts: None, + _legacy_cors: None, + _legacy_user: Some("username".into()), + _legacy_pass: Some("password".into()) }), secretstore: Some(SecretStore { disable: None, disable_http: None, - disable_acl_check: None, disable_auto_migrate: None, + acl_contract: None, service_contract: None, service_contract_srv_gen: None, service_contract_srv_retr: None, @@ -1893,6 +1954,7 @@ mod tests { self_secret: None, admin_public: None, nodes: None, + server_set_contract: None, interface: None, port: Some(8083), http_interface: None, @@ -1919,6 +1981,7 @@ mod tests { relay_set: None, min_gas_price: None, gas_price_percentile: None, + poll_lifetime: None, usd_per_tx: None, usd_per_eth: None, price_update_period: Some("hourly".into()), @@ -1927,10 +1990,11 @@ mod tests { tx_queue_size: Some(8192), tx_queue_per_sender: None, tx_queue_mem_limit: None, - tx_queue_gas: Some("off".into()), tx_queue_strategy: None, tx_queue_ban_count: None, tx_queue_ban_time: None, + tx_queue_no_unfamiliar_locals: None, + tx_queue_no_early_reject: None, tx_gas_limit: None, tx_time_limit: None, extra_data: None, @@ -1959,7 +2023,6 @@ mod tests { disable_periodic: Some(true), }), misc: Some(Misc { - ntp_servers: Some(vec!["0.parity.pool.ntp.org:123".into()]), logging: Some("own_tx=trace".into()), log_file: Some("/var/log/parity.log".into()), color: Some(true), diff --git a/parity/cli/presets/mod.rs b/parity/cli/presets/mod.rs index ca1ad4559be169f8d997237928aee66ec784191d..125ab510c3cac9c23a8386366351fcbb0e412a31 100644 --- a/parity/cli/presets/mod.rs +++ b/parity/cli/presets/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -25,4 +25,4 @@ pub fn preset_config_string(arg: &str) -> Result<&'static str, Error> { "dev-insecure" => Ok(include_str!("./config.dev-insecure.toml")), _ => Err(Error::new(ErrorKind::InvalidInput, "Config doesn't match any presets [dev, mining, non-standard-ports, insecure, dev-insecure]")) } -} \ No newline at end of file +} diff --git a/parity/cli/tests/config.full.toml b/parity/cli/tests/config.full.toml index fb3614aa96d6ee7d5a21c3a6b7ed47b73f8739a5..d615996cfce611630ca1a7ae8a7ba764698f90f4 100644 --- a/parity/cli/tests/config.full.toml +++ b/parity/cli/tests/config.full.toml @@ -91,12 +91,13 @@ pass = "test_pass" [secretstore] disable = false disable_http = false -disable_acl_check = false +acl_contract = "registry" service_contract = "none" service_contract_srv_gen = "none" service_contract_srv_retr = "none" service_contract_doc_store = "none" service_contract_doc_sretr = "none" +server_set_contract = "registry" nodes = [] http_interface = "local" http_port = 8082 @@ -127,12 +128,13 @@ price_update_period = "hourly" gas_floor_target = "4700000" gas_cap = "6283184" tx_queue_size = 8192 -tx_queue_gas = "off" tx_queue_strategy = "gas_factor" tx_queue_ban_count = 1 tx_queue_ban_time = 180 #s tx_gas_limit = "6283184" tx_time_limit = 100 #ms +tx_queue_no_unfamiliar_locals = false +tx_queue_no_early_reject = false extra_data = "Parity" remove_solved = false notify_work = ["http://localhost:3001"] @@ -148,7 +150,6 @@ cache_size_blocks = 8 cache_size_queue = 50 cache_size_state = 25 cache_size = 128 # Overrides above caches with total size -fast_and_loose = false db_compaction = "ssd" fat_db = "auto" scale_verifiers = true diff --git a/parity/cli/tests/config.toml b/parity/cli/tests/config.toml index 245935de12e88cc5d4e294b08cb539b8656d9bcc..5f9e655d51c83c1608d90a1fc8c69e1022d3e1e0 100644 --- a/parity/cli/tests/config.toml +++ b/parity/cli/tests/config.toml @@ -57,7 +57,6 @@ reseal_min_period = 4000 reseal_max_period = 60000 price_update_period = "hourly" tx_queue_size = 8192 -tx_queue_gas = "off" [footprint] tracing = "on" @@ -75,7 +74,6 @@ scale_verifiers = false disable_periodic = true [misc] -ntp_servers = ["0.parity.pool.ntp.org:123"] logging = "own_tx=trace" log_file = "/var/log/parity.log" color = true diff --git a/parity/cli/usage.rs b/parity/cli/usage.rs index ce138fdff3d46ab010dc4495593ce6dc31c408d1..caacd364f2ca5c078fde1118373a9782fb5b206c 100644 --- a/parity/cli/usage.rs +++ b/parity/cli/usage.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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)] @@ -443,73 +448,71 @@ macro_rules! usage { // Arguments and flags let args_wrapper = Wrapper::new(term_width).initial_indent(TAB_TAB).subsequent_indent(TAB_TAB); $( - help.push_str($group_name); help.push_str(":\n"); - - $( - help.push_str(&format!("{}{}\n{}\n", - TAB, $flag_usage, - args_wrapper.fill($flag_help) - )); - help.push_str("\n"); - )* - - $( - if_option!( - $($arg_type_tt)+, - THEN { - if_option_vec!( - $($arg_type_tt)+, - THEN { - help.push_str(&format!("{}{}\n{}\n", - TAB, $arg_usage, - args_wrapper.fill(format!( - "{} (default: {:?})", - $arg_help, - {let x : inner_option_type!($($arg_type_tt)+)> = $arg_default; x} - ).as_ref()) - )) - } - ELSE { - help.push_str(&format!("{}{}\n{}\n", - TAB, $arg_usage, - args_wrapper.fill(format!( - "{}{}", - $arg_help, - $arg_default.map(|x: inner_option_type!($($arg_type_tt)+)| format!(" (default: {})",x)).unwrap_or("".to_owned()) - ).as_ref()) - )) - } - ) - } - ELSE { - if_vec!( - $($arg_type_tt)+, - THEN { - help.push_str(&format!("{}{}\n{}\n", TAB, $arg_usage, - args_wrapper.fill(format!( - "{} (default: {:?})", - $arg_help, - {let x : $($arg_type_tt)+ = $arg_default; x} - ).as_ref()) - )) - } - ELSE { - help.push_str(&format!("{}{}\n{}\n", TAB, $arg_usage, - args_wrapper.fill(format!( - "{} (default: {})", - $arg_help, - $arg_default - ).as_ref()) - )) - } - ) - } - ); - help.push_str("\n"); - )* - + if $group_name != "Legacy Options" { + help.push_str($group_name); help.push_str(":\n"); + $( + help.push_str(&format!("{}{}\n{}\n", + TAB, $flag_usage, + args_wrapper.fill($flag_help) + )); + help.push_str("\n"); + )* + $( + if_option!( + $($arg_type_tt)+, + THEN { + if_option_vec!( + $($arg_type_tt)+, + THEN { + help.push_str(&format!("{}{}\n{}\n", + TAB, $arg_usage, + args_wrapper.fill(format!( + "{} (default: {:?})", + $arg_help, + {let x : inner_option_type!($($arg_type_tt)+)> = $arg_default; x} + ).as_ref()) + )) + } + ELSE { + help.push_str(&format!("{}{}\n{}\n", + TAB, $arg_usage, + args_wrapper.fill(format!( + "{}{}", + $arg_help, + $arg_default.map(|x: inner_option_type!($($arg_type_tt)+)| format!(" (default: {})",x)).unwrap_or("".to_owned()) + ).as_ref()) + )) + } + ) + } + ELSE { + if_vec!( + $($arg_type_tt)+, + THEN { + help.push_str(&format!("{}{}\n{}\n", TAB, $arg_usage, + args_wrapper.fill(format!( + "{} (default: {:?})", + $arg_help, + {let x : $($arg_type_tt)+ = $arg_default; x} + ).as_ref()) + )) + } + ELSE { + help.push_str(&format!("{}{}\n{}\n", TAB, $arg_usage, + args_wrapper.fill(format!( + "{} (default: {})", + $arg_help, + $arg_default + ).as_ref()) + )) + } + ) + } + ); + help.push_str("\n"); + )* + } )* - help } } diff --git a/parity/configuration.rs b/parity/configuration.rs index 426b651015ae0d2677d8ada68b80d1167214baae..6a40aff3d60f8799dde9da4d8abe5a72a62bc230 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -17,10 +17,9 @@ use std::time::Duration; use std::io::Read; use std::net::SocketAddr; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::collections::BTreeMap; use std::cmp; -use std::str::FromStr; use cli::{Args, ArgsError}; use hash::keccak; use ethereum_types::{U256, H256, Address}; @@ -34,7 +33,7 @@ use ethcore::miner::{stratum, MinerOptions}; use ethcore::verification::queue::VerifierSettings; use miner::pool; -use rpc::{IpcConfiguration, HttpConfiguration, WsConfiguration, UiConfiguration}; +use rpc::{IpcConfiguration, HttpConfiguration, WsConfiguration}; use parity_rpc::NetworkSettings; use cache::CacheConfig; use helpers::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_price, geth_ipc_path, parity_ipc_path, to_bootnodes, to_addresses, to_address, to_queue_strategy, to_queue_penalization, passwords_from_files}; @@ -42,7 +41,6 @@ use dir::helpers::{replace_home, replace_home_and_local}; use params::{ResealPolicy, AccountsConfig, GasPricerConfig, MinerExtras, SpecType}; use ethcore_logger::Config as LogConfig; use dir::{self, Directories, default_hypervisor_path, default_local_path, default_data_path}; -use dapps::Configuration as DappsConfiguration; use ipfs::Configuration as IpfsConfiguration; use ethcore_private_tx::{ProviderConfig, EncryptorConfig}; use secretstore::{NodeSecretKey, Configuration as SecretStoreConfiguration, ContractAddress as SecretStoreContractAddress}; @@ -65,7 +63,7 @@ pub enum Cmd { Account(AccountCmd), ImportPresaleWallet(ImportWallet), Blockchain(BlockchainCmd), - SignerToken(WsConfiguration, UiConfiguration, LogConfig), + SignerToken(WsConfiguration, LogConfig), SignerSign { id: Option, pwfile: Option, @@ -104,7 +102,7 @@ impl Configuration { /// # Example /// /// ``` - /// let _cfg = parity::Configuration::parse_cli(&["--light", "--chain", "koven"]).unwrap(); + /// let _cfg = parity_ethereum::Configuration::parse_cli(&["--light", "--chain", "kovan"]).unwrap(); /// ``` pub fn parse_cli>(command: &[S]) -> Result { let config = Configuration { @@ -130,16 +128,13 @@ impl Configuration { let http_conf = self.http_config()?; let ipc_conf = self.ipc_config()?; let net_conf = self.net_config()?; - let ui_conf = self.ui_config(); let network_id = self.network_id(); let cache_config = self.cache_config(); let tracing = self.args.arg_tracing.parse()?; let fat_db = self.args.arg_fat_db.parse()?; let compaction = self.args.arg_db_compaction.parse()?; - let wal = !self.args.flag_fast_and_loose; let warp_sync = !self.args.flag_no_warp; let geth_compatibility = self.args.flag_geth; - let dapps_conf = self.dapps_config(); let ipfs_conf = self.ipfs_config(); let secretstore_conf = self.secretstore_config()?; let format = self.format()?; @@ -150,7 +145,7 @@ impl Configuration { let authfile = ::signer::codes_path(&ws_conf.signer_path); if self.args.cmd_signer_new_token { - Cmd::SignerToken(ws_conf, ui_conf, logger_config.clone()) + Cmd::SignerToken(ws_conf, logger_config.clone()) } else if self.args.cmd_signer_sign { let pwfile = self.accounts_config()?.password_files.first().map(|pwfile| { PathBuf::from(pwfile) @@ -238,7 +233,6 @@ impl Configuration { pruning_history: pruning_history, pruning_memory: self.args.arg_pruning_memory, compaction: compaction, - wal: wal, tracing: tracing, fat_db: fat_db, vm_type: vm_type, @@ -260,7 +254,6 @@ impl Configuration { pruning_history: pruning_history, pruning_memory: self.args.arg_pruning_memory, compaction: compaction, - wal: wal, tracing: tracing, fat_db: fat_db, from_block: to_block_id(&self.args.arg_export_blocks_from)?, @@ -279,7 +272,6 @@ impl Configuration { pruning_history: pruning_history, pruning_memory: self.args.arg_pruning_memory, compaction: compaction, - wal: wal, tracing: tracing, fat_db: fat_db, at: to_block_id(&self.args.arg_export_state_at)?, @@ -304,7 +296,6 @@ impl Configuration { fat_db: fat_db, compaction: compaction, file_path: self.args.arg_snapshot_file.clone(), - wal: wal, kind: snapshot::Kind::Take, block_at: to_block_id(&self.args.arg_snapshot_at)?, }; @@ -321,7 +312,6 @@ impl Configuration { fat_db: fat_db, compaction: compaction, file_path: self.args.arg_restore_file.clone(), - wal: wal, kind: snapshot::Kind::Restore, block_at: to_block_id("latest")?, // unimportant. }; @@ -333,7 +323,6 @@ impl Configuration { spec: spec, pruning: pruning, compaction: compaction, - wal: wal, }; Cmd::ExportHardcodedSync(export_hs_cmd) } else { @@ -358,7 +347,7 @@ impl Configuration { logger_config: logger_config.clone(), miner_options: self.miner_options()?, gas_price_percentile: self.args.arg_gas_price_percentile, - ntp_servers: self.ntp_servers(), + poll_lifetime: self.args.arg_poll_lifetime, ws_conf: ws_conf, http_conf: http_conf, ipc_conf: ipc_conf, @@ -373,21 +362,16 @@ impl Configuration { tracing: tracing, fat_db: fat_db, compaction: compaction, - wal: wal, vm_type: vm_type, warp_sync: warp_sync, warp_barrier: self.args.arg_warp_barrier, geth_compatibility: geth_compatibility, net_settings: self.network_settings()?, - dapps_conf: dapps_conf, ipfs_conf: ipfs_conf, - ui_conf: ui_conf, secretstore_conf: secretstore_conf, private_provider_conf: private_provider_conf, private_encryptor_conf: private_enc_conf, private_tx_enabled, - dapp: self.dapp_to_open()?, - ui: self.args.cmd_ui, name: self.args.arg_identity, custom_bootnodes: self.args.arg_bootnodes.is_some(), no_periodic_snapshot: self.args.flag_no_periodic_snapshot, @@ -553,6 +537,7 @@ impl Configuration { tx_queue_penalization: to_queue_penalization(self.args.arg_tx_time_limit)?, tx_queue_strategy: to_queue_strategy(&self.args.arg_tx_queue_strategy)?, + tx_queue_no_unfamiliar_locals: self.args.flag_tx_queue_no_unfamiliar_locals, refuse_service_transactions: self.args.flag_refuse_service_transactions, pool_limits: self.pool_limits()?, @@ -585,74 +570,16 @@ impl Configuration { Some(ref d) => to_u256(d)?, None => U256::max_value(), }, + no_early_reject: self.args.flag_tx_queue_no_early_reject, }) } - fn ui_port(&self) -> u16 { - self.args.arg_ports_shift + self.args.arg_ui_port - } - - fn ntp_servers(&self) -> Vec { - self.args.arg_ntp_servers.split(",").map(str::to_owned).collect() - } - - fn ui_config(&self) -> UiConfiguration { - let ui = self.ui_enabled(); - UiConfiguration { - enabled: ui.enabled, - interface: self.ui_interface(), - port: self.ui_port(), - hosts: self.ui_hosts(), - info_page_only: ui.info_page_only, - } - } - - fn dapps_config(&self) -> DappsConfiguration { - let dev_ui = if self.args.flag_ui_no_validation { vec![("127.0.0.1".to_owned(), 3000)] } else { vec![] }; - let ui_port = self.ui_port(); - - DappsConfiguration { - enabled: self.dapps_enabled(), - dapps_path: PathBuf::from(self.directories().dapps), - extra_dapps: if self.args.cmd_dapp { - self.args.arg_dapp_path.iter().map(|path| PathBuf::from(path)).collect() - } else { - vec![] - }, - extra_embed_on: { - let mut extra_embed = dev_ui.clone(); - match self.ui_hosts() { - // In case host validation is disabled allow all frame ancestors - None => { - // NOTE Chrome does not seem to support "*:" - // we use `http(s)://*:` instead. - extra_embed.push(("http://*".to_owned(), ui_port)); - extra_embed.push(("https://*".to_owned(), ui_port)); - }, - Some(hosts) => extra_embed.extend(hosts.into_iter().filter_map(|host| { - let mut it = host.split(":"); - let host = it.next(); - let port = it.next().and_then(|v| u16::from_str(v).ok()); - - match (host, port) { - (Some(host), Some(port)) => Some((host.into(), port)), - (Some(host), None) => Some((host.into(), ui_port)), - _ => None, - } - })), - } - extra_embed - }, - extra_script_src: dev_ui, - } - } - fn secretstore_config(&self) -> Result { Ok(SecretStoreConfiguration { enabled: self.secretstore_enabled(), http_enabled: self.secretstore_http_enabled(), - acl_check_enabled: self.secretstore_acl_check_enabled(), auto_migrate_enabled: self.secretstore_auto_migrate_enabled(), + acl_check_contract_address: self.secretstore_acl_check_contract_address()?, service_contract_address: self.secretstore_service_contract_address()?, service_contract_srv_gen_address: self.secretstore_service_contract_srv_gen_address()?, service_contract_srv_retr_address: self.secretstore_service_contract_srv_retr_address()?, @@ -660,6 +587,7 @@ impl Configuration { service_contract_doc_sretr_address: self.secretstore_service_contract_doc_sretr_address()?, self_secret: self.secretstore_self_secret()?, nodes: self.secretstore_nodes()?, + key_server_set_contract_address: self.secretstore_key_server_set_contract_address()?, interface: self.secretstore_interface(), port: self.args.arg_ports_shift + self.args.arg_secretstore_port, http_interface: self.secretstore_http_interface(), @@ -679,19 +607,6 @@ impl Configuration { } } - fn dapp_to_open(&self) -> Result, String> { - if !self.args.cmd_dapp { - return Ok(None); - } - let path = self.args.arg_dapp_path.as_ref().map(String::as_str).unwrap_or("."); - let path = Path::new(path).canonicalize() - .map_err(|e| format!("Invalid path: {}. Error: {:?}", path, e))?; - let name = path.file_name() - .and_then(|name| name.to_str()) - .ok_or_else(|| "Root path is not supported.".to_owned())?; - Ok(Some(name.into())) - } - fn gas_pricer_config(&self) -> Result { fn wei_per_gas(usd_per_tx: f32, usd_per_eth: f32) -> U256 { let wei_per_usd: f32 = 1.0e18 / usd_per_eth; @@ -800,7 +715,15 @@ impl Configuration { ret.config_path = Some(net_path.to_str().unwrap().to_owned()); ret.reserved_nodes = self.init_reserved_nodes()?; ret.allow_non_reserved = !self.args.flag_reserved_only; - ret.client_version = version(); + ret.client_version = { + let mut client_version = version(); + if !self.args.arg_identity.is_empty() { + // Insert name after the "Parity-Ethereum/" at the beginning of version string. + let idx = client_version.find('/').unwrap_or(client_version.len()); + client_version.insert_str(idx, &format!("/{}", self.args.arg_identity)); + } + client_version + }; Ok(ret) } @@ -863,10 +786,6 @@ impl Configuration { Some(hosts) } - fn ui_hosts(&self) -> Option> { - self.hosts(&self.args.arg_ui_hosts, &self.ui_interface()) - } - fn rpc_hosts(&self) -> Option> { self.hosts(&self.args.arg_jsonrpc_hosts, &self.rpc_interface()) } @@ -876,7 +795,7 @@ impl Configuration { } fn ws_origins(&self) -> Option> { - if self.args.flag_unsafe_expose || self.args.flag_ui_no_validation { + if self.args.flag_unsafe_expose { return None; } @@ -919,15 +838,16 @@ impl Configuration { _ => 1, }, processing_threads: self.args.arg_jsonrpc_threads, + max_payload: match self.args.arg_jsonrpc_max_payload { + Some(max) if max > 0 => max as usize, + _ => 5usize, + }, }; Ok(conf) } fn ws_config(&self) -> Result { - let ui = self.ui_config(); - let http = self.http_config()?; - let support_token_api = // enabled when not unlocking self.args.arg_unlock.is_none(); @@ -941,8 +861,6 @@ impl Configuration { origins: self.ws_origins(), signer_path: self.directories().signer.into(), support_token_api, - ui_address: ui.address(), - dapps_address: http.address(), max_connections: self.args.arg_ws_max_connections, }; @@ -1017,7 +935,13 @@ impl Configuration { let is_using_base_path = self.args.arg_base_path.is_some(); // If base_path is set and db_path is not we default to base path subdir instead of LOCAL. let base_db_path = if is_using_base_path && self.args.arg_db_path.is_none() { - "$BASE/chains" + if self.args.flag_light { + "$BASE/chains_light" + } else { + "$BASE/chains" + } + } else if self.args.flag_light { + self.args.arg_db_path.as_ref().map_or(dir::CHAINS_PATH_LIGHT, |s| &s) } else { self.args.arg_db_path.as_ref().map_or(dir::CHAINS_PATH, |s| &s) }; @@ -1026,7 +950,6 @@ impl Configuration { let db_path = replace_home_and_local(&data_path, &local_path, &base_db_path); let cache_path = replace_home_and_local(&data_path, &local_path, cache_path); let keys_path = replace_home(&data_path, &self.args.arg_keys_path); - let dapps_path = replace_home(&data_path, &self.args.arg_dapps_path); let secretstore_path = replace_home(&data_path, &self.args.arg_secretstore_path); let ui_path = replace_home(&data_path, &self.args.arg_ui_path); @@ -1035,7 +958,6 @@ impl Configuration { base: data_path, cache: cache_path, db: db_path, - dapps: dapps_path, signer: ui_path, secretstore: secretstore_path, } @@ -1065,10 +987,6 @@ impl Configuration { }.into() } - fn ui_interface(&self) -> String { - self.interface(&self.args.arg_ui_interface) - } - fn rpc_interface(&self) -> String { let rpc_interface = self.args.arg_rpcaddr.clone().unwrap_or(self.args.arg_jsonrpc_interface.clone()); self.interface(&rpc_interface) @@ -1144,10 +1062,6 @@ impl Configuration { !self.args.flag_no_ws } - fn dapps_enabled(&self) -> bool { - !self.args.flag_dapps_off && !self.args.flag_no_dapps && self.rpc_enabled() && cfg!(feature = "dapps") - } - fn secretstore_enabled(&self) -> bool { !self.args.flag_no_secretstore && cfg!(feature = "secretstore") } @@ -1156,14 +1070,14 @@ impl Configuration { !self.args.flag_no_secretstore_http && cfg!(feature = "secretstore") } - fn secretstore_acl_check_enabled(&self) -> bool { - !self.args.flag_no_secretstore_acl_check - } - fn secretstore_auto_migrate_enabled(&self) -> bool { !self.args.flag_no_secretstore_auto_migrate } + fn secretstore_acl_check_contract_address(&self) -> Result, String> { + into_secretstore_service_contract_address(self.args.arg_secretstore_acl_contract.as_ref()) + } + fn secretstore_service_contract_address(&self) -> Result, String> { into_secretstore_service_contract_address(self.args.arg_secretstore_contract.as_ref()) } @@ -1184,22 +1098,8 @@ impl Configuration { into_secretstore_service_contract_address(self.args.arg_secretstore_doc_sretr_contract.as_ref()) } - fn ui_enabled(&self) -> UiEnabled { - if self.args.flag_force_ui { - return UiEnabled { - enabled: true, - info_page_only: false, - }; - } - - let ui_disabled = self.args.arg_unlock.is_some() || - self.args.flag_geth || - self.args.flag_no_ui; - - return UiEnabled { - enabled: (self.args.cmd_ui || !ui_disabled) && cfg!(feature = "ui-enabled"), - info_page_only: !self.args.cmd_ui, - } + fn secretstore_key_server_set_contract_address(&self) -> Result, String> { + into_secretstore_service_contract_address(self.args.arg_secretstore_server_set_contract.as_ref()) } fn verifier_settings(&self) -> VerifierSettings { @@ -1220,17 +1120,11 @@ impl Configuration { } } -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -struct UiEnabled { - pub enabled: bool, - pub info_page_only: bool, -} - -fn into_secretstore_service_contract_address(s: &str) -> Result, String> { - match s { - "none" => Ok(None), - "registry" => Ok(Some(SecretStoreContractAddress::Registry)), - a => Ok(Some(SecretStoreContractAddress::Address(a.parse().map_err(|e| format!("{}", e))?))), +fn into_secretstore_service_contract_address(s: Option<&String>) -> Result, String> { + match s.map(String::as_str) { + None | Some("none") => Ok(None), + Some("registry") => Ok(Some(SecretStoreContractAddress::Registry)), + Some(a) => Ok(Some(SecretStoreContractAddress::Address(a.parse().map_err(|e| format!("{}", e))?))), } } @@ -1254,7 +1148,7 @@ mod tests { use helpers::{default_network_config}; use params::SpecType; use presale::ImportWallet; - use rpc::{WsConfiguration, UiConfiguration}; + use rpc::WsConfiguration; use rpc_apis::ApiSet; use run::RunCmd; @@ -1343,7 +1237,6 @@ mod tests { pruning_history: 64, pruning_memory: 32, compaction: Default::default(), - wal: true, tracing: Default::default(), fat_db: Default::default(), vm_type: VMType::Interpreter, @@ -1368,7 +1261,6 @@ mod tests { pruning_memory: 32, format: Default::default(), compaction: Default::default(), - wal: true, tracing: Default::default(), fat_db: Default::default(), from_block: BlockId::Number(1), @@ -1391,7 +1283,6 @@ mod tests { pruning_memory: 32, format: Default::default(), compaction: Default::default(), - wal: true, tracing: Default::default(), fat_db: Default::default(), at: BlockId::Latest, @@ -1416,7 +1307,6 @@ mod tests { pruning_memory: 32, format: Some(DataFormat::Hex), compaction: Default::default(), - wal: true, tracing: Default::default(), fat_db: Default::default(), from_block: BlockId::Number(1), @@ -1438,16 +1328,8 @@ mod tests { origins: Some(vec!["parity://*".into(),"chrome-extension://*".into(), "moz-extension://*".into()]), hosts: Some(vec![]), signer_path: expected.into(), - ui_address: Some("127.0.0.1:8180".into()), - dapps_address: Some("127.0.0.1:8545".into()), support_token_api: true, max_connections: 100, - }, UiConfiguration { - enabled: true, - interface: "127.0.0.1".into(), - port: 8180, - hosts: Some(vec![]), - info_page_only: true, }, LogConfig { color: true, mode: None, @@ -1481,12 +1363,7 @@ mod tests { logger_config: Default::default(), miner_options: Default::default(), gas_price_percentile: 50, - ntp_servers: vec![ - "0.parity.pool.ntp.org:123".into(), - "1.parity.pool.ntp.org:123".into(), - "2.parity.pool.ntp.org:123".into(), - "3.parity.pool.ntp.org:123".into(), - ], + poll_lifetime: 60, ws_conf: Default::default(), http_conf: Default::default(), ipc_conf: Default::default(), @@ -1510,19 +1387,14 @@ mod tests { mode: Default::default(), tracing: Default::default(), compaction: Default::default(), - wal: true, vm_type: Default::default(), geth_compatibility: false, net_settings: Default::default(), - dapps_conf: Default::default(), ipfs_conf: Default::default(), - ui_conf: Default::default(), secretstore_conf: Default::default(), private_provider_conf: Default::default(), private_encryptor_conf: Default::default(), private_tx_enabled: false, - ui: false, - dapp: None, name: "".into(), custom_bootnodes: false, fat_db: Default::default(), @@ -1704,49 +1576,6 @@ mod tests { assert_eq!(conf2.ipfs_cors(), Some(vec!["http://parity.io".into(),"http://something.io".into()])); } - #[test] - fn should_disable_signer_in_geth_compat() { - // given - - // when - let conf0 = parse(&["parity", "--geth"]); - let conf1 = parse(&["parity", "--geth", "--force-ui"]); - let conf2 = parse(&["parity", "--geth", "ui"]); - let conf3 = parse(&["parity"]); - - // then - assert_eq!(conf0.ui_enabled(), UiEnabled { - enabled: false, - info_page_only: true, - }); - assert_eq!(conf1.ui_enabled(), UiEnabled { - enabled: true, - info_page_only: false, - }); - assert_eq!(conf2.ui_enabled(), UiEnabled { - enabled: true, - info_page_only: false, - }); - assert_eq!(conf3.ui_enabled(), UiEnabled { - enabled: true, - info_page_only: true, - }); - } - - #[test] - fn should_disable_signer_when_account_is_unlocked() { - // given - - // when - let conf0 = parse(&["parity", "--unlock", "0x0"]); - - // then - assert_eq!(conf0.ui_enabled(), UiEnabled { - enabled: false, - info_page_only: true, - }); - } - #[test] fn should_parse_ui_configuration() { // given @@ -1757,83 +1586,22 @@ mod tests { let conf2 = parse(&["parity", "--ui-path=signer", "--ui-port", "3123"]); let conf3 = parse(&["parity", "--ui-path=signer", "--ui-interface", "test"]); let conf4 = parse(&["parity", "--ui-path=signer", "--force-ui"]); - let conf5 = parse(&["parity", "--ui-path=signer", "ui"]); // then assert_eq!(conf0.directories().signer, "signer".to_owned()); - assert_eq!(conf0.ui_config(), UiConfiguration { - enabled: true, - interface: "127.0.0.1".into(), - port: 8180, - hosts: Some(vec![]), - info_page_only: true, - }); assert!(conf1.ws_config().unwrap().hosts.is_some()); - assert_eq!(conf1.ws_config().unwrap().origins, None); + assert_eq!(conf1.ws_config().unwrap().origins, Some(vec!["parity://*".into(), "chrome-extension://*".into(), "moz-extension://*".into()])); assert_eq!(conf1.directories().signer, "signer".to_owned()); - assert_eq!(conf1.ui_config(), UiConfiguration { - enabled: true, - interface: "127.0.0.1".into(), - port: 8180, - hosts: Some(vec![]), - info_page_only: true, - }); - assert_eq!(conf1.dapps_config().extra_embed_on, vec![("127.0.0.1".to_owned(), 3000)]); assert!(conf2.ws_config().unwrap().hosts.is_some()); assert_eq!(conf2.directories().signer, "signer".to_owned()); - assert_eq!(conf2.ui_config(), UiConfiguration { - enabled: true, - interface: "127.0.0.1".into(), - port: 3123, - hosts: Some(vec![]), - info_page_only: true, - }); assert!(conf3.ws_config().unwrap().hosts.is_some()); assert_eq!(conf3.directories().signer, "signer".to_owned()); - assert_eq!(conf3.ui_config(), UiConfiguration { - enabled: true, - interface: "test".into(), - port: 8180, - hosts: Some(vec![]), - info_page_only: true, - }); assert!(conf4.ws_config().unwrap().hosts.is_some()); assert_eq!(conf4.directories().signer, "signer".to_owned()); - assert_eq!(conf4.ui_config(), UiConfiguration { - enabled: true, - interface: "127.0.0.1".into(), - port: 8180, - hosts: Some(vec![]), - info_page_only: false, - }); - - assert!(conf5.ws_config().unwrap().hosts.is_some()); - assert_eq!(conf5.directories().signer, "signer".to_owned()); - assert_eq!(conf5.ui_config(), UiConfiguration { - enabled: true, - interface: "127.0.0.1".into(), - port: 8180, - hosts: Some(vec![]), - info_page_only: false, - }); - } - - #[test] - fn should_parse_dapp_opening() { - // given - let tempdir = TempDir::new("").unwrap(); - - // when - let conf0 = parse(&["parity", "dapp", tempdir.path().to_str().unwrap()]); - - // then - assert_eq!(conf0.dapp_to_open(), Ok(Some(tempdir.path().file_name().unwrap().to_str().unwrap().into()))); - let extra_dapps = conf0.dapps_config().extra_dapps; - assert_eq!(extra_dapps, vec![tempdir.path().to_owned()]); } #[test] @@ -1881,7 +1649,6 @@ mod tests { assert_eq!(c.net_conf.min_peers, 50); assert_eq!(c.net_conf.max_peers, 100); assert_eq!(c.ipc_conf.enabled, false); - assert_eq!(c.dapps_conf.enabled, false); assert_eq!(c.miner_options.force_sealing, true); assert_eq!(c.miner_options.reseal_on_external_tx, true); assert_eq!(c.miner_options.reseal_on_own_tx, true); @@ -1962,6 +1729,19 @@ mod tests { } } + #[test] + fn test_identity_arg() { + let args = vec!["parity", "--identity", "Somebody"]; + let conf = Configuration::parse_cli(&args).unwrap(); + match conf.into_command().unwrap().cmd { + Cmd::Run(c) => { + assert_eq!(c.name, "Somebody"); + assert!(c.net_conf.client_version.starts_with("Parity-Ethereum/Somebody/")); + } + _ => panic!("Should be Cmd::Run"), + } + } + #[test] fn should_apply_ports_shift() { // given @@ -1976,19 +1756,16 @@ mod tests { assert_eq!(conf0.network_settings().unwrap().rpc_port, 8546); assert_eq!(conf0.http_config().unwrap().port, 8546); assert_eq!(conf0.ws_config().unwrap().port, 8547); - assert_eq!(conf0.ui_config().port, 8181); assert_eq!(conf0.secretstore_config().unwrap().port, 8084); assert_eq!(conf0.secretstore_config().unwrap().http_port, 8083); assert_eq!(conf0.ipfs_config().port, 5002); assert_eq!(conf0.stratum_options().unwrap().unwrap().port, 8009); - assert_eq!(conf1.net_addresses().unwrap().0.port(), 30304); assert_eq!(conf1.network_settings().unwrap().network_port, 30304); assert_eq!(conf1.network_settings().unwrap().rpc_port, 8545); assert_eq!(conf1.http_config().unwrap().port, 8545); assert_eq!(conf1.ws_config().unwrap().port, 8547); - assert_eq!(conf1.ui_config().port, 8181); assert_eq!(conf1.secretstore_config().unwrap().port, 8084); assert_eq!(conf1.secretstore_config().unwrap().http_port, 8083); assert_eq!(conf1.ipfs_config().port, 5002); @@ -2008,8 +1785,6 @@ mod tests { assert_eq!(&conf0.ws_config().unwrap().interface, "0.0.0.0"); assert_eq!(conf0.ws_config().unwrap().hosts, None); assert_eq!(conf0.ws_config().unwrap().origins, None); - assert_eq!(&conf0.ui_config().interface, "0.0.0.0"); - assert_eq!(conf0.ui_config().hosts, None); assert_eq!(&conf0.secretstore_config().unwrap().interface, "0.0.0.0"); assert_eq!(&conf0.secretstore_config().unwrap().http_interface, "0.0.0.0"); assert_eq!(&conf0.ipfs_config().interface, "0.0.0.0"); diff --git a/parity/dapps.rs b/parity/dapps.rs deleted file mode 100644 index 2219f7cbee5a43a03d0a4436c4a2fae0ff0c12c6..0000000000000000000000000000000000000000 --- a/parity/dapps.rs +++ /dev/null @@ -1,320 +0,0 @@ -// Copyright 2015-2017 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 . - -use std::path::PathBuf; -use std::sync::Arc; - -use bytes::Bytes; -use dir::default_data_path; -use dir::helpers::replace_home; -use ethcore::client::{Client, BlockChainClient, BlockId, CallContract}; -use sync::LightSync; -use futures::{Future, future, IntoFuture}; -use futures_cpupool::CpuPool; -use hash_fetch::fetch::Client as FetchClient; -use registrar::{RegistrarClient, Asynchronous}; -use light::client::LightChainClient; -use light::on_demand::{self, OnDemand}; -use node_health::{SyncStatus, NodeHealth}; -use rpc; -use rpc_apis::SignerService; -use transaction::{Transaction, Action}; -use ethereum_types::Address; - -#[derive(Debug, PartialEq, Clone)] -pub struct Configuration { - pub enabled: bool, - pub dapps_path: PathBuf, - pub extra_dapps: Vec, - pub extra_embed_on: Vec<(String, u16)>, - pub extra_script_src: Vec<(String, u16)>, -} - -impl Default for Configuration { - fn default() -> Self { - let data_dir = default_data_path(); - Configuration { - enabled: true, - dapps_path: replace_home(&data_dir, "$BASE/dapps").into(), - extra_dapps: vec![], - extra_embed_on: vec![], - extra_script_src: vec![], - } - } -} - -impl Configuration { - pub fn address(&self, address: Option<::parity_rpc::Host>) -> Option<::parity_rpc::Host> { - match self.enabled { - true => address, - false => None, - } - } -} - -/// Registrar implementation of the full client. -pub struct FullRegistrar { - /// Handle to the full client. - pub client: Arc, -} - -impl FullRegistrar { - pub fn new(client: Arc) -> Self { - FullRegistrar { - client, - } - } -} - -impl RegistrarClient for FullRegistrar { - type Call = Asynchronous; - - fn registrar_address(&self) -> Result { - self.client.registrar_address() - .ok_or_else(|| "Registrar not defined.".into()) - } - - fn call_contract(&self, address: Address, data: Bytes) -> Self::Call { - Box::new(self.client.call_contract(BlockId::Latest, address, data).into_future()) - } -} - -/// Registrar implementation for the light client. -pub struct LightRegistrar { - /// The light client. - pub client: Arc, - /// Handle to the on-demand service. - pub on_demand: Arc, - /// Handle to the light network service. - pub sync: Arc, -} - -impl RegistrarClient for LightRegistrar { - type Call = Box + Send>; - - fn registrar_address(&self) -> Result { - self.client.engine().additional_params().get("registrar") - .ok_or_else(|| "Registrar not defined.".into()) - .and_then(|registrar| { - registrar.parse().map_err(|e| format!("Invalid registrar address: {:?}", e)) - }) - } - - fn call_contract(&self, address: Address, data: Bytes) -> Self::Call { - let header = self.client.best_block_header(); - let env_info = self.client.env_info(BlockId::Hash(header.hash())) - .ok_or_else(|| format!("Cannot fetch env info for header {}", header.hash())); - - let env_info = match env_info { - Ok(e) => e, - Err(e) => return Box::new(future::err(e)), - }; - - let maybe_future = self.sync.with_context(move |ctx| { - self.on_demand - .request(ctx, on_demand::request::TransactionProof { - tx: Transaction { - nonce: self.client.engine().account_start_nonce(header.number()), - action: Action::Call(address), - gas: 50_000.into(), // should be enough for all registry lookups. TODO: exponential backoff - gas_price: 0.into(), - value: 0.into(), - data: data, - }.fake_sign(Address::default()), - header: header.into(), - env_info: env_info, - engine: self.client.engine().clone(), - }) - .expect("No back-references; therefore all back-refs valid; qed") - .then(|res| match res { - Ok(Ok(executed)) => Ok(executed.output), - Ok(Err(e)) => Err(format!("Failed to execute transaction: {}", e)), - Err(_) => Err(format!("On-demand service dropped request unexpectedly.")), - }) - }); - - match maybe_future { - Some(fut) => Box::new(fut), - None => Box::new(future::err("cannot query registry: network disabled".into())), - } - } -} - -// TODO: light client implementation forwarding to OnDemand and waiting for future -// to resolve. -#[derive(Clone)] -pub struct Dependencies { - pub node_health: NodeHealth, - pub sync_status: Arc, - pub contract_client: Arc>, - pub fetch: FetchClient, - pub pool: CpuPool, - pub signer: Arc, - pub ui_address: Option<(String, u16)>, - pub info_page_only: bool, -} - -pub fn new(configuration: Configuration, deps: Dependencies) -> Result, String> { - if !configuration.enabled { - return Ok(None); - } - - server::dapps_middleware( - deps, - configuration.dapps_path, - configuration.extra_dapps, - rpc::DAPPS_DOMAIN, - configuration.extra_embed_on, - configuration.extra_script_src, - ).map(Some) -} - -pub fn new_ui(enabled: bool, deps: Dependencies) -> Result, String> { - if !enabled { - return Ok(None); - } - - server::ui_middleware( - deps, - rpc::DAPPS_DOMAIN, - ).map(Some) -} - -pub use self::server::{Middleware, service}; - -#[cfg(not(feature = "dapps"))] -mod server { - use super::Dependencies; - use std::sync::Arc; - use std::path::PathBuf; - use parity_rpc::{hyper, RequestMiddleware, RequestMiddlewareAction}; - use rpc_apis; - - pub struct Middleware; - impl RequestMiddleware for Middleware { - fn on_request(&self, _req: hyper::Request) -> RequestMiddlewareAction { - unreachable!() - } - } - - pub fn dapps_middleware( - _deps: Dependencies, - _dapps_path: PathBuf, - _extra_dapps: Vec, - _dapps_domain: &str, - _extra_embed_on: Vec<(String, u16)>, - _extra_script_src: Vec<(String, u16)>, - ) -> Result { - Err("Your Parity version has been compiled without WebApps support.".into()) - } - - pub fn ui_middleware( - _deps: Dependencies, - _dapps_domain: &str, - ) -> Result { - Err("Your Parity version has been compiled without UI support.".into()) - } - - pub fn service(_: &Option) -> Option> { - None - } -} - -#[cfg(feature = "dapps")] -mod server { - use super::Dependencies; - use std::path::PathBuf; - use std::sync::Arc; - use rpc_apis; - - use parity_dapps; - - pub use parity_dapps::Middleware; - - pub fn dapps_middleware( - deps: Dependencies, - dapps_path: PathBuf, - extra_dapps: Vec, - dapps_domain: &str, - extra_embed_on: Vec<(String, u16)>, - extra_script_src: Vec<(String, u16)>, - ) -> Result { - let signer = deps.signer; - let web_proxy_tokens = Arc::new(move |token| signer.web_proxy_access_token_domain(&token)); - - Ok(parity_dapps::Middleware::dapps( - deps.pool, - deps.node_health, - deps.ui_address, - extra_embed_on, - extra_script_src, - dapps_path, - extra_dapps, - dapps_domain, - deps.contract_client, - deps.sync_status, - web_proxy_tokens, - deps.fetch, - )) - } - - pub fn ui_middleware( - deps: Dependencies, - dapps_domain: &str, - ) -> Result { - Ok(parity_dapps::Middleware::ui( - deps.pool, - deps.node_health, - dapps_domain, - deps.contract_client, - deps.sync_status, - deps.fetch, - deps.info_page_only, - )) - } - - pub fn service(middleware: &Option) -> Option> { - middleware.as_ref().map(|m| Arc::new(DappsServiceWrapper { - endpoints: m.endpoints().clone(), - }) as Arc) - } - - pub struct DappsServiceWrapper { - endpoints: parity_dapps::Endpoints, - } - - impl rpc_apis::DappsService for DappsServiceWrapper { - fn list_dapps(&self) -> Vec { - self.endpoints.list() - .into_iter() - .map(|app| rpc_apis::LocalDapp { - id: app.id.unwrap_or_else(|| "unknown".into()), - name: app.name, - description: app.description, - version: app.version, - author: app.author, - icon_url: app.icon_url, - local_url: app.local_url, - }) - .collect() - } - - fn refresh_local_dapps(&self) -> bool { - self.endpoints.refresh_local_dapps(); - true - } - } -} diff --git a/parity/db/mod.rs b/parity/db/mod.rs index 39f43fd145e03e5084d0a645d3573febb6779d8a..a5d66339826968076be38e3b80345d4a99a54aa3 100644 --- a/parity/db/mod.rs +++ b/parity/db/mod.rs @@ -19,7 +19,7 @@ #[path="rocksdb/mod.rs"] mod impls; -pub use self::impls::{open_db, open_client_db, restoration_db_handler, migrate}; +pub use self::impls::{open_db, restoration_db_handler, migrate}; #[cfg(feature = "secretstore")] pub use self::impls::open_secretstore_db; diff --git a/parity/db/rocksdb/blooms.rs b/parity/db/rocksdb/blooms.rs new file mode 100644 index 0000000000000000000000000000000000000000..eba8eb896f794504a999e5a3b342172824a03c4c --- /dev/null +++ b/parity/db/rocksdb/blooms.rs @@ -0,0 +1,84 @@ +// 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 . + +//! Blooms migration from rocksdb to blooms-db + +use std::path::Path; +use ethereum_types::Bloom; +use ethcore::error::Error; +use rlp; +use super::kvdb_rocksdb::DatabaseConfig; +use super::open_database; + +pub fn migrate_blooms>(path: P, config: &DatabaseConfig) -> Result<(), Error> { + // init + let db = open_database(&path.as_ref().to_string_lossy(), config)?; + + // possible optimization: + // pre-allocate space on disk for faster migration + + // iterate over header blooms and insert them in blooms-db + // Some(3) -> COL_EXTRA + // 3u8 -> ExtrasIndex::BlocksBlooms + // 0u8 -> level 0 + let blooms_iterator = db.key_value() + .iter_from_prefix(Some(3), &[3u8, 0u8]) + .filter(|(key, _)| key.len() == 6) + .take_while(|(key, _)| { + key[0] == 3u8 && key[1] == 0u8 + }) + .map(|(key, group)| { + let number = + (key[2] as u64) << 24 | + (key[3] as u64) << 16 | + (key[4] as u64) << 8 | + (key[5] as u64); + + let blooms = rlp::decode_list::(&group); + (number, blooms) + }); + + for (number, blooms) in blooms_iterator { + db.blooms().insert_blooms(number, blooms.iter())?; + } + + // iterate over trace blooms and insert them in blooms-db + // Some(4) -> COL_TRACE + // 1u8 -> TraceDBIndex::BloomGroups + // 0u8 -> level 0 + let trace_blooms_iterator = db.key_value() + .iter_from_prefix(Some(4), &[1u8, 0u8]) + .filter(|(key, _)| key.len() == 6) + .take_while(|(key, _)| { + key[0] == 1u8 && key[1] == 0u8 + }) + .map(|(key, group)| { + let number = + (key[2] as u64) | + (key[3] as u64) << 8 | + (key[4] as u64) << 16 | + (key[5] as u64) << 24; + + let blooms = rlp::decode_list::(&group); + (number, blooms) + }); + + for (number, blooms) in trace_blooms_iterator { + db.trace_blooms().insert_blooms(number, blooms.iter())?; + } + + Ok(()) +} diff --git a/parity/db/rocksdb/helpers.rs b/parity/db/rocksdb/helpers.rs index ca685d3e86db9c12dd9a14d921dd236e242dc9ab..1b7f05c1a14095d6690b7b5d25b460e61cfa3e1c 100644 --- a/parity/db/rocksdb/helpers.rs +++ b/parity/db/rocksdb/helpers.rs @@ -32,7 +32,6 @@ pub fn client_db_config(client_path: &Path, client_config: &ClientConfig) -> Dat client_db_config.memory_budget = client_config.db_cache_size; client_db_config.compaction = compaction_profile(&client_config.db_compaction, &client_path); - client_db_config.wal = client_config.db_wal; client_db_config } diff --git a/parity/db/rocksdb/migration.rs b/parity/db/rocksdb/migration.rs index df6a4b5dc9ca360707e8fdcde3ef7bf26fb0d2b6..c6489116b5df88a5cf032ad6516881eca9d7c381 100644 --- a/parity/db/rocksdb/migration.rs +++ b/parity/db/rocksdb/migration.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -18,11 +18,13 @@ use std::fs; use std::io::{Read, Write, Error as IoError, ErrorKind}; use std::path::{Path, PathBuf}; use std::fmt::{Display, Formatter, Error as FmtError}; -use super::migration_rocksdb::{self, Manager as MigrationManager, Config as MigrationConfig, ChangeColumns}; -use super::kvdb_rocksdb::CompactionProfile; +use super::migration_rocksdb::{Manager as MigrationManager, Config as MigrationConfig, ChangeColumns}; +use super::kvdb_rocksdb::{CompactionProfile, DatabaseConfig}; use ethcore::client::DatabaseCompactionProfile; +use ethcore::{self, db}; use super::helpers; +use super::blooms::migrate_blooms; /// The migration from v10 to v11. /// Adds a column for node info. @@ -40,13 +42,12 @@ pub const TO_V12: ChangeColumns = ChangeColumns { version: 12, }; - /// Database is assumed to be at default version, when no version file is found. const DEFAULT_VERSION: u32 = 5; /// Current version of database models. -const CURRENT_VERSION: u32 = 12; -/// First version of the consolidated database. -const CONSOLIDATION_VERSION: u32 = 9; +const CURRENT_VERSION: u32 = 13; +/// A version of database at which blooms-db was introduced +const BLOOMS_DB_VERSION: u32 = 13; /// Defines how many items are migrated to the new version of database at once. const BATCH_SIZE: usize = 1024; /// Version file name. @@ -61,8 +62,8 @@ pub enum Error { FutureDBVersion, /// Migration is not possible. MigrationImpossible, - /// Internal migration error. - Internal(migration_rocksdb::Error), + /// Blooms-db migration error. + BloomsDB(ethcore::error::Error), /// Migration was completed succesfully, /// but there was a problem with io. Io(IoError), @@ -74,7 +75,7 @@ impl Display for Error { Error::UnknownDatabaseVersion => "Current database version cannot be read".into(), Error::FutureDBVersion => "Database was created with newer client version. Upgrade your client or delete DB and resync.".into(), Error::MigrationImpossible => format!("Database migration to version {} is not possible.", CURRENT_VERSION), - Error::Internal(ref err) => format!("{}", err), + Error::BloomsDB(ref err) => format!("blooms-db migration error: {}", err), Error::Io(ref err) => format!("Unexpected io error on DB migration: {}.", err), }; @@ -88,15 +89,6 @@ impl From for Error { } } -impl From for Error { - fn from(err: migration_rocksdb::Error) -> Self { - match err.into() { - migration_rocksdb::ErrorKind::Io(e) => Error::Io(e), - err => Error::Internal(err.into()), - } - } -} - /// Returns the version file path. fn version_file_path(path: &Path) -> PathBuf { let mut file_path = path.to_owned(); @@ -159,7 +151,7 @@ fn consolidated_database_migrations(compaction_profile: &CompactionProfile) -> R } /// Migrates database at given position with given migration rules. -fn migrate_database(version: u32, db_path: PathBuf, mut migrations: MigrationManager) -> Result<(), Error> { +fn migrate_database(version: u32, db_path: &Path, mut migrations: MigrationManager) -> Result<(), Error> { // check if migration is needed if !migrations.is_needed(version) { return Ok(()) @@ -212,10 +204,25 @@ pub fn migrate(path: &Path, compaction_profile: &DatabaseCompactionProfile) -> R return Ok(()) } + let db_path = consolidated_database_path(path); + // Further migrations - if version >= CONSOLIDATION_VERSION && version < CURRENT_VERSION && exists(&consolidated_database_path(path)) { - println!("Migrating database from version {} to {}", ::std::cmp::max(CONSOLIDATION_VERSION, version), CURRENT_VERSION); - migrate_database(version, consolidated_database_path(path), consolidated_database_migrations(&compaction_profile)?)?; + if version < CURRENT_VERSION && exists(&db_path) { + println!("Migrating database from version {} to {}", version, CURRENT_VERSION); + migrate_database(version, &db_path, consolidated_database_migrations(&compaction_profile)?)?; + + if version < BLOOMS_DB_VERSION { + println!("Migrating blooms to blooms-db..."); + let db_config = DatabaseConfig { + max_open_files: 64, + memory_budget: None, + compaction: compaction_profile, + columns: db::NUM_COLUMNS, + }; + + migrate_blooms(&db_path, &db_config).map_err(Error::BloomsDB)?; + } + println!("Migration finished"); } diff --git a/parity/db/rocksdb/mod.rs b/parity/db/rocksdb/mod.rs index 7bfd28f6502690048b87f8fb9ec1696f952f2972..91160f9218aa1fbab8783a2ffc865e51959acefa 100644 --- a/parity/db/rocksdb/mod.rs +++ b/parity/db/rocksdb/mod.rs @@ -17,20 +17,44 @@ extern crate kvdb_rocksdb; extern crate migration_rocksdb; +use std::{io, fs}; use std::sync::Arc; use std::path::Path; +use blooms_db; +use ethcore::{BlockChainDBHandler, BlockChainDB}; use ethcore::db::NUM_COLUMNS; use ethcore::client::{ClientConfig, DatabaseCompactionProfile}; -use kvdb::{KeyValueDB, KeyValueDBHandler}; +use kvdb::KeyValueDB; use self::kvdb_rocksdb::{Database, DatabaseConfig}; use cache::CacheConfig; +mod blooms; mod migration; mod helpers; pub use self::migration::migrate; +struct AppDB { + key_value: Arc, + blooms: blooms_db::Database, + trace_blooms: blooms_db::Database, +} + +impl BlockChainDB for AppDB { + fn key_value(&self) -> &Arc { + &self.key_value + } + + fn blooms(&self) -> &blooms_db::Database { + &self.blooms + } + + fn trace_blooms(&self) -> &blooms_db::Database { + &self.trace_blooms + } +} + /// Open a secret store DB using the given secret store data path. The DB path is one level beneath the data path. #[cfg(feature = "secretstore")] pub fn open_secretstore_db(data_path: &str) -> Result, String> { @@ -42,31 +66,17 @@ pub fn open_secretstore_db(data_path: &str) -> Result, String> { Ok(Arc::new(Database::open_default(&db_path).map_err(|e| format!("Error opening database: {:?}", e))?)) } -/// Open a new client DB. -pub fn open_client_db(client_path: &Path, client_config: &ClientConfig) -> Result, String> { - let client_db_config = helpers::client_db_config(client_path, client_config); - - let client_db = Arc::new(Database::open( - &client_db_config, - &client_path.to_str().expect("DB path could not be converted to string.") - ).map_err(|e| format!("Client service database error: {:?}", e))?); - - Ok(client_db) -} - /// Create a restoration db handler using the config generated by `client_path` and `client_config`. -pub fn restoration_db_handler(client_path: &Path, client_config: &ClientConfig) -> Box { - use kvdb::Error; - +pub fn restoration_db_handler(client_path: &Path, client_config: &ClientConfig) -> Box { let client_db_config = helpers::client_db_config(client_path, client_config); struct RestorationDBHandler { config: DatabaseConfig, } - impl KeyValueDBHandler for RestorationDBHandler { - fn open(&self, db_path: &Path) -> Result, Error> { - Ok(Arc::new(Database::open(&self.config, &db_path.to_string_lossy())?)) + impl BlockChainDBHandler for RestorationDBHandler { + fn open(&self, db_path: &Path) -> io::Result> { + open_database(&db_path.to_string_lossy(), &self.config) } } @@ -76,16 +86,31 @@ pub fn restoration_db_handler(client_path: &Path, client_config: &ClientConfig) } /// Open a new main DB. -pub fn open_db(client_path: &str, cache_config: &CacheConfig, compaction: &DatabaseCompactionProfile, wal: bool) -> Result, String> { +pub fn open_db(client_path: &str, cache_config: &CacheConfig, compaction: &DatabaseCompactionProfile) -> io::Result> { + let path = Path::new(client_path); + let db_config = DatabaseConfig { memory_budget: Some(cache_config.blockchain() as usize * 1024 * 1024), - compaction: helpers::compaction_profile(&compaction, &Path::new(client_path)), - wal: wal, + compaction: helpers::compaction_profile(&compaction, path), .. DatabaseConfig::with_columns(NUM_COLUMNS) }; - Ok(Arc::new(Database::open( - &db_config, - client_path - ).map_err(|e| format!("Failed to open database: {}", e))?)) + open_database(client_path, &db_config) +} + +pub fn open_database(client_path: &str, config: &DatabaseConfig) -> io::Result> { + let path = Path::new(client_path); + + let blooms_path = path.join("blooms"); + let trace_blooms_path = path.join("trace_blooms"); + fs::create_dir_all(&blooms_path)?; + fs::create_dir_all(&trace_blooms_path)?; + + let db = AppDB { + key_value: Arc::new(Database::open(&config, client_path)?), + blooms: blooms_db::Database::open(blooms_path)?, + trace_blooms: blooms_db::Database::open(trace_blooms_path)?, + }; + + Ok(Arc::new(db)) } diff --git a/parity/deprecated.rs b/parity/deprecated.rs index b41475d9dbdfe7dff35cdc0ed7bdf7ec025d4f18..91a872e220246b1de2c805cd2d550e426bea53db 100644 --- a/parity/deprecated.rs +++ b/parity/deprecated.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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,69 @@ 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")); + } + + // Removed in 2.0. + + if args.flag_fast_and_loose { + result.push(Deprecated::Removed("--fast-and-loose")); + } + + if args.cmd_dapp { + result.push(Deprecated::Removed("parity dapp")); + } + + if args.arg_dapp_path.is_some() { + result.push(Deprecated::Removed("--dapp-path")); + } + + if args.flag_no_dapps { + result.push(Deprecated::Removed("--no-dapps")); + } + + if args.arg_dapps_path.is_some() { + result.push(Deprecated::Removed("--dapps-path")); + } + + if args.arg_ntp_servers.is_some() { + result.push(Deprecated::Removed("--ntp-servers")); + } result } @@ -138,6 +259,8 @@ mod tests { args.arg_dapps_user = Some(Default::default()); args.arg_dapps_pass = Some(Default::default()); args.flag_dapps_apis_all = true; + args.flag_fast_and_loose = true; + args.arg_ntp_servers = Some(Default::default()); args }), vec![ Deprecated::DoesNothing("--warp"), @@ -150,14 +273,15 @@ 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"), + Deprecated::Removed("--fast-and-loose"), + Deprecated::Removed("--ntp-servers"), ]); } } - diff --git a/parity/export_hardcoded_sync.rs b/parity/export_hardcoded_sync.rs index 3aa2b5614908e5ac8fae3d76484a2fe06b92cd38..b3121f08616bc8fa68526a430dff025ac5eefb73 100644 --- a/parity/export_hardcoded_sync.rs +++ b/parity/export_hardcoded_sync.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -40,7 +40,6 @@ pub struct ExportHsyncCmd { pub spec: SpecType, pub pruning: Pruning, pub compaction: DatabaseCompactionProfile, - pub wal: bool, } pub fn execute(cmd: ExportHsyncCmd) -> Result { @@ -69,7 +68,7 @@ pub fn execute(cmd: ExportHsyncCmd) -> Result { execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?; // create dirs used by parity - cmd.dirs.create_dirs(false, false, false)?; + cmd.dirs.create_dirs(false, false)?; // TODO: configurable cache size. let cache = LightDataCache::new(Default::default(), Duration::from_secs(60 * GAS_CORPUS_EXPIRATION_MINUTES)); @@ -89,8 +88,7 @@ pub fn execute(cmd: ExportHsyncCmd) -> Result { // initialize database. let db = db::open_db(&db_dirs.client_path(algorithm).to_str().expect("DB path could not be converted to string."), &cmd.cache_config, - &cmd.compaction, - cmd.wal)?; + &cmd.compaction).map_err(|e| format!("Failed to open database {:?}", e))?; let service = light_client::Service::start(config, &spec, UnavailableDataFetcher, db, cache) .map_err(|e| format!("Error starting light client: {}", e))?; diff --git a/parity/helpers.rs b/parity/helpers.rs index a5ec3c99d4b2d4a93ad6817de2a046d1b69efdb3..342306c15851c3847d17a36487aaca60b6f5e57c 100644 --- a/parity/helpers.rs +++ b/parity/helpers.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -30,6 +30,7 @@ use upgrade::{upgrade, upgrade_data_paths}; use sync::{validate_node_url, self}; use db::migrate; use path; +use ethkey::Password; pub fn to_duration(s: &str) -> Result { to_seconds(s).map(Duration::from_secs) @@ -209,7 +210,6 @@ pub fn to_client_config( tracing: bool, fat_db: bool, compaction: DatabaseCompactionProfile, - wal: bool, vm_type: VMType, name: String, pruning: Algorithm, @@ -245,7 +245,6 @@ pub fn to_client_config( client_config.pruning = pruning; client_config.history = pruning_history; client_config.db_compaction = compaction; - client_config.db_wal = wal; client_config.vm_type = vm_type; client_config.name = name; client_config.verifier_type = if check_seal { VerifierType::Canon } else { VerifierType::CanonNoSeal }; @@ -277,7 +276,7 @@ pub fn execute_upgrades( } /// Prompts user asking for password. -pub fn password_prompt() -> Result { +pub fn password_prompt() -> Result { use rpassword::read_password; const STDIN_ERROR: &'static str = "Unable to ask for password on non-interactive terminal."; @@ -285,12 +284,12 @@ pub fn password_prompt() -> Result { print!("Type password: "); flush_stdout(); - let password = read_password().map_err(|_| STDIN_ERROR.to_owned())?; + let password = read_password().map_err(|_| STDIN_ERROR.to_owned())?.into(); print!("Repeat password: "); flush_stdout(); - let password_repeat = read_password().map_err(|_| STDIN_ERROR.to_owned())?; + let password_repeat = read_password().map_err(|_| STDIN_ERROR.to_owned())?.into(); if password != password_repeat { return Err("Passwords do not match!".into()); @@ -300,24 +299,24 @@ pub fn password_prompt() -> Result { } /// Read a password from password file. -pub fn password_from_file(path: String) -> Result { +pub fn password_from_file(path: String) -> Result { let passwords = passwords_from_files(&[path])?; // use only first password from the file - passwords.get(0).map(String::to_owned) + passwords.get(0).map(Password::clone) .ok_or_else(|| "Password file seems to be empty.".to_owned()) } /// Reads passwords from files. Treats each line as a separate password. -pub fn passwords_from_files(files: &[String]) -> Result, String> { +pub fn passwords_from_files(files: &[String]) -> Result, String> { let passwords = files.iter().map(|filename| { let file = File::open(filename).map_err(|_| format!("{} Unable to read password file. Ensure it exists and permissions are correct.", filename))?; let reader = BufReader::new(&file); let lines = reader.lines() .filter_map(|l| l.ok()) - .map(|pwd| pwd.trim().to_owned()) - .collect::>(); + .map(|pwd| pwd.trim().to_owned().into()) + .collect::>(); Ok(lines) - }).collect::>, String>>(); + }).collect::>, String>>(); Ok(passwords?.into_iter().flat_map(|x| x).collect()) } @@ -330,6 +329,7 @@ mod tests { use ethereum_types::U256; use ethcore::client::{Mode, BlockId}; use ethcore::miner::PendingSet; + use ethkey::Password; use super::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_address, to_addresses, to_price, geth_ipc_path, to_bootnodes, password_from_file}; #[test] @@ -435,7 +435,7 @@ ignored but the first password is trimmed "#).unwrap(); - assert_eq!(&password_from_file(path.to_str().unwrap().into()).unwrap(), "password with trailing whitespace"); + assert_eq!(password_from_file(path.to_str().unwrap().into()).unwrap(), Password::from("password with trailing whitespace")); } #[test] diff --git a/parity/informant.rs b/parity/informant.rs index 43788bc9d9036f29e3cd90f1867c3ae2f331cadc..d3489a52f3ba30ab42d66230c23493dd8f7acd3d 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -35,7 +35,7 @@ use io::{TimerToken, IoContext, IoHandler}; use light::Cache as LightDataCache; use light::client::{LightChainClient, LightChainNotify}; use number_prefix::{binary_prefix, Standalone, Prefixed}; -use parity_rpc::{is_major_importing}; +use parity_rpc::is_major_importing_or_waiting; use parity_rpc::informant::RpcStats; use ethereum_types::H256; use bytes::Bytes; @@ -128,7 +128,7 @@ impl InformantData for FullNodeInformantData { fn is_major_importing(&self) -> bool { let state = self.sync.as_ref().map(|sync| sync.status().state); - is_major_importing(state, self.client.queue_info()) + is_major_importing_or_waiting(state, self.client.queue_info(), false) } fn report(&self) -> Report { @@ -142,7 +142,8 @@ impl InformantData for FullNodeInformantData { cache_sizes.insert("queue", queue_info.mem_used); cache_sizes.insert("chain", blockchain_cache_info.total()); - let (importing, sync_info) = match (self.sync.as_ref(), self.net.as_ref()) { + let importing = self.is_major_importing(); + let sync_info = match (self.sync.as_ref(), self.net.as_ref()) { (Some(sync), Some(net)) => { let status = sync.status(); let num_peers_range = net.num_peers_range(); @@ -150,16 +151,15 @@ impl InformantData for FullNodeInformantData { cache_sizes.insert("sync", status.mem_used); - let importing = is_major_importing(Some(status.state), queue_info.clone()); - (importing, Some(SyncInfo { + Some(SyncInfo { last_imported_block_number: status.last_imported_block_number.unwrap_or(chain_info.best_block_number), last_imported_old_block_number: status.last_imported_old_block_number, num_peers: status.num_peers, max_peers: status.current_max_peers(num_peers_range.start, num_peers_range.end - 1), snapshot_sync: status.is_snapshot_syncing(), - })) + }) } - _ => (is_major_importing(self.sync.as_ref().map(|s| s.status().state), queue_info.clone()), None), + _ => None }; Report { @@ -304,7 +304,7 @@ impl Informant { paint(White.bold(), format!("{}", chain_info.best_block_hash)), if self.target.executes_transactions() { format!("{} blk/s {} tx/s {} Mgas/s", - paint(Yellow.bold(), format!("{:5.2}", (client_report.blocks_imported * 1000) as f64 / elapsed.as_milliseconds() as f64)), + paint(Yellow.bold(), format!("{:7.2}", (client_report.blocks_imported * 1000) as f64 / elapsed.as_milliseconds() as f64)), paint(Yellow.bold(), format!("{:6.1}", (client_report.transactions_applied * 1000) as f64 / elapsed.as_milliseconds() as f64)), paint(Yellow.bold(), format!("{:4}", (client_report.gas_processed / From::from(elapsed.as_milliseconds() * 1000)).low_u64())) ) @@ -335,7 +335,13 @@ impl Informant { match sync_info.as_ref() { Some(ref sync_info) => format!("{}{}/{} peers", match importing { - true => format!("{} ", paint(Green.bold(), format!("{:>8}", format!("#{}", sync_info.last_imported_block_number)))), + true => format!("{}", + if self.target.executes_transactions() { + paint(Green.bold(), format!("{:>8} ", format!("#{}", sync_info.last_imported_block_number))) + } else { + String::new() + } + ), false => match sync_info.last_imported_old_block_number { Some(number) => format!("{} ", paint(Yellow.bold(), format!("{:>8}", format!("#{}", number)))), None => String::new(), diff --git a/parity/ipfs.rs b/parity/ipfs.rs index ac9a4662b214a51a99f168aa042d75b4162e6b19..2cc2effca5ff3bc1a29b68fcc95184851d94db55 100644 --- a/parity/ipfs.rs +++ b/parity/ipfs.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/lib.rs b/parity/lib.rs index 6ef332da65e51756a260e1594cbcc3db1be04485..93edd74982b056c4027dc36f7855c4d3110e1400 100644 --- a/parity/lib.rs +++ b/parity/lib.rs @@ -42,8 +42,9 @@ extern crate serde_json; extern crate serde_derive; extern crate toml; +extern crate blooms_db; extern crate ethcore; -extern crate ethcore_bytes as bytes; +extern crate parity_bytes as bytes; extern crate ethcore_io as io; extern crate ethcore_light as light; extern crate ethcore_logger; @@ -56,7 +57,6 @@ extern crate ethcore_transaction as transaction; extern crate ethereum_types; extern crate ethkey; extern crate kvdb; -extern crate node_health; extern crate panic_hook; extern crate parity_hash_fetch as hash_fetch; extern crate parity_ipfs_api; @@ -76,7 +76,7 @@ extern crate registrar; #[macro_use] extern crate log as rlog; -#[cfg(feature="secretstore")] +#[cfg(feature = "secretstore")] extern crate ethcore_secretstore; #[cfg(feature = "dapps")] @@ -86,8 +86,6 @@ extern crate parity_dapps; #[macro_use] extern crate pretty_assertions; -#[cfg(windows)] extern crate winapi; - #[cfg(test)] extern crate tempdir; @@ -96,7 +94,6 @@ mod blockchain; mod cache; mod cli; mod configuration; -mod dapps; mod export_hardcoded_sync; mod ipfs; mod deprecated; @@ -113,24 +110,27 @@ mod secretstore; mod signer; mod snapshot; mod upgrade; -mod url; mod user_defaults; mod whisper; mod db; -use std::net::{TcpListener}; use std::io::BufReader; use std::fs::File; -use ansi_term::Style; use hash::keccak_buffer; use cli::Args; use configuration::{Cmd, Execute}; use deprecated::find_deprecated; -use ethcore_logger::{Config as LogConfig, setup_log}; +use ethcore_logger::setup_log; +#[cfg(feature = "memory_profiling")] +use std::alloc::System; pub use self::configuration::Configuration; pub use self::run::RunningClient; +#[cfg(feature = "memory_profiling")] +#[global_allocator] +static A: System = System; + fn print_hash_of(maybe_file: Option) -> Result { if let Some(file) = maybe_file { let mut f = BufReader::new(File::open(&file).map_err(|_| "Unable to open file".to_owned())?); @@ -146,6 +146,7 @@ fn run_deadlock_detection_thread() { use std::thread; use std::time::Duration; use parking_lot::deadlock; + use ansi_term::Style; info!("Starting deadlock detection thread."); // Create a background thread which checks for deadlocks every 10s @@ -195,28 +196,6 @@ fn execute(command: Execute, on_client_rq: Cr, on_updater_rq: Rr) -> Res match command.cmd { Cmd::Run(run_cmd) => { - if run_cmd.ui_conf.enabled && !run_cmd.ui_conf.info_page_only { - warn!("{}", Style::new().bold().paint("Parity browser interface is deprecated. It's going to be removed in the next version, use standalone Parity UI instead.")); - warn!("{}", Style::new().bold().paint("Standalone Parity UI: https://github.com/Parity-JS/shell/releases")); - } - - if run_cmd.ui && run_cmd.dapps_conf.enabled { - // Check if Parity is already running - let addr = format!("{}:{}", run_cmd.ui_conf.interface, run_cmd.ui_conf.port); - if !TcpListener::bind(&addr as &str).is_ok() { - return open_ui(&run_cmd.ws_conf, &run_cmd.ui_conf, &run_cmd.logger_config).map(|_| ExecutionAction::Instant(None)); - } - } - - // start ui - if run_cmd.ui { - open_ui(&run_cmd.ws_conf, &run_cmd.ui_conf, &run_cmd.logger_config)?; - } - - if let Some(ref dapp) = run_cmd.dapp { - open_dapp(&run_cmd.dapps_conf, &run_cmd.http_conf, dapp)?; - } - let outcome = run::execute(run_cmd, logger, on_client_rq, on_updater_rq)?; Ok(ExecutionAction::Running(outcome)) }, @@ -225,7 +204,7 @@ fn execute(command: Execute, on_client_rq: Cr, on_updater_rq: Rr) -> Res Cmd::Account(account_cmd) => account::execute(account_cmd).map(|s| ExecutionAction::Instant(Some(s))), Cmd::ImportPresaleWallet(presale_cmd) => presale::execute(presale_cmd).map(|s| ExecutionAction::Instant(Some(s))), Cmd::Blockchain(blockchain_cmd) => blockchain::execute(blockchain_cmd).map(|_| ExecutionAction::Instant(None)), - Cmd::SignerToken(ws_conf, ui_conf, logger_config) => signer::execute(ws_conf, ui_conf, logger_config).map(|s| ExecutionAction::Instant(Some(s))), + Cmd::SignerToken(ws_conf, logger_config) => signer::execute(ws_conf, logger_config).map(|s| ExecutionAction::Instant(Some(s))), Cmd::SignerSign { id, pwfile, port, authfile } => rpc_cli::signer_sign(id, pwfile, port, authfile).map(|s| ExecutionAction::Instant(Some(s))), Cmd::SignerList { port, authfile } => rpc_cli::signer_list(port, authfile).map(|s| ExecutionAction::Instant(Some(s))), Cmd::SignerReject { id, port, authfile } => rpc_cli::signer_reject(id, port, authfile).map(|s| ExecutionAction::Instant(Some(s))), @@ -256,26 +235,3 @@ pub fn start(conf: Configuration, on_client_rq: Cr, on_updater_rq: Rr) - execute(conf.into_command()?, on_client_rq, on_updater_rq) } - -fn open_ui(ws_conf: &rpc::WsConfiguration, ui_conf: &rpc::UiConfiguration, logger_config: &LogConfig) -> Result<(), String> { - if !ui_conf.enabled { - return Err("Cannot use UI command with UI turned off.".into()) - } - - let token = signer::generate_token_and_url(ws_conf, ui_conf, logger_config)?; - // Open a browser - url::open(&token.url).map_err(|e| format!("{}", e))?; - // Print a message - println!("{}", token.message); - Ok(()) -} - -fn open_dapp(dapps_conf: &dapps::Configuration, rpc_conf: &rpc::HttpConfiguration, dapp: &str) -> Result<(), String> { - if !dapps_conf.enabled { - return Err("Cannot use DAPP command with Dapps turned off.".into()) - } - - let url = format!("http://{}:{}/{}/", rpc_conf.interface, rpc_conf.port, dapp); - url::open(&url).map_err(|e| format!("{}", e))?; - Ok(()) -} diff --git a/parity/light_helpers/epoch_fetch.rs b/parity/light_helpers/epoch_fetch.rs index 1b9ae864846fd81239bbffc1ae69d75e6227f858..a7d8f4171fbad3dbf24445a4f7a82ef6284ca639 100644 --- a/parity/light_helpers/epoch_fetch.rs +++ b/parity/light_helpers/epoch_fetch.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/light_helpers/mod.rs b/parity/light_helpers/mod.rs index 5fc9c516b455fdd8d2c67a30767edc1245b5d058..c30b62da55e8aced8a5d453b1c1c21d7151eddd0 100644 --- a/parity/light_helpers/mod.rs +++ b/parity/light_helpers/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/light_helpers/queue_cull.rs b/parity/light_helpers/queue_cull.rs index b6be59e2ce35f3674ef479e2fdea8fa11313759d..03ec2efe74d05974c4bbe0a82e6e546dd3053bff 100644 --- a/parity/light_helpers/queue_cull.rs +++ b/parity/light_helpers/queue_cull.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/main.rs b/parity/main.rs index 06671cbfebfcb263d37c5883b776b6d2851ad9d1..9256373ca03f4c164c279d6e98a8fb3a4490be7f 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -18,53 +18,90 @@ #![warn(missing_docs)] -extern crate parity; - extern crate ctrlc; extern crate dir; extern crate fdlimit; #[macro_use] extern crate log; extern crate panic_hook; +extern crate parity_ethereum; extern crate parking_lot; #[cfg(windows)] extern crate winapi; -use std::{process, env}; -use std::io::{self as stdio, Read, Write}; +use std::ffi::OsString; use std::fs::{remove_file, metadata, File, create_dir_all}; +use std::io::{self as stdio, Read, Write}; use std::path::PathBuf; use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::{process, env}; + use ctrlc::CtrlC; use dir::default_hypervisor_path; use fdlimit::raise_fd_limit; -use parity::{start, ExecutionAction}; +use parity_ethereum::{start, ExecutionAction}; use parking_lot::{Condvar, Mutex}; -fn updates_path(name: &str) -> PathBuf { - let mut dest = PathBuf::from(default_hypervisor_path()); +const PLEASE_RESTART_EXIT_CODE: i32 = 69; +const PARITY_EXECUTABLE_NAME: &str = "parity"; + +#[derive(Debug)] +enum Error { + BinaryNotFound, + ExitCode(i32), + Restart, + Unknown +} + +fn update_path(name: &str) -> PathBuf { + let mut dest = default_hypervisor_path(); dest.push(name); dest } -fn latest_exe_path() -> Option { - File::open(updates_path("latest")).ok() - .and_then(|mut f| { let mut exe = String::new(); f.read_to_string(&mut exe).ok().map(|_| updates_path(&exe)) }) +fn latest_exe_path() -> Result { + File::open(update_path("latest")).and_then(|mut f| { + let mut exe_path = String::new(); + trace!(target: "updater", "latest binary path: {:?}", f); + f.read_to_string(&mut exe_path).map(|_| update_path(&exe_path)) + }) + .or(Err(Error::BinaryNotFound)) } -fn set_spec_name_override(spec_name: String) { +fn latest_binary_is_newer(current_binary: &Option, latest_binary: &Option) -> bool { + match ( + current_binary + .as_ref() + .and_then(|p| metadata(p.as_path()).ok()) + .and_then(|m| m.modified().ok()), + latest_binary + .as_ref() + .and_then(|p| metadata(p.as_path()).ok()) + .and_then(|m| m.modified().ok()) + ) { + (Some(latest_exe_time), Some(this_exe_time)) if latest_exe_time > this_exe_time => true, + _ => false, + } +} + +fn set_spec_name_override(spec_name: &str) { if let Err(e) = create_dir_all(default_hypervisor_path()) - .and_then(|_| File::create(updates_path("spec_name_override")) + .and_then(|_| File::create(update_path("spec_name_override")) .and_then(|mut f| f.write_all(spec_name.as_bytes()))) { - warn!("Couldn't override chain spec: {} at {:?}", e, updates_path("spec_name_override")); + warn!("Couldn't override chain spec: {} at {:?}", e, update_path("spec_name_override")); } } fn take_spec_name_override() -> Option { - let p = updates_path("spec_name_override"); - let r = File::open(p.clone()).ok() - .and_then(|mut f| { let mut spec_name = String::new(); f.read_to_string(&mut spec_name).ok().map(|_| spec_name) }); + let p = update_path("spec_name_override"); + let r = File::open(p.clone()) + .ok() + .and_then(|mut f| { + let mut spec_name = String::new(); + f.read_to_string(&mut spec_name).ok().map(|_| spec_name) + }); let _ = remove_file(p); r } @@ -95,31 +132,56 @@ fn global_init() { #[cfg(not(windows))] fn global_cleanup() {} -// Starts ~/.parity-updates/parity and returns the code it exits with. -fn run_parity() -> Option { +// Starts parity binary installed via `parity-updater` and returns the code it exits with. +fn run_parity() -> Result<(), Error> { global_init(); - use ::std::ffi::OsString; + let prefix = vec![OsString::from("--can-restart"), OsString::from("--force-direct")]; - let res = latest_exe_path().and_then(|exe| process::Command::new(exe) + + let res: Result<(), Error> = latest_exe_path() + .and_then(|exe| process::Command::new(exe) .args(&(env::args_os().skip(1).chain(prefix.into_iter()).collect::>())) .status() - .map(|es| es.code().unwrap_or(128)) .ok() + .map_or(Err(Error::Unknown), |es| { + match es.code() { + // Process success + Some(0) => Ok(()), + // Please restart + Some(PLEASE_RESTART_EXIT_CODE) => Err(Error::Restart), + // Process error code `c` + Some(c) => Err(Error::ExitCode(c)), + // Unknown error, couldn't determine error code + _ => Err(Error::Unknown), + } + }) ); + global_cleanup(); res } -const PLEASE_RESTART_EXIT_CODE: i32 = 69; +#[derive(Debug)] +/// Status used to exit or restart the program. +struct ExitStatus { + /// Whether the program panicked. + panicking: bool, + /// Whether the program should exit. + should_exit: bool, + /// Whether the program should restart. + should_restart: bool, + /// If a restart happens, whether a new chain spec should be used. + spec_name_override: Option, +} -// Run our version of parity. +// Run `locally installed version` of parity (i.e, not installed via `parity-updater`) // Returns the exit error code. fn main_direct(force_can_restart: bool) -> i32 { global_init(); let mut conf = { let args = std::env::args().collect::>(); - parity::Configuration::parse_cli(&args).unwrap_or_else(|e| e.exit()) + parity_ethereum::Configuration::parse_cli(&args).unwrap_or_else(|e| e.exit()) }; if let Some(spec_override) = take_spec_name_override() { @@ -132,14 +194,52 @@ fn main_direct(force_can_restart: bool) -> i32 { // increase max number of open files raise_fd_limit(); - let exit = Arc::new((Mutex::new((false, None)), Condvar::new())); + let exit = Arc::new((Mutex::new(ExitStatus { + panicking: false, + should_exit: false, + should_restart: false, + spec_name_override: None + }), Condvar::new())); + + // Double panic can happen. So when we lock `ExitStatus` after the main thread is notified, it cannot be locked + // again. + let exiting = Arc::new(AtomicBool::new(false)); let exec = if can_restart { - let e1 = exit.clone(); - let e2 = exit.clone(); - start(conf, - move |new_chain: String| { *e1.0.lock() = (true, Some(new_chain)); e1.1.notify_all(); }, - move || { *e2.0.lock() = (true, None); e2.1.notify_all(); }) + start( + conf, + { + let e = exit.clone(); + let exiting = exiting.clone(); + move |new_chain: String| { + if !exiting.swap(true, Ordering::SeqCst) { + *e.0.lock() = ExitStatus { + panicking: false, + should_exit: true, + should_restart: true, + spec_name_override: Some(new_chain), + }; + e.1.notify_all(); + } + } + }, + { + let e = exit.clone(); + let exiting = exiting.clone(); + move || { + if !exiting.swap(true, Ordering::SeqCst) { + *e.0.lock() = ExitStatus { + panicking: false, + should_exit: true, + should_restart: true, + spec_name_override: None, + }; + e.1.notify_all(); + } + } + } + ) + } else { trace!(target: "mode", "Not hypervised: not setting exit handlers."); start(conf, move |_| {}, move || {}) @@ -150,25 +250,57 @@ fn main_direct(force_can_restart: bool) -> i32 { ExecutionAction::Instant(Some(s)) => { println!("{}", s); 0 }, ExecutionAction::Instant(None) => 0, ExecutionAction::Running(client) => { + panic_hook::set_with({ + let e = exit.clone(); + let exiting = exiting.clone(); + move || { + if !exiting.swap(true, Ordering::SeqCst) { + *e.0.lock() = ExitStatus { + panicking: true, + should_exit: true, + should_restart: false, + spec_name_override: None, + }; + e.1.notify_all(); + } + } + }); + CtrlC::set_handler({ let e = exit.clone(); - move || { e.1.notify_all(); } + let exiting = exiting.clone(); + move || { + if !exiting.swap(true, Ordering::SeqCst) { + *e.0.lock() = ExitStatus { + panicking: false, + should_exit: true, + should_restart: false, + spec_name_override: None, + }; + e.1.notify_all(); + } + } }); // Wait for signal let mut lock = exit.0.lock(); - let _ = exit.1.wait(&mut lock); + if !lock.should_exit { + let _ = exit.1.wait(&mut lock); + } client.shutdown(); - match &*lock { - &(true, ref spec_name_override) => { - if let &Some(ref spec_name) = spec_name_override { - set_spec_name_override(spec_name.clone()); - } - PLEASE_RESTART_EXIT_CODE - }, - _ => 0, + if lock.should_restart { + if let Some(ref spec_name) = lock.spec_name_override { + set_spec_name_override(&spec_name.clone()); + } + PLEASE_RESTART_EXIT_CODE + } else { + if lock.panicking { + 1 + } else { + 0 + } } }, }, @@ -195,48 +327,82 @@ macro_rules! trace_main { } fn main() { - panic_hook::set(); + panic_hook::set_abort(); - // assuming the user is not running with `--force-direct`, then: - // if argv[0] == "parity" and this executable != ~/.parity-updates/parity, run that instead. + // the user has specified to run its originally installed binary (not via `parity-updater`) let force_direct = std::env::args().any(|arg| arg == "--force-direct"); - let exe = std::env::current_exe().ok(); - let development = exe.as_ref().and_then(|p| p.parent().and_then(|p| p.parent()).and_then(|p| p.file_name()).map(|n| n == "target")).unwrap_or(false); - let same_name = exe.as_ref().map(|p| p.file_stem().map_or(false, |s| s == "parity") && p.extension().map_or(true, |x| x == "exe")).unwrap_or(false); - trace_main!("Starting up {} (force-direct: {}, development: {}, same-name: {})", std::env::current_exe().map(|x| format!("{}", x.display())).unwrap_or("".to_owned()), force_direct, development, same_name); + + // absolute path to the current `binary` + let exe_path = std::env::current_exe().ok(); + + // the binary is named `target/xx/yy` + let development = exe_path + .as_ref() + .and_then(|p| { + p.parent() + .and_then(|p| p.parent()) + .and_then(|p| p.file_name()) + .map(|n| n == "target") + }) + .unwrap_or(false); + + // the binary is named `parity` + let same_name = exe_path + .as_ref() + .map_or(false, |p| { + p.file_stem().map_or(false, |n| n == PARITY_EXECUTABLE_NAME) + }); + + trace_main!("Starting up {} (force-direct: {}, development: {}, same-name: {})", + std::env::current_exe().ok().map_or_else(|| "".into(), |x| format!("{}", x.display())), + force_direct, + development, + same_name); + if !force_direct && !development && same_name { - // looks like we're not running ~/.parity-updates/parity when the user is expecting otherwise. + // Try to run the latest installed version of `parity`, + // Upon failure it falls back to the locally installed version of `parity` // Everything run inside a loop, so we'll be able to restart from the child into a new version seamlessly. loop { - // If we fail to run the updated parity then fallback to local version. - let latest_exe = latest_exe_path(); + // `Path` to the latest downloaded binary + let latest_exe = latest_exe_path().ok(); + + // `Latest´ binary exist let have_update = latest_exe.as_ref().map_or(false, |p| p.exists()); - let is_non_updated_current = exe.as_ref().map_or(false, |exe| latest_exe.as_ref().map_or(false, |lexe| exe.canonicalize().ok() != lexe.canonicalize().ok())); - let update_is_newer = match ( - latest_exe.as_ref() - .and_then(|p| metadata(p.as_path()).ok()) - .and_then(|m| m.modified().ok()), - exe.as_ref() - .and_then(|p| metadata(p.as_path()).ok()) - .and_then(|m| m.modified().ok()) - ) { - (Some(latest_exe_time), Some(this_exe_time)) if latest_exe_time > this_exe_time => true, - _ => false, - }; - trace_main!("Starting... (have-update: {}, non-updated-current: {}, update-is-newer: {})", have_update, is_non_updated_current, update_is_newer); - let exit_code = if have_update && is_non_updated_current && update_is_newer { - trace_main!("Attempting to run latest update ({})...", latest_exe.as_ref().expect("guarded by have_update; latest_exe must exist for have_update; qed").display()); - run_parity().unwrap_or_else(|| { trace_main!("Falling back to local..."); main_direct(true) }) + + // Canonicalized path to the current binary is not the same as to latest binary + let canonicalized_path_not_same = exe_path + .as_ref() + .map_or(false, |exe| latest_exe.as_ref() + .map_or(false, |lexe| exe.canonicalize().ok() != lexe.canonicalize().ok())); + + // Downloaded `binary` is newer + let update_is_newer = latest_binary_is_newer(&latest_exe, &exe_path); + trace_main!("Starting... (have-update: {}, non-updated-current: {}, update-is-newer: {})", have_update, canonicalized_path_not_same, update_is_newer); + + let exit_code = if have_update && canonicalized_path_not_same && update_is_newer { + trace_main!("Attempting to run latest update ({})...", + latest_exe.as_ref().expect("guarded by have_update; latest_exe must exist for have_update; qed").display()); + match run_parity() { + Ok(_) => 0, + // Restart parity + Err(Error::Restart) => PLEASE_RESTART_EXIT_CODE, + // Fall back to local version + Err(e) => { + error!(target: "updater", "Updated binary could not be executed error: {:?}. Falling back to local version", e); + main_direct(true) + } + } } else { trace_main!("No latest update. Attempting to direct..."); main_direct(true) }; - trace_main!("Latest exited with {}", exit_code); + trace_main!("Latest binary exited with exit code: {}", exit_code); if exit_code != PLEASE_RESTART_EXIT_CODE { trace_main!("Quitting..."); process::exit(exit_code); } - trace_main!("Rerunning..."); + trace!(target: "updater", "Re-running updater loop"); } } else { trace_main!("Running direct"); diff --git a/parity/modules.rs b/parity/modules.rs index cf46149b8e8ad6efacf44ac19e9082e2ac29a00c..e12e8ee458351c48398b5284aaa53fedd1c5524d 100644 --- a/parity/modules.rs +++ b/parity/modules.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/params.rs b/parity/params.rs index 957b280193581bc69c9bdacea866ce3725b67f17..2d1514a02d46976679824ee4faec4b1ccd9e7ad5 100644 --- a/parity/params.rs +++ b/parity/params.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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; @@ -33,6 +34,7 @@ pub enum SpecType { Foundation, Morden, Ropsten, + Tobalaba, Kovan, Olympic, Classic, @@ -61,6 +63,7 @@ impl str::FromStr for SpecType { "morden" | "classic-testnet" => SpecType::Morden, "ropsten" => SpecType::Ropsten, "kovan" | "testnet" => SpecType::Kovan, + "tobalaba" => SpecType::Tobalaba, "olympic" => SpecType::Olympic, "expanse" => SpecType::Expanse, "musicoin" => SpecType::Musicoin, @@ -88,6 +91,7 @@ impl fmt::Display for SpecType { SpecType::Easthub => "easthub", SpecType::Social => "social", SpecType::Kovan => "kovan", + SpecType::Tobalaba => "tobalaba", SpecType::Dev => "dev", SpecType::Custom(ref custom) => custom, }) @@ -108,6 +112,7 @@ impl SpecType { SpecType::Ellaism => Ok(ethereum::new_ellaism(params)), SpecType::Easthub => Ok(ethereum::new_easthub(params)), SpecType::Social => Ok(ethereum::new_social(params)), + SpecType::Tobalaba => Ok(ethereum::new_tobalaba(params)), SpecType::Kovan => Ok(ethereum::new_kovan(params)), SpecType::Dev => Ok(Spec::new_instant()), SpecType::Custom(ref filename) => { @@ -244,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, + ) ) } } @@ -327,7 +334,7 @@ pub fn fatdb_switch_to_bool(switch: Switch, user_defaults: &UserDefaults, _algor } pub fn mode_switch_to_bool(switch: Option, user_defaults: &UserDefaults) -> Result { - Ok(switch.unwrap_or(user_defaults.mode.clone())) + Ok(switch.unwrap_or(user_defaults.mode().clone())) } #[cfg(test)] diff --git a/parity/presale.rs b/parity/presale.rs index 216ff66a848b5b8185f9ba48853bfbe34ccb61dd..16af2fb82318d2c736084f7bd06db9a9f93aab00 100644 --- a/parity/presale.rs +++ b/parity/presale.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -30,7 +30,7 @@ pub struct ImportWallet { } pub fn execute(cmd: ImportWallet) -> Result { - let password: String = match cmd.password_file { + let password = match cmd.password_file { Some(file) => password_from_file(file)?, None => password_prompt()?, }; diff --git a/parity/rpc.rs b/parity/rpc.rs index 21bc9a409696995681b820420288fd6e69e76702..eb769eda08722dadeaa2f83fc93b4dda22dc9063 100644 --- a/parity/rpc.rs +++ b/parity/rpc.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -19,7 +19,6 @@ use std::sync::Arc; use std::path::PathBuf; use std::collections::HashSet; -use dapps; use dir::default_data_path; use dir::helpers::replace_home; use helpers::parity_ipc_path; @@ -45,12 +44,7 @@ pub struct HttpConfiguration { pub hosts: Option>, pub server_threads: usize, pub processing_threads: usize, -} - -impl HttpConfiguration { - pub fn address(&self) -> Option { - address(self.enabled, &self.interface, self.port, &self.hosts) - } + pub max_payload: usize, } impl Default for HttpConfiguration { @@ -64,58 +58,7 @@ impl Default for HttpConfiguration { hosts: Some(vec![]), server_threads: 1, processing_threads: 4, - } - } -} - -#[derive(Debug, PartialEq, Clone)] -pub struct UiConfiguration { - pub enabled: bool, - pub interface: String, - pub port: u16, - pub hosts: Option>, - pub info_page_only: bool, -} - -impl UiConfiguration { - pub fn address(&self) -> Option { - address(self.enabled, &self.interface, self.port, &self.hosts) - } - - pub fn redirection_address(&self) -> Option<(String, u16)> { - self.address().map(|host| { - let mut it = host.split(':'); - let hostname: Option = it.next().map(|s| s.to_owned()); - let port: Option = it.next().and_then(|s| s.parse().ok()); - - (hostname.unwrap_or_else(|| "localhost".into()), port.unwrap_or(8180)) - }) - } -} - -impl From for HttpConfiguration { - fn from(conf: UiConfiguration) -> Self { - HttpConfiguration { - enabled: conf.enabled, - interface: conf.interface, - port: conf.port, - apis: rpc_apis::ApiSet::UnsafeContext, - cors: Some(vec![]), - hosts: conf.hosts, - server_threads: 1, - processing_threads: 0, - } - } -} - -impl Default for UiConfiguration { - fn default() -> Self { - UiConfiguration { - enabled: cfg!(feature = "ui-enabled"), - port: 8180, - interface: "127.0.0.1".into(), - hosts: Some(vec![]), - info_page_only: true, + max_payload: 5, } } } @@ -153,8 +96,6 @@ pub struct WsConfiguration { pub hosts: Option>, pub signer_path: PathBuf, pub support_token_api: bool, - pub ui_address: Option, - pub dapps_address: Option, } impl Default for WsConfiguration { @@ -170,8 +111,6 @@ impl Default for WsConfiguration { hosts: Some(Vec::new()), signer_path: replace_home(&data_dir, "$BASE/signer").into(), support_token_api: true, - ui_address: Some("127.0.0.1:8180".into()), - dapps_address: Some("127.0.0.1:8545".into()), } } } @@ -212,7 +151,6 @@ pub fn new_ws( let url = format!("{}:{}", conf.interface, conf.port); let addr = url.parse().map_err(|_| format!("Invalid WebSockets listen host/port given: {}", url))?; - let full_handler = setup_apis(rpc_apis::ApiSet::SafeContext, deps); let handler = { let mut handler = MetaIoHandler::with_middleware(( @@ -226,9 +164,8 @@ pub fn new_ws( }; let remote = deps.remote.clone(); - let ui_address = conf.ui_address.clone(); - let allowed_origins = into_domains(with_domain(conf.origins, domain, &ui_address, &conf.dapps_address)); - let allowed_hosts = into_domains(with_domain(conf.hosts, domain, &Some(url.clone().into()), &None)); + let allowed_origins = into_domains(with_domain(conf.origins, domain, &None)); + let allowed_hosts = into_domains(with_domain(conf.hosts, domain, &Some(url.clone().into()))); let signer_path; let path = match conf.support_token_api { @@ -264,7 +201,6 @@ pub fn new_http( options: &str, conf: HttpConfiguration, deps: &Dependencies, - middleware: Option, ) -> Result, String> { if !conf.enabled { return Ok(None); @@ -277,7 +213,7 @@ pub fn new_http( let remote = deps.remote.clone(); let cors_domains = into_domains(conf.cors); - let allowed_hosts = into_domains(with_domain(conf.hosts, domain, &Some(url.clone().into()), &None)); + let allowed_hosts = into_domains(with_domain(conf.hosts, domain, &Some(url.clone().into()))); let start_result = rpc::start_http( &addr, @@ -286,8 +222,8 @@ pub fn new_http( handler, remote, rpc::RpcExtractor, - middleware, conf.server_threads, + conf.max_payload, ); match start_result { @@ -329,7 +265,7 @@ fn into_domains>(items: Option>) -> DomainsValidatio items.map(|vals| vals.into_iter().map(T::from).collect()).into() } -fn with_domain(items: Option>, domain: &str, ui_address: &Option, dapps_address: &Option) -> Option> { +fn with_domain(items: Option>, domain: &str, dapps_address: &Option) -> Option> { fn extract_port(s: &str) -> Option { s.split(':').nth(1).and_then(|s| s.parse().ok()) } @@ -348,7 +284,6 @@ fn with_domain(items: Option>, domain: &str, ui_address: &Option, pub net_service: Arc, pub updater: Arc, - pub health: NodeHealth, pub geth_compatibility: bool, - pub dapps_service: Option>, - pub dapps_address: Option, pub ws_address: Option, pub fetch: FetchClient, pub pool: CpuPool, pub remote: parity_reactor::Remote, pub whisper_rpc: Option<::whisper::RpcFactory>, pub gas_price_percentile: usize, + pub poll_lifetime: u32, } impl FullDependencies { @@ -288,12 +284,13 @@ impl FullDependencies { allow_pending_receipt_query: !self.geth_compatibility, send_block_number_in_get_work: !self.geth_compatibility, gas_price_percentile: self.gas_price_percentile, + poll_lifetime: self.poll_lifetime } ); handler.extend_with(client.to_delegate()); if !for_generic_pubsub { - let filter_client = EthFilterClient::new(self.client.clone(), self.miner.clone()); + let filter_client = EthFilterClient::new(self.client.clone(), self.miner.clone(), self.poll_lifetime); handler.extend_with(filter_client.to_delegate()); add_signing_methods!(EthSigning, handler, self, nonces.clone()); @@ -304,7 +301,7 @@ impl FullDependencies { let client = EthPubSubClient::new(self.client.clone(), self.remote.clone()); let h = client.handler(); self.miner.add_transactions_listener(Box::new(move |hashes| if let Some(h) = h.upgrade() { - h.new_transactions(hashes); + h.notify_new_transactions(hashes); })); if let Some(h) = client.handler().upgrade() { @@ -330,12 +327,10 @@ impl FullDependencies { self.sync.clone(), self.updater.clone(), self.net_service.clone(), - self.health.clone(), self.secret_store.clone(), self.logger.clone(), self.settings.clone(), signer, - self.dapps_address.clone(), self.ws_address.clone(), ).to_delegate()); @@ -360,7 +355,6 @@ impl FullDependencies { &self.miner, &self.updater, &self.net_service, - self.dapps_service.clone(), self.fetch.clone(), self.pool.clone(), ).to_delegate()) @@ -433,12 +427,9 @@ pub struct LightDependencies { pub secret_store: Arc, pub logger: Arc, pub settings: Arc, - pub health: NodeHealth, pub on_demand: Arc<::light::on_demand::OnDemand>, pub cache: Arc>, pub transaction_queue: Arc>, - pub dapps_service: Option>, - pub dapps_address: Option, pub ws_address: Option, pub fetch: FetchClient, pub pool: CpuPool, @@ -447,6 +438,7 @@ pub struct LightDependencies { pub whisper_rpc: Option<::whisper::RpcFactory>, pub private_tx_service: Option>, pub gas_price_percentile: usize, + pub poll_lifetime: u32, } impl LightDependencies { @@ -504,6 +496,7 @@ impl LightDependencies { self.secret_store.clone(), self.cache.clone(), self.gas_price_percentile, + self.poll_lifetime, ); handler.extend_with(Eth::to_delegate(client.clone())); @@ -525,7 +518,7 @@ impl LightDependencies { let h = client.handler(); self.transaction_queue.write().add_listener(Box::new(move |transactions| { if let Some(h) = h.upgrade() { - h.new_transactions(transactions); + h.notify_new_transactions(transactions); } })); handler.extend_with(EthPubSub::to_delegate(client)); @@ -547,9 +540,7 @@ impl LightDependencies { self.secret_store.clone(), self.logger.clone(), self.settings.clone(), - self.health.clone(), signer, - self.dapps_address.clone(), self.ws_address.clone(), self.gas_price_percentile, ).to_delegate()); @@ -572,7 +563,6 @@ impl LightDependencies { Api::ParitySet => { handler.extend_with(light::ParitySetClient::new( self.sync.clone(), - self.dapps_service.clone(), self.fetch.clone(), self.pool.clone(), ).to_delegate()) diff --git a/parity/run.rs b/parity/run.rs index bd8d4fb4a835a41222c276d404034d062486cc9b..f9ff961111239dfac3ef8db10e0f8babf16386f1 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -15,14 +15,14 @@ // along with Parity. If not, see . use std::any::Any; -use std::fmt; use std::sync::{Arc, Weak}; use std::time::{Duration, Instant}; use std::thread; use ansi_term::Colour; +use bytes::Bytes; use ethcore::account_provider::{AccountProvider, AccountProviderSettings}; -use ethcore::client::{Client, Mode, DatabaseCompactionProfile, VMType, BlockChainClient, BlockInfo}; +use ethcore::client::{BlockId, CallContract, Client, Mode, DatabaseCompactionProfile, VMType, BlockChainClient, BlockInfo}; use ethcore::ethstore::ethkey; use ethcore::miner::{stratum, Miner, MinerService, MinerOptions}; use ethcore::snapshot; @@ -30,8 +30,10 @@ use ethcore::spec::{SpecParams, OptimizeFor}; use ethcore::verification::queue::VerifierSettings; use ethcore_logger::{Config as LogConfig, RotatingLogger}; use ethcore_service::ClientService; +use ethereum_types::Address; use sync::{self, SyncConfig}; use miner::work_notify::WorkPoster; +use futures::IntoFuture; use futures_cpupool::CpuPool; use hash_fetch::{self, fetch}; use informant::{Informant, LightNodeInformantData, FullNodeInformantData}; @@ -39,7 +41,6 @@ use journaldb::Algorithm; use light::Cache as LightDataCache; use miner::external::ExternalMiner; use node_filter::NodeFilter; -use node_health; use parity_reactor::EventLoop; use parity_rpc::{Origin, Metadata, NetworkSettings, informant, is_major_importing}; use updater::{UpdatePolicy, Updater}; @@ -54,15 +55,16 @@ use upgrade::upgrade_key_location; use dir::{Directories, DatabaseDirectories}; use cache::CacheConfig; use user_defaults::UserDefaults; -use dapps; use ipfs; use jsonrpc_core; use modules; +use registrar::{RegistrarClient, Asynchronous}; use rpc; use rpc_apis; use secretstore; use signer; use db; +use ethkey::Password; // how often to take periodic snapshots. const SNAPSHOT_PERIOD: u64 = 5000; @@ -90,7 +92,7 @@ pub struct RunCmd { pub logger_config: LogConfig, pub miner_options: MinerOptions, pub gas_price_percentile: usize, - pub ntp_servers: Vec, + pub poll_lifetime: u32, pub ws_conf: rpc::WsConfiguration, pub http_conf: rpc::HttpConfiguration, pub ipc_conf: rpc::IpcConfiguration, @@ -106,19 +108,14 @@ pub struct RunCmd { pub tracing: Switch, pub fat_db: Switch, pub compaction: DatabaseCompactionProfile, - pub wal: bool, pub vm_type: VMType, pub geth_compatibility: bool, pub net_settings: NetworkSettings, - pub dapps_conf: dapps::Configuration, pub ipfs_conf: ipfs::Configuration, - pub ui_conf: rpc::UiConfiguration, pub secretstore_conf: secretstore::Configuration, pub private_provider_conf: ProviderConfig, pub private_encryptor_conf: EncryptorConfig, pub private_tx_enabled: bool, - pub dapp: Option, - pub ui: bool, pub name: String, pub custom_bootnodes: bool, pub stratum: Option, @@ -185,10 +182,10 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc) -> Result) -> Result) -> Result); - impl fmt::Debug for LightSyncStatus { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "Light Sync Status") - } - } - impl node_health::SyncStatus for LightSyncStatus { - fn is_major_importing(&self) -> bool { self.0.is_major_importing() } - fn peers(&self) -> (usize, usize) { - let peers = sync::LightSyncProvider::peer_numbers(&*self.0); - (peers.connected, peers.max) - } - } - - let sync_status = Arc::new(LightSyncStatus(light_sync.clone())); - let node_health = node_health::NodeHealth::new( - sync_status.clone(), - node_health::TimeChecker::new(&cmd.ntp_servers, cpu_pool.clone()), - event_loop.remote(), - ); - - (node_health.clone(), dapps::Dependencies { - sync_status, - node_health, - contract_client: Arc::new(contract_client), - fetch: fetch.clone(), - pool: cpu_pool.clone(), - signer: signer_service.clone(), - ui_address: cmd.ui_conf.redirection_address(), - info_page_only: cmd.ui_conf.info_page_only, - }) - }; - - let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps.clone())?; - let ui_middleware = dapps::new_ui(cmd.ui_conf.enabled, dapps_deps)?; // start RPCs - let dapps_service = dapps::service(&dapps_middleware); let deps_for_rpc_apis = Arc::new(rpc_apis::LightDependencies { signer_service: signer_service, client: client.clone(), sync: light_sync.clone(), net: light_sync.clone(), - health: node_health, secret_store: account_provider, logger: logger, settings: Arc::new(cmd.net_settings), on_demand: on_demand, cache: cache.clone(), transaction_queue: txq, - dapps_service: dapps_service, - dapps_address: cmd.dapps_conf.address(cmd.http_conf.address()), ws_address: cmd.ws_conf.address(), fetch: fetch, pool: cpu_pool.clone(), @@ -355,6 +305,7 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc) -> Result) -> Result) -> Result(cmd: RunCmd, logger: Arc, on_client_rq: execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?; // create dirs used by parity - cmd.dirs.create_dirs(cmd.dapps_conf.enabled, cmd.ui_conf.enabled, cmd.secretstore_conf.enabled)?; + cmd.dirs.create_dirs(cmd.acc_conf.unlocked_accounts.len() == 0, cmd.secretstore_conf.enabled)?; // run in daemon mode if let Some(pid_file) = cmd.daemon { @@ -452,7 +402,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: } //print out running parity environment - print_running_environment(&spec.name, &cmd.dirs, &db_dirs, &cmd.dapps_conf); + print_running_environment(&spec.name, &cmd.dirs, &db_dirs); // display info about used pruning algorithm info!("State DB configuration: {}{}{}", @@ -521,25 +471,29 @@ 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, cmd.gas_pricer_conf.to_gas_pricer(fetch.clone(), cpu_pool.clone()), &spec, - Some(account_provider.clone()) + Some(account_provider.clone()), + )); 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()) )); } + let engine_signer = cmd.miner_extras.engine_signer; if engine_signer != Default::default() { // Check if engine signer exists - if !account_provider.has_account(engine_signer).unwrap_or(false) { + if !account_provider.has_account(engine_signer) { return Err(format!("Consensus signer account not found for the current chain. {}", build_create_account_hint(&cmd.spec, &cmd.dirs.keys))); } @@ -567,7 +521,6 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: tracing, fat_db, cmd.compaction, - cmd.wal, cmd.vm_type, cmd.name, algorithm, @@ -577,6 +530,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; @@ -587,8 +541,9 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: // set network path. net_conf.net_config_path = Some(db_dirs.network_path().to_string_lossy().into_owned()); - let client_db = db::open_client_db(&client_path, &client_config)?; let restoration_db_handler = db::restoration_db_handler(&client_path, &client_config); + let client_db = restoration_db_handler.open(&client_path) + .map_err(|e| format!("Failed to open database {:?}", e))?; // create client service. let service = ClientService::start( @@ -629,7 +584,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: } }; - let store = ::local_store::create(db, ::ethcore::db::COL_NODE_INFO, node_info); + let store = ::local_store::create(db.key_value().clone(), ::ethcore::db::COL_NODE_INFO, node_info); if cmd.no_persistent_txqueue { info!("Running without a persistent transaction queue."); @@ -706,13 +661,27 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: chain_notify.start(); } - let contract_client = Arc::new(::dapps::FullRegistrar::new(client.clone())); + let contract_client = { + struct FullRegistrar { client: Arc } + impl RegistrarClient for FullRegistrar { + type Call = Asynchronous; + fn registrar_address(&self) -> Result { + self.client.registrar_address() + .ok_or_else(|| "Registrar not defined.".into()) + } + fn call_contract(&self, address: Address, data: Bytes) -> Self::Call { + Box::new(self.client.call_contract(BlockId::Latest, address, data).into_future()) + } + } + + Arc::new(FullRegistrar { client: client.clone() }) + }; // the updater service let updater_fetch = fetch.clone(); let updater = Updater::new( - Arc::downgrade(&(service.client() as Arc)), - Arc::downgrade(&sync_provider), + &Arc::downgrade(&(service.client() as Arc)), + &Arc::downgrade(&sync_provider), update_policy, hash_fetch::Client::with_fetch(contract_client.clone(), cpu_pool.clone(), updater_fetch, event_loop.remote()) ); @@ -723,53 +692,11 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: let secret_store = account_provider.clone(); let signer_service = Arc::new(signer::new_service(&cmd.ws_conf, &cmd.logger_config)); - // the dapps server - let (node_health, dapps_deps) = { - let (sync, client) = (sync_provider.clone(), client.clone()); - - struct SyncStatus(Arc, Arc, sync::NetworkConfiguration); - impl fmt::Debug for SyncStatus { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "Dapps Sync Status") - } - } - impl node_health::SyncStatus for SyncStatus { - fn is_major_importing(&self) -> bool { - is_major_importing(Some(self.0.status().state), self.1.queue_info()) - } - fn peers(&self) -> (usize, usize) { - let status = self.0.status(); - (status.num_peers, status.current_max_peers(self.2.min_peers, self.2.max_peers) as usize) - } - } - - let sync_status = Arc::new(SyncStatus(sync, client, net_conf)); - let node_health = node_health::NodeHealth::new( - sync_status.clone(), - node_health::TimeChecker::new(&cmd.ntp_servers, cpu_pool.clone()), - event_loop.remote(), - ); - (node_health.clone(), dapps::Dependencies { - sync_status, - node_health, - contract_client, - fetch: fetch.clone(), - pool: cpu_pool.clone(), - signer: signer_service.clone(), - ui_address: cmd.ui_conf.redirection_address(), - info_page_only: cmd.ui_conf.info_page_only, - }) - }; - let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps.clone())?; - let ui_middleware = dapps::new_ui(cmd.ui_conf.enabled, dapps_deps)?; - - let dapps_service = dapps::service(&dapps_middleware); let deps_for_rpc_apis = Arc::new(rpc_apis::FullDependencies { signer_service: signer_service, snapshot: snapshot_service.clone(), client: client.clone(), sync: sync_provider.clone(), - health: node_health, net: manage_network.clone(), secret_store: secret_store, miner: miner.clone(), @@ -779,8 +706,6 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: net_service: manage_network.clone(), updater: updater.clone(), geth_compatibility: cmd.geth_compatibility, - dapps_service: dapps_service, - dapps_address: cmd.dapps_conf.address(cmd.http_conf.address()), ws_address: cmd.ws_conf.address(), fetch: fetch.clone(), pool: cpu_pool.clone(), @@ -788,6 +713,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: whisper_rpc: whisper_factory, private_tx_service: Some(private_tx_service.clone()), gas_price_percentile: cmd.gas_price_percentile, + poll_lifetime: cmd.poll_lifetime, }); let dependencies = rpc::Dependencies { @@ -806,9 +732,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: let rpc_direct = rpc::setup_apis(rpc_apis::ApiSet::All, &dependencies); let ws_server = rpc::new_ws(cmd.ws_conf.clone(), &dependencies)?; let ipc_server = rpc::new_ipc(cmd.ipc_conf, &dependencies)?; - let http_server = rpc::new_http("HTTP JSON-RPC", "jsonrpc", cmd.http_conf.clone(), &dependencies, dapps_middleware)?; - // the ui server - let ui_server = rpc::new_http("UI WALLET", "ui", cmd.ui_conf.clone().into(), &dependencies, ui_middleware)?; + let http_server = rpc::new_http("HTTP JSON-RPC", "jsonrpc", cmd.http_conf.clone(), &dependencies)?; // secret store key server let secretstore_deps = secretstore::Dependencies { @@ -842,13 +766,13 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: user_defaults.pruning = algorithm; user_defaults.tracing = tracing; user_defaults.fat_db = fat_db; - user_defaults.mode = mode; + user_defaults.set_mode(mode); user_defaults.save(&user_defaults_path)?; // tell client how to save the default mode if it gets changed. client.on_user_defaults_change(move |mode: Option| { if let Some(mode) = mode { - user_defaults.mode = mode; + user_defaults.set_mode(mode); } let _ = user_defaults.save(&user_defaults_path); // discard failures - there's nothing we can do }); @@ -881,7 +805,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: informant, client, client_service: Arc::new(service), - keep_alive: Box::new((watcher, updater, ws_server, http_server, ipc_server, ui_server, secretstore_key_server, ipfs_server, event_loop)), + keep_alive: Box::new((watcher, updater, ws_server, http_server, ipc_server, secretstore_key_server, ipfs_server, event_loop)), } }) } @@ -1002,14 +926,13 @@ fn daemonize(_pid_file: String) -> Result<(), String> { Err("daemon is no supported on windows".into()) } -fn print_running_environment(spec_name: &String, dirs: &Directories, db_dirs: &DatabaseDirectories, dapps_conf: &dapps::Configuration) { +fn print_running_environment(spec_name: &String, dirs: &Directories, db_dirs: &DatabaseDirectories) { info!("Starting {}", Colour::White.bold().paint(version())); info!("Keys path {}", Colour::White.bold().paint(dirs.keys_path(spec_name).to_string_lossy().into_owned())); info!("DB path {}", Colour::White.bold().paint(db_dirs.db_root_path().to_string_lossy().into_owned())); - info!("Path to dapps {}", Colour::White.bold().paint(dapps_conf.dapps_path.to_string_lossy().into_owned())); } -fn prepare_account_provider(spec: &SpecType, dirs: &Directories, data_dir: &str, cfg: AccountsConfig, passwords: &[String]) -> Result { +fn prepare_account_provider(spec: &SpecType, dirs: &Directories, data_dir: &str, cfg: AccountsConfig, passwords: &[Password]) -> Result { use ethcore::ethstore::EthStore; use ethcore::ethstore::accounts_dir::RootDiskDirectory; @@ -1039,7 +962,7 @@ fn prepare_account_provider(spec: &SpecType, dirs: &Directories, data_dir: &str, for a in cfg.unlocked_accounts { // Check if the account exists - if !account_provider.has_account(a).unwrap_or(false) { + if !account_provider.has_account(a) { return Err(format!("Account {} not found for the current chain. {}", a, build_create_account_hint(spec, &dirs.keys))); } @@ -1064,8 +987,8 @@ fn prepare_account_provider(spec: &SpecType, dirs: &Directories, data_dir: &str, fn insert_dev_account(account_provider: &AccountProvider) { let secret: ethkey::Secret = "4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7".into(); let dev_account = ethkey::KeyPair::from_secret(secret.clone()).expect("Valid secret produces valid key;qed"); - if let Ok(false) = account_provider.has_account(dev_account.address()) { - match account_provider.insert_account(secret, "") { + if !account_provider.has_account(dev_account.address()) { + match account_provider.insert_account(secret, &Password::from(String::new())) { Err(e) => warn!("Unable to add development account: {}", e), Ok(address) => { let _ = account_provider.set_account_name(address.clone(), "Development Account".into()); diff --git a/parity/secretstore.rs b/parity/secretstore.rs index 168a9b3fcf19688918cc757def4ddafa0bfa2841..1e322e3ba86030a7125c6374b60c5a948785f7b2 100644 --- a/parity/secretstore.rs +++ b/parity/secretstore.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -50,10 +50,10 @@ pub struct Configuration { pub enabled: bool, /// Is HTTP API enabled? pub http_enabled: bool, - /// Is ACL check enabled. - pub acl_check_enabled: bool, /// Is auto migrate enabled. pub auto_migrate_enabled: bool, + /// ACL check contract address. + pub acl_check_contract_address: Option, /// Service contract address. pub service_contract_address: Option, /// Server key generation service contract address. @@ -68,6 +68,8 @@ pub struct Configuration { pub self_secret: Option, /// Other nodes IDs + addresses. pub nodes: BTreeMap, + /// Key Server Set contract address. If None, 'nodes' map is used. + pub key_server_set_contract_address: Option, /// Interface to listen to pub interface: String, /// Port to listen to @@ -93,7 +95,7 @@ pub struct Dependencies<'a> { /// Account provider. pub account_provider: Arc, /// Passed accounts passwords. - pub accounts_passwords: &'a [String], + pub accounts_passwords: &'a [Password], } #[cfg(not(feature = "secretstore"))] @@ -111,12 +113,12 @@ mod server { } } -#[cfg(feature="secretstore")] +#[cfg(feature = "secretstore")] mod server { use std::sync::Arc; use ethcore_secretstore; use ethkey::KeyPair; - use ansi_term::Colour::Red; + use ansi_term::Colour::{Red, White}; use db; use super::{Configuration, Dependencies, NodeSecretKey, ContractAddress}; @@ -135,16 +137,12 @@ mod server { impl KeyServer { /// Create new key server pub fn new(mut conf: Configuration, deps: Dependencies) -> Result { - if !conf.acl_check_enabled { - warn!("Running SecretStore with disabled ACL check: {}", Red.bold().paint("everyone has access to stored keys")); - } - let self_secret: Arc = match conf.self_secret.take() { Some(NodeSecretKey::Plain(secret)) => Arc::new(ethcore_secretstore::PlainNodeKeyPair::new( KeyPair::from_secret(secret).map_err(|e| format!("invalid secret: {}", e))?)), Some(NodeSecretKey::KeyStore(account)) => { // Check if account exists - if !deps.account_provider.has_account(account.clone()).unwrap_or(false) { + if !deps.account_provider.has_account(account.clone()) { return Err(format!("Account {} passed as secret store node key is not found", account)); } @@ -163,6 +161,11 @@ mod server { None => return Err("self secret is required when using secretstore".into()), }; + info!("Starting SecretStore node: {}", White.bold().paint(format!("{:?}", self_secret.public()))); + if conf.acl_check_contract_address.is_none() { + warn!("Running SecretStore with disabled ACL check: {}", Red.bold().paint("everyone has access to stored keys")); + } + let key_server_name = format!("{}:{}", conf.interface, conf.port); let mut cconf = ethcore_secretstore::ServiceConfiguration { listener_address: if conf.http_enabled { Some(ethcore_secretstore::NodeAddress { @@ -174,7 +177,7 @@ mod server { service_contract_srv_retr_address: conf.service_contract_srv_retr_address.map(into_service_contract_address), service_contract_doc_store_address: conf.service_contract_doc_store_address.map(into_service_contract_address), service_contract_doc_sretr_address: conf.service_contract_doc_sretr_address.map(into_service_contract_address), - acl_check_enabled: conf.acl_check_enabled, + acl_check_contract_address: conf.acl_check_contract_address.map(into_service_contract_address), cluster_config: ethcore_secretstore::ClusterConfiguration { threads: 4, listener_address: ethcore_secretstore::NodeAddress { @@ -185,6 +188,7 @@ mod server { address: ip, port: port, })).collect(), + key_server_set_contract_address: conf.key_server_set_contract_address.map(into_service_contract_address), allow_connecting_to_higher_nodes: true, admin_public: conf.admin_public, auto_migrate_enabled: conf.auto_migrate_enabled, @@ -205,6 +209,7 @@ mod server { } pub use self::server::KeyServer; +use ethkey::Password; impl Default for Configuration { fn default() -> Self { @@ -212,8 +217,8 @@ impl Default for Configuration { Configuration { enabled: true, http_enabled: true, - acl_check_enabled: true, auto_migrate_enabled: true, + acl_check_contract_address: Some(ContractAddress::Registry), service_contract_address: None, service_contract_srv_gen_address: None, service_contract_srv_retr_address: None, @@ -222,6 +227,7 @@ impl Default for Configuration { self_secret: None, admin_public: None, nodes: BTreeMap::new(), + key_server_set_contract_address: Some(ContractAddress::Registry), interface: "127.0.0.1".to_owned(), port: 8083, http_interface: "127.0.0.1".to_owned(), diff --git a/parity/signer.rs b/parity/signer.rs index ab476ef9d7e54324d0374db48c103c7ea2deb7e2..e9a636bf8bcc75a733bb8375faacc2fc7c821b46 100644 --- a/parity/signer.rs +++ b/parity/signer.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -28,7 +28,6 @@ pub const CODES_FILENAME: &'static str = "authcodes"; pub struct NewToken { pub token: String, - pub url: String, pub message: String, } @@ -49,45 +48,26 @@ pub fn codes_path(path: &Path) -> PathBuf { p } -pub fn execute(ws_conf: rpc::WsConfiguration, ui_conf: rpc::UiConfiguration, logger_config: LogConfig) -> Result { - Ok(generate_token_and_url(&ws_conf, &ui_conf, &logger_config)?.message) +pub fn execute(ws_conf: rpc::WsConfiguration, logger_config: LogConfig) -> Result { + Ok(generate_token_and_url(&ws_conf, &logger_config)?.message) } -pub fn generate_token_and_url(ws_conf: &rpc::WsConfiguration, ui_conf: &rpc::UiConfiguration, logger_config: &LogConfig) -> Result { +pub fn generate_token_and_url(ws_conf: &rpc::WsConfiguration, logger_config: &LogConfig) -> Result { let code = generate_new_token(&ws_conf.signer_path, logger_config.color).map_err(|err| format!("Error generating token: {:?}", err))?; - let auth_url = format!("http://{}:{}/#/auth?token={}", ui_conf.interface, ui_conf.port, code); let colored = |s: String| match logger_config.color { true => format!("{}", White.bold().paint(s)), false => s, }; - if !ui_conf.enabled { - return Ok(NewToken { - token: code.clone(), - url: auth_url.clone(), - message: format!( - r#" -Generated token: -{} -"#, - colored(code) - ), - }) - } - - // And print in to the console Ok(NewToken { token: code.clone(), - url: auth_url.clone(), message: format!( r#" -Open: {} -to authorize your browser. -Or use the generated token: -{}"#, - colored(auth_url), - code - ) +Generated token: +{} +"#, + colored(code) + ), }) } diff --git a/parity/snapshot.rs b/parity/snapshot.rs index 3c0dadedaa32c8e3fc65fe3b41be70ea0177c43f..0611734fd334a2ae32bd4c297b308c4a749681ce 100644 --- a/parity/snapshot.rs +++ b/parity/snapshot.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -60,7 +60,6 @@ pub struct SnapshotCommand { pub fat_db: Switch, pub compaction: DatabaseCompactionProfile, pub file_path: Option, - pub wal: bool, pub kind: Kind, pub block_at: BlockId, } @@ -173,17 +172,17 @@ impl SnapshotCommand { tracing, fat_db, self.compaction, - self.wal, VMType::default(), "".into(), algorithm, self.pruning_history, self.pruning_memory, - true + true, ); - let client_db = db::open_client_db(&client_path, &client_config)?; let restoration_db_handler = db::restoration_db_handler(&client_path, &client_config); + let client_db = restoration_db_handler.open(&client_path) + .map_err(|e| format!("Failed to open database {:?}", e))?; let service = ClientService::start( client_config, diff --git a/parity/stratum.rs b/parity/stratum.rs index 043ba5062239fa4dba0c48a488f670f5ae9639fc..efaa6b307ce953de18769f52202a9caf826362d6 100644 --- a/parity/stratum.rs +++ b/parity/stratum.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/upgrade.rs b/parity/upgrade.rs index c5c2e1ed48ccf8f05dcb0c12827784055ff72c58..d98123ce13bc4cf747c9d2e5401ab4b08f8d0ab1 100644 --- a/parity/upgrade.rs +++ b/parity/upgrade.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/url.rs b/parity/url.rs deleted file mode 100644 index 4f547c28f07367dfe75f59273b7afa74a4cc6d25..0000000000000000000000000000000000000000 --- a/parity/url.rs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Cross-platform open url in default browser - -use std; -use std::os::raw::c_int; - -#[allow(unused)] -pub enum Error { - ProcessError(std::io::Error), - WindowsShellExecute(c_int), -} - -impl From for Error { - fn from(err: std::io::Error) -> Self { - Error::ProcessError(err) - } -} - -impl std::fmt::Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - match *self { - Error::ProcessError(ref e) => write!(f, "{}", e), - Error::WindowsShellExecute(e) => write!(f, "WindowsShellExecute error: {}", e), - } - } -} - -#[cfg(windows)] -pub fn open(url: &str) -> Result<(), Error> { - use std::ffi::CString; - use std::ptr; - use winapi::um::shellapi::ShellExecuteA; - use winapi::um::winuser::SW_SHOWNORMAL as Normal; - - const WINDOWS_SHELL_EXECUTE_SUCCESS: c_int = 32; - - let h_instance = unsafe { - ShellExecuteA(ptr::null_mut(), - CString::new("open").unwrap().as_ptr(), - CString::new(url.to_owned().replace("\n", "%0A")).unwrap().as_ptr(), - ptr::null(), - ptr::null(), - Normal) as c_int - }; - - // https://msdn.microsoft.com/en-us/library/windows/desktop/bb762153(v=vs.85).aspx - // `ShellExecute` returns a value greater than 32 on success - if h_instance > WINDOWS_SHELL_EXECUTE_SUCCESS { - Ok(()) - } else { - Err(Error::WindowsShellExecute(h_instance)) - } -} - -#[cfg(any(target_os="macos", target_os="freebsd"))] -pub fn open(url: &str) -> Result<(), Error> { - let _ = std::process::Command::new("open").arg(url).spawn()?; - Ok(()) -} - -#[cfg(target_os="linux")] -pub fn open(url: &str) -> Result<(), Error> { - let _ = std::process::Command::new("xdg-open").arg(url).spawn()?; - Ok(()) -} - -#[cfg(target_os="android")] -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 - // as a library and not as a full binary. - Ok(()) -} diff --git a/parity/user_defaults.rs b/parity/user_defaults.rs index be91e302ebe4cace355950d131116bd0097044c3..5df50dd99d382c348d2ffb93a802f3656c40e02d 100644 --- a/parity/user_defaults.rs +++ b/parity/user_defaults.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,107 +14,130 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::fmt; use std::fs::File; use std::io::Write; use std::path::Path; -use std::collections::BTreeMap; use std::time::Duration; -use serde::{Serialize, Serializer, Deserialize, Deserializer}; -use serde::de::{Error, Visitor, MapAccess}; -use serde::de::value::MapAccessDeserializer; -use serde_json::Value; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_json::de::from_reader; use serde_json::ser::to_string; use journaldb::Algorithm; -use ethcore::client::Mode; +use ethcore::client::{Mode as ClientMode}; +#[derive(Clone)] +pub struct Seconds(Duration); + +impl Seconds { + pub fn value(&self) -> u64 { + self.0.as_secs() + } +} + +impl From for Seconds { + fn from(s: u64) -> Seconds { + Seconds(Duration::from_secs(s)) + } +} + +impl From for Seconds { + fn from(d: Duration) -> Seconds { + Seconds(d) + } +} + +impl Into for Seconds { + fn into(self) -> Duration { + self.0 + } +} + +impl Serialize for Seconds { + fn serialize(&self, serializer: S) -> Result { + serializer.serialize_u64(self.value()) + } +} + +impl<'de> Deserialize<'de> for Seconds { + fn deserialize>(deserializer: D) -> Result { + let secs = u64::deserialize(deserializer)?; + Ok(Seconds::from(secs)) + } +} + +#[derive(Clone, Serialize, Deserialize)] +#[serde(rename_all = "lowercase", tag = "mode")] +pub enum Mode { + Active, + Passive { + #[serde(rename = "mode.timeout")] + timeout: Seconds, + #[serde(rename = "mode.alarm")] + alarm: Seconds, + }, + Dark { + #[serde(rename = "mode.timeout")] + timeout: Seconds, + }, + Offline, +} + +impl Into for Mode { + fn into(self) -> ClientMode { + match self { + Mode::Active => ClientMode::Active, + Mode::Passive { timeout, alarm } => ClientMode::Passive(timeout.into(), alarm.into()), + Mode::Dark { timeout } => ClientMode::Dark(timeout.into()), + Mode::Offline => ClientMode::Off, + } + } +} + +impl From for Mode { + fn from(mode: ClientMode) -> Mode { + match mode { + ClientMode::Active => Mode::Active, + ClientMode::Passive(timeout, alarm) => Mode::Passive { timeout: timeout.into(), alarm: alarm.into() }, + ClientMode::Dark(timeout) => Mode::Dark { timeout: timeout.into() }, + ClientMode::Off => Mode::Offline, + } + } +} + +#[derive(Serialize, Deserialize)] pub struct UserDefaults { pub is_first_launch: bool, + #[serde(with = "algorithm_serde")] pub pruning: Algorithm, pub tracing: bool, pub fat_db: bool, - pub mode: Mode, + #[serde(flatten)] + mode: Mode, } -impl Serialize for UserDefaults { - fn serialize(&self, serializer: S) -> Result - where S: Serializer { - let mut map: BTreeMap = BTreeMap::new(); - map.insert("is_first_launch".into(), Value::Bool(self.is_first_launch)); - map.insert("pruning".into(), Value::String(self.pruning.as_str().into())); - map.insert("tracing".into(), Value::Bool(self.tracing)); - map.insert("fat_db".into(), Value::Bool(self.fat_db)); - let mode_str = match self.mode { - Mode::Off => "offline", - Mode::Dark(timeout) => { - map.insert("mode.timeout".into(), Value::Number(timeout.as_secs().into())); - "dark" - }, - Mode::Passive(timeout, alarm) => { - map.insert("mode.timeout".into(), Value::Number(timeout.as_secs().into())); - map.insert("mode.alarm".into(), Value::Number(alarm.as_secs().into())); - "passive" - }, - Mode::Active => "active", - }; - map.insert("mode".into(), Value::String(mode_str.into())); - - map.serialize(serializer) +impl UserDefaults { + pub fn mode(&self) -> ClientMode { + self.mode.clone().into() } -} -struct UserDefaultsVisitor; - -impl<'a> Deserialize<'a> for UserDefaults { - fn deserialize(deserializer: D) -> Result - where D: Deserializer<'a> { - deserializer.deserialize_any(UserDefaultsVisitor) + pub fn set_mode(&mut self, mode: ClientMode) { + self.mode = mode.into(); } } -impl<'a> Visitor<'a> for UserDefaultsVisitor { - type Value = UserDefaults; +mod algorithm_serde { + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + use serde::de::Error; + use journaldb::Algorithm; - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "a valid UserDefaults object") + pub fn serialize(algorithm: &Algorithm, serializer: S) -> Result + where S: Serializer { + algorithm.as_str().serialize(serializer) } - fn visit_map(self, visitor: V) -> Result where V: MapAccess<'a> { - let mut map: BTreeMap = Deserialize::deserialize(MapAccessDeserializer::new(visitor))?; - let pruning: Value = map.remove("pruning").ok_or_else(|| Error::custom("missing pruning"))?; - let pruning = pruning.as_str().ok_or_else(|| Error::custom("invalid pruning value"))?; - let pruning = pruning.parse().map_err(|_| Error::custom("invalid pruning method"))?; - let tracing: Value = map.remove("tracing").ok_or_else(|| Error::custom("missing tracing"))?; - let tracing = tracing.as_bool().ok_or_else(|| Error::custom("invalid tracing value"))?; - let fat_db: Value = map.remove("fat_db").unwrap_or_else(|| Value::Bool(false)); - let fat_db = fat_db.as_bool().ok_or_else(|| Error::custom("invalid fat_db value"))?; - - let mode: Value = map.remove("mode").unwrap_or_else(|| Value::String("active".to_owned())); - let mode = match mode.as_str().ok_or_else(|| Error::custom("invalid mode value"))? { - "offline" => Mode::Off, - "dark" => { - let timeout = map.remove("mode.timeout").and_then(|v| v.as_u64()).ok_or_else(|| Error::custom("invalid/missing mode.timeout value"))?; - Mode::Dark(Duration::from_secs(timeout)) - }, - "passive" => { - let timeout = map.remove("mode.timeout").and_then(|v| v.as_u64()).ok_or_else(|| Error::custom("invalid/missing mode.timeout value"))?; - let alarm = map.remove("mode.alarm").and_then(|v| v.as_u64()).ok_or_else(|| Error::custom("invalid/missing mode.alarm value"))?; - Mode::Passive(Duration::from_secs(timeout), Duration::from_secs(alarm)) - }, - "active" => Mode::Active, - _ => { return Err(Error::custom("invalid mode value")); }, - }; - - let user_defaults = UserDefaults { - is_first_launch: false, - pruning: pruning, - tracing: tracing, - fat_db: fat_db, - mode: mode, - }; - - Ok(user_defaults) + pub fn deserialize<'de, D>(deserializer: D) -> Result + where D: Deserializer<'de> { + let pruning = String::deserialize(deserializer)?; + pruning.parse().map_err(|_| Error::custom("invalid pruning method")) } } @@ -122,7 +145,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/parity/whisper.rs b/parity/whisper.rs index bb9aebf0b9beb19db7b26e2292605769bce952e0..c3c8854dcb6c700611d28af7994f29b5ea09615a 100644 --- a/parity/whisper.rs +++ b/parity/whisper.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/price-info/Cargo.toml b/price-info/Cargo.toml index 948f09983bae78ce6a6e49f2058ae16ddc6b483b..7dc648516fd3c8fc43c0ef30ed65ac3eb9d1c9eb 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/price-info/src/lib.rs b/price-info/src/lib.rs index e3594ad2ae90bfdbafc3994c1ce55ce3d2989848..93dacca33847b7df033e62a8d66a1e2879f441fa 100644 --- a/price-info/src/lib.rs +++ b/price-info/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/registrar/Cargo.toml b/registrar/Cargo.toml index 3ba26e45607f5aac8156abfb2d9aba38080b1d24..dcbfa439e22e2e2962c84916f25431b359c726fb 100644 --- a/registrar/Cargo.toml +++ b/registrar/Cargo.toml @@ -10,4 +10,4 @@ futures = "0.1" ethabi = "5.1.0" ethabi-derive = "5.0.5" ethabi-contract = "5.0.3" -keccak-hash = { path = "../util/hash" } +keccak-hash = { git = "https://github.com/paritytech/parity-common" } diff --git a/registrar/src/lib.rs b/registrar/src/lib.rs index 961fbb17ee64adeee97ee37a7757966c5b8affc6..aad33765efef03813516c0015a30acff435303f1 100644 --- a/registrar/src/lib.rs +++ b/registrar/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/registrar/src/registrar.rs b/registrar/src/registrar.rs index c4128660d23bc78fa9a40c53974afbc21c49a6d1..0a17de499a7585769a06f969987f2bc0500964bd 100644 --- a/registrar/src/registrar.rs +++ b/registrar/src/registrar.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -74,4 +74,3 @@ pub trait RegistrarClient: Send + Sync { /// Call Contract fn call_contract(&self, address: Address, data: Bytes) -> Self::Call; } - diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 8a0b689c65592be60ca552a9f5bb6116cc04ff93..7e25871a35028e6059973a721bd80d0ce2020f30 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" @@ -36,9 +36,9 @@ jsonrpc-macros = { git = "https://github.com/paritytech/jsonrpc.git", branch = " jsonrpc-pubsub = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } ethash = { path = "../ethash" } -ethcore = { path = "../ethcore" } -ethcore-bytes = { path = "../util/bytes" } -ethcore-crypto = { path = "../ethcore/crypto" } +ethcore = { path = "../ethcore", features = ["test-helpers"] } +parity-bytes = { git = "https://github.com/paritytech/parity-common" } +parity-crypto = { git = "https://github.com/paritytech/parity-common" } ethcore-devtools = { path = "../devtools" } ethcore-io = { path = "../util/io" } ethcore-light = { path = "../ethcore/light" } @@ -53,21 +53,26 @@ ethjson = { path = "../json" } ethkey = { path = "../ethkey" } ethstore = { path = "../ethstore" } fetch = { path = "../util/fetch" } -hardware-wallet = { path = "../hw" } -keccak-hash = { path = "../util/hash" } -node-health = { path = "../dapps/node-health" } +keccak-hash = { git = "https://github.com/paritytech/parity-common" } parity-reactor = { path = "../util/reactor" } parity-updater = { path = "../updater" } parity-version = { path = "../util/version" } -patricia-trie = { path = "../util/patricia_trie" } -rlp = { path = "../util/rlp" } +patricia-trie = { git = "https://github.com/paritytech/parity-common" } +rlp = { git = "https://github.com/paritytech/parity-common" } stats = { path = "../util/stats" } vm = { path = "../ethcore/vm" } +[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))'.dependencies] +hardware-wallet = { path = "../hw" } + +[target.'cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))'.dependencies] +fake-hardware-wallet = { path = "../util/fake-hardware-wallet" } + [dev-dependencies] +ethcore = { path = "../ethcore", features = ["test-helpers"] } ethcore-network = { path = "../util/network" } fake-fetch = { path = "../util/fake-fetch" } -kvdb-memorydb = { path = "../util/kvdb-memorydb" } +kvdb-memorydb = { git = "https://github.com/paritytech/parity-common" } macros = { path = "../util/macros" } pretty_assertions = "0.1" transaction-pool = { path = "../transaction-pool" } diff --git a/rpc/src/authcodes.rs b/rpc/src/authcodes.rs index d18d0741fd69b80358e7d7fcab841b8f44e4106c..5b7309a317692eafbf4efe835f54d8613ffdefc4 100644 --- a/rpc/src/authcodes.rs +++ b/rpc/src/authcodes.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/http_common.rs b/rpc/src/http_common.rs index 72af6e469741ab5ecc9f62da99d1ae22e8b36e7c..8296720b20f95c70988223553a2c666af0526b94 100644 --- a/rpc/src/http_common.rs +++ b/rpc/src/http_common.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 1fc3d0e242879085f05b8b2b1bcac120faebddca..2e731cd3475894332b372592a6f53efbabe947e2 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -43,10 +43,9 @@ extern crate jsonrpc_ipc_server as ipc; extern crate jsonrpc_pubsub; extern crate ethash; -#[cfg_attr(test, macro_use)] extern crate ethcore; -extern crate ethcore_bytes as bytes; -extern crate ethcore_crypto as crypto; +extern crate parity_bytes as bytes; +extern crate parity_crypto as crypto; extern crate ethcore_devtools as devtools; extern crate ethcore_io as io; extern crate ethcore_light as light; @@ -58,17 +57,20 @@ extern crate ethcore_transaction as transaction; extern crate ethereum_types; extern crate ethkey; extern crate ethstore; -extern crate vm; extern crate fetch; -extern crate node_health; +extern crate keccak_hash as hash; extern crate parity_reactor; extern crate parity_updater as updater; extern crate parity_version as version; +extern crate patricia_trie as trie; extern crate rlp; extern crate stats; -extern crate keccak_hash as hash; +extern crate vm; + +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] extern crate hardware_wallet; -extern crate patricia_trie as trie; +#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] +extern crate fake_hardware_wallet as hardware_wallet; #[macro_use] extern crate log; @@ -114,8 +116,8 @@ pub use http::{ AccessControlAllowOrigin, Host, DomainsValidation }; -pub use v1::{NetworkSettings, Metadata, Origin, informant, dispatch, signer, dapps}; -pub use v1::block_import::is_major_importing; +pub use v1::{NetworkSettings, Metadata, Origin, informant, dispatch, signer}; +pub use v1::block_import::{is_major_importing, is_major_importing_or_waiting}; pub use v1::extractors::{RpcExtractor, WsExtractor, WsStats, WsDispatcher}; pub use authcodes::{AuthCodes, TimeProvider}; pub use http_common::HttpMetaExtractor; @@ -127,34 +129,59 @@ use http::tokio_core; pub type HttpServer = http::Server; /// Start http server asynchronously and returns result with `Server` handle on success or an error. -pub fn start_http( +pub fn start_http( addr: &SocketAddr, cors_domains: http::DomainsValidation, allowed_hosts: http::DomainsValidation, handler: H, remote: tokio_core::reactor::Remote, extractor: T, - middleware: Option, threads: usize, + max_payload: usize, ) -> ::std::io::Result where M: jsonrpc_core::Metadata, S: jsonrpc_core::Middleware, H: Into>, T: HttpMetaExtractor, - R: RequestMiddleware, { let extractor = http_common::MetaExtractor::new(extractor); - let mut builder = http::ServerBuilder::with_meta_extractor(handler, extractor) + Ok(http::ServerBuilder::with_meta_extractor(handler, extractor) .threads(threads) .event_loop_remote(remote) .cors(cors_domains.into()) - .allowed_hosts(allowed_hosts.into()); - - if let Some(dapps) = middleware { - builder = builder.request_middleware(dapps) - } + .allowed_hosts(allowed_hosts.into()) + .max_request_body_size(max_payload * 1024 * 1024) + .start_http(addr)?) +} - Ok(builder.start_http(addr)?) +/// Same as `start_http`, but takes an additional `middleware` parameter that is introduced as a +/// hyper middleware. +pub fn start_http_with_middleware( + addr: &SocketAddr, + cors_domains: http::DomainsValidation, + allowed_hosts: http::DomainsValidation, + handler: H, + remote: tokio_core::reactor::Remote, + extractor: T, + middleware: R, + threads: usize, + max_payload: usize, +) -> ::std::io::Result where + M: jsonrpc_core::Metadata, + S: jsonrpc_core::Middleware, + H: Into>, + T: HttpMetaExtractor, + R: RequestMiddleware, +{ + let extractor = http_common::MetaExtractor::new(extractor); + Ok(http::ServerBuilder::with_meta_extractor(handler, extractor) + .threads(threads) + .event_loop_remote(remote) + .cors(cors_domains.into()) + .allowed_hosts(allowed_hosts.into()) + .max_request_body_size(max_payload * 1024 * 1024) + .request_middleware(middleware) + .start_http(addr)?) } /// Start ipc server asynchronously and returns result with `Server` handle on success or an error. diff --git a/rpc/src/tests/helpers.rs b/rpc/src/tests/helpers.rs index db61353d538eebacad0b23ef7976849d6ec76748..602648d063c107b86e436fe76339ca7706a6e6d7 100644 --- a/rpc/src/tests/helpers.rs +++ b/rpc/src/tests/helpers.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/tests/mod.rs b/rpc/src/tests/mod.rs index d4d9538dcaa1e35585044fb91c125391557b3b21..6ecab3299ae51d144c6a754359e5084c11f6824e 100644 --- a/rpc/src/tests/mod.rs +++ b/rpc/src/tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/tests/rpc.rs b/rpc/src/tests/rpc.rs index 6e2900c8b7bb4ba0a0a31d06bd111a87fda94f46..d15aeca6cb0af92ee07d67a432ec2c46c286b30c 100644 --- a/rpc/src/tests/rpc.rs +++ b/rpc/src/tests/rpc.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -26,20 +26,21 @@ fn serve(handler: Option>) -> Server { let address = "127.0.0.1:0".parse().unwrap(); let handler = handler.unwrap_or_default(); - Server::new(|remote| ::start_http( + Server::new(|remote| ::start_http_with_middleware( &address, http::DomainsValidation::Disabled, http::DomainsValidation::Disabled, handler, remote, extractors::RpcExtractor, - Some(|request: hyper::Request| { + |request: hyper::Request| { http::RequestMiddlewareAction::Proceed { should_continue_on_invalid_cors: false, request, } - }), + }, 1, + 5, ).unwrap()) } diff --git a/rpc/src/tests/ws.rs b/rpc/src/tests/ws.rs index 429ff6d3c4e10aa571052ce78b5d0092c8c1d591..91f10e64758b95bf534f5a77ed82ca917bd8c6da 100644 --- a/rpc/src/tests/ws.rs +++ b/rpc/src/tests/ws.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -177,7 +177,6 @@ mod testing { ) ); - // then assert_eq!(response1.status, "HTTP/1.1 101 Switching Protocols".to_owned()); assert_eq!(response2.status, "HTTP/1.1 403 Forbidden".to_owned()); diff --git a/rpc/src/v1/extractors.rs b/rpc/src/v1/extractors.rs index 071e57dae4345fb3f83efb349f8c4a98c860ab42..c69c41dddf32f309f74c74864bea786dbc95e969 100644 --- a/rpc/src/v1/extractors.rs +++ b/rpc/src/v1/extractors.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/ui-deprecation/build.rs b/rpc/src/v1/helpers/accounts.rs similarity index 68% rename from dapps/ui-deprecation/build.rs rename to rpc/src/v1/helpers/accounts.rs index c427f3d54d5bf873d75640d1f16e2d0cdcc922ec..4268bf2f99f298154f295a1c4fdd405cb65cd3b7 100644 --- a/dapps/ui-deprecation/build.rs +++ b/rpc/src/v1/helpers/accounts.rs @@ -14,8 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -extern crate parity_dapps_glue; +use std::sync::Arc; +use ethcore::account_provider::AccountProvider; +use jsonrpc_core::Error; +use v1::helpers::errors; -fn main() { - parity_dapps_glue::generate(); +pub fn unwrap_provider(provider: &Option>) -> Result, Error> { + match *provider { + Some(ref arc) => Ok(arc.clone()), + None => Err(errors::public_unsupported(None)), + } } diff --git a/rpc/src/v1/helpers/block_import.rs b/rpc/src/v1/helpers/block_import.rs index 1246faa658b17cffbe739064bf559ed5c6522b23..50a4ed8e00662179a3adfe4beb39b0579bef32b9 100644 --- a/rpc/src/v1/helpers/block_import.rs +++ b/rpc/src/v1/helpers/block_import.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -19,23 +19,29 @@ use ethcore::client::BlockQueueInfo; use sync::SyncState; -/// Check if client is during major sync or during block import. -pub fn is_major_importing(sync_state: Option, queue_info: BlockQueueInfo) -> bool { +/// Check if client is during major sync or during block import and allows defining whether 'waiting for peers' should +/// be considered a syncing state. +pub fn is_major_importing_or_waiting(sync_state: Option, queue_info: BlockQueueInfo, waiting_is_syncing_state: bool) -> bool { let is_syncing_state = sync_state.map_or(false, |s| match s { - SyncState::Idle | SyncState::NewBlocks | SyncState::WaitingPeers => false, + SyncState::Idle | SyncState::NewBlocks => false, + SyncState::WaitingPeers if !waiting_is_syncing_state => false, _ => true, }); let is_verifying = queue_info.unverified_queue_size + queue_info.verified_queue_size > 3; is_verifying || is_syncing_state } +/// Check if client is during major sync or during block import. +pub fn is_major_importing(sync_state: Option, queue_info: BlockQueueInfo) -> bool { + is_major_importing_or_waiting(sync_state, queue_info, true) +} + #[cfg(test)] mod tests { use ethcore::client::BlockQueueInfo; use sync::SyncState; use super::is_major_importing; - fn queue_info(unverified: usize, verified: usize) -> BlockQueueInfo { BlockQueueInfo { unverified_queue_size: unverified, diff --git a/rpc/src/v1/helpers/dapps.rs b/rpc/src/v1/helpers/dapps.rs deleted file mode 100644 index 391a12c824d34b8fc84380f380395fced0181ed6..0000000000000000000000000000000000000000 --- a/rpc/src/v1/helpers/dapps.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Dapps Service - -use v1::types::LocalDapp; - -/// Dapps Server service. -pub trait DappsService: Send + Sync + 'static { - /// List available local dapps. - fn list_dapps(&self) -> Vec; - /// Refresh local dapps list - fn refresh_local_dapps(&self) -> bool; -} diff --git a/rpc/src/v1/helpers/dispatch.rs b/rpc/src/v1/helpers/dispatch.rs index 1f43ef008efbdbf2edada8a8b88743914a6c3f5f..9b789a56bb2e2f9cb026b296550b72a7db0a0c1c 100644 --- a/rpc/src/v1/helpers/dispatch.rs +++ b/rpc/src/v1/helpers/dispatch.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -24,14 +24,13 @@ use light::cache::Cache as LightDataCache; use light::client::LightChainClient; use light::on_demand::{request, OnDemand}; use light::TransactionQueue as LightTransactionQueue; -use rlp; use hash::keccak; use ethereum_types::{H256, H520, Address, U256}; use bytes::Bytes; use parking_lot::{Mutex, RwLock}; use stats::Corpus; -use ethkey::Signature; +use ethkey::{Password, Signature}; use sync::LightSync; use ethcore::ids::BlockId; use ethcore::client::BlockChainClient; @@ -52,6 +51,7 @@ use v1::types::{ SignRequest as RpcSignRequest, DecryptRequest as RpcDecryptRequest, }; +use rlp; pub use self::nonce::Reservations; @@ -123,10 +123,13 @@ impl FullDispatcher { } /// Imports transaction to the miner's queue. - pub fn dispatch_transaction(client: &C, miner: &M, signed_transaction: PendingTransaction) -> Result { + pub fn dispatch_transaction(client: &C, miner: &M, signed_transaction: PendingTransaction, trusted: bool) -> Result { let hash = signed_transaction.transaction.hash(); - miner.import_own_transaction(client, signed_transaction) + // use `import_claimed_local_transaction` so we can decide (based on config flags) if we want to treat + // it as local or not. Nodes with public RPC interfaces will want these transactions to be treated like + // external transactions. + miner.import_claimed_local_transaction(client, signed_transaction, trusted) .map_err(errors::transaction) .map(|_| hash) } @@ -175,12 +178,11 @@ impl Dispatcher } fn enrich(&self, signed_transaction: SignedTransaction) -> RpcRichRawTransaction { - let block_number = self.client.best_block_header().number(); - RpcRichRawTransaction::from_signed(signed_transaction, block_number, self.client.eip86_transition()) + RpcRichRawTransaction::from_signed(signed_transaction) } fn dispatch_transaction(&self, signed_transaction: PendingTransaction) -> Result { - Self::dispatch_transaction(&*self.client, &*self.miner, signed_transaction) + Self::dispatch_transaction(&*self.client, &*self.miner, signed_transaction, true) } } @@ -237,7 +239,7 @@ pub fn fetch_gas_price_corpus( /// Returns a eth_sign-compatible hash of data to sign. /// The data is prepended with special message to prevent -/// chosen-plaintext attacks. +/// malicious DApps from using the function to sign forged transactions. pub fn eth_data_hash(mut data: Bytes) -> H256 { let mut message_data = format!("\x19Ethereum Signed Message:\n{}", data.len()) @@ -320,7 +322,7 @@ impl LightDispatcher { x.map(move |acc| acc.map_or(account_start_nonce, |acc| acc.nonce)) .map_err(|_| errors::no_light_peers()) ), - None => Box::new(future::err(errors::network_disabled())) + None => Box::new(future::err(errors::network_disabled())) } } } @@ -402,8 +404,7 @@ impl Dispatcher for LightDispatcher { } fn enrich(&self, signed_transaction: SignedTransaction) -> RpcRichRawTransaction { - let block_number = self.client.best_block_header().number(); - RpcRichRawTransaction::from_signed(signed_transaction, block_number, self.client.eip86_transition()) + RpcRichRawTransaction::from_signed(signed_transaction) } fn dispatch_transaction(&self, signed_transaction: PendingTransaction) -> Result { @@ -557,15 +558,15 @@ impl Future for ProspectiveSigner { } /// Single-use account token. -pub type AccountToken = String; +pub type AccountToken = Password; /// Values used to unlock accounts for signing. -#[derive(Debug, Clone, PartialEq)] +#[derive(Clone, PartialEq)] pub enum SignWith { /// Nothing -- implies the account is already unlocked. Nothing, /// Unlock with password. - Password(String), + Password(Password), /// Unlock with single-use token. Token(AccountToken), } @@ -581,8 +582,7 @@ impl SignWith { } /// A value, potentially accompanied by a signing token. -#[derive(Debug)] -pub enum WithToken { +pub enum WithToken { /// No token. No(T), /// With token. @@ -674,9 +674,16 @@ pub fn execute( }, ConfirmationPayload::EthSignMessage(address, data) => { if accounts.is_hardware_address(&address) { - return Box::new(future::err(errors::unsupported("Signing via hardware wallets is not supported.", None))); - } + let signature = accounts.sign_message_with_hardware(&address, &data) + .map(|s| H520(s.into_electrum())) + .map(RpcH520::from) + .map(ConfirmationResponse::Signature) + // TODO: is this correct? I guess the `token` is the wallet in this context + .map(WithToken::No) + .map_err(|e| errors::account("Error signing message with hardware_wallet", e)); + return Box::new(future::done(signature)); + } let hash = eth_data_hash(data); let res = signature(&accounts, address, hash, pass) .map(|result| result @@ -690,7 +697,6 @@ pub fn execute( if accounts.is_hardware_address(&address) { return Box::new(future::err(errors::unsupported("Decrypting via hardware wallets is not supported.", None))); } - let res = decrypt(&accounts, address, data, pass) .map(|result| result .map(RpcBytes) @@ -720,7 +726,7 @@ fn hardware_signature(accounts: &AccountProvider, address: Address, t: Transacti let mut stream = rlp::RlpStream::new(); t.rlp_append_unsigned_transaction(&mut stream, chain_id); - let signature = accounts.sign_with_hardware(address, &t, chain_id, &stream.as_raw()) + let signature = accounts.sign_transaction_with_hardware(&address, &t, chain_id, &stream.as_raw()) .map_err(|e| { debug!(target: "miner", "Error signing transaction with hardware wallet: {}", e); errors::account("Error signing transaction with hardware wallet", e) @@ -728,8 +734,8 @@ fn hardware_signature(accounts: &AccountProvider, address: Address, t: Transacti SignedTransaction::new(t.with_signature(signature, chain_id)) .map_err(|e| { - debug!(target: "miner", "Hardware wallet has produced invalid signature: {}", e); - errors::account("Invalid signature generated", e) + debug!(target: "miner", "Hardware wallet has produced invalid signature: {}", e); + errors::account("Invalid signature generated", e) }) } diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index 0d36a926e9dcccad38a3b0c9eb1b4fc7d8749336..710f7d7497a173206e523786f2e1ae48c697e4c6 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -211,14 +211,6 @@ pub fn signer_disabled() -> Error { } } -pub fn dapps_disabled() -> Error { - Error { - code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST), - message: "Dapps Server is disabled. This API is not available.".into(), - data: None, - } -} - pub fn ws_disabled() -> Error { Error { code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST), diff --git a/rpc/src/v1/helpers/fake_sign.rs b/rpc/src/v1/helpers/fake_sign.rs index 84a225d8141714c2e993681976a168f2e0daa3c7..fc6aaccdd5fcb23daa1d19c69b05c843bbbf18c4 100644 --- a/rpc/src/v1/helpers/fake_sign.rs +++ b/rpc/src/v1/helpers/fake_sign.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -15,7 +15,6 @@ // along with Parity. If not, see . use transaction::{Transaction, SignedTransaction, Action}; -use ethereum_types::U256; use jsonrpc_core::Error; use v1::helpers::CallRequest; @@ -29,7 +28,7 @@ pub fn sign_call(request: CallRequest, gas_cap: bool) -> Result gas, None if gas_cap => max_gas, - None => U256::from(2) << 50, + None => max_gas * 10, }; let from = request.from.unwrap_or(0.into()); diff --git a/rpc/src/v1/helpers/ipfs.rs b/rpc/src/v1/helpers/ipfs.rs index da51f1fd549552d9439d387fa66a585a4b2090e7..12980d3f418c092ba5cdad7037261d7b9cf31ced 100644 --- a/rpc/src/v1/helpers/ipfs.rs +++ b/rpc/src/v1/helpers/ipfs.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/helpers/light_fetch.rs b/rpc/src/v1/helpers/light_fetch.rs index 1baf9a76471fcf49863a5456182c28e03f1f92a4..1da2fdf1ad36d022cca2e9f8410e10f5ee823b7f 100644 --- a/rpc/src/v1/helpers/light_fetch.rs +++ b/rpc/src/v1/helpers/light_fetch.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -20,7 +20,6 @@ use std::sync::Arc; use ethcore::basic_account::BasicAccount; use ethcore::encoded; -use ethcore::executed::{Executed, ExecutionError}; use ethcore::ids::BlockId; use ethcore::filter::Filter as EthcoreFilter; use ethcore::receipt::Receipt; @@ -33,7 +32,10 @@ use jsonrpc_macros::Trailing; use light::cache::Cache; use light::client::LightChainClient; use light::cht; -use light::on_demand::{request, OnDemand, HeaderRef, Request as OnDemandRequest, Response as OnDemandResponse}; +use light::on_demand::{ + request, OnDemand, HeaderRef, Request as OnDemandRequest, + Response as OnDemandResponse, ExecutionResult, +}; use light::request::Field; use sync::LightSync; @@ -64,7 +66,7 @@ pub struct LightFetch { } /// Extract a transaction at given index. -pub fn extract_transaction_at_index(block: encoded::Block, index: usize, eip86_transition: u64) -> Option { +pub fn extract_transaction_at_index(block: encoded::Block, index: usize) -> Option { block.transactions().into_iter().nth(index) // Verify if transaction signature is correct. .and_then(|tx| SignedTransaction::new(tx).ok()) @@ -83,13 +85,9 @@ pub fn extract_transaction_at_index(block: encoded::Block, index: usize, eip86_t cached_sender, } }) - .map(|tx| Transaction::from_localized(tx, eip86_transition)) + .map(|tx| Transaction::from_localized(tx)) } - -/// Type alias for convenience. -pub type ExecutionResult = ::std::result::Result; - // extract the header indicated by the given `HeaderRef` from the given responses. // fails only if they do not correspond. fn extract_header(res: &[OnDemandResponse], header: HeaderRef) -> Option { @@ -367,7 +365,7 @@ impl LightFetch { // Get a transaction by hash. also returns the index in the block. // Only returns transactions in the canonical chain. - pub fn transaction_by_hash(&self, tx_hash: H256, eip86_transition: u64) + pub fn transaction_by_hash(&self, tx_hash: H256) -> impl Future, Error = Error> + Send { let params = (self.sync.clone(), self.on_demand.clone()); @@ -399,7 +397,7 @@ impl LightFetch { } let index = index.index as usize; - let transaction = extract_transaction_at_index(blk, index, eip86_transition); + let transaction = extract_transaction_at_index(blk, index); if transaction.as_ref().map_or(true, |tx| tx.hash != tx_hash.into()) { // index is actively wrong: indicated block has diff --git a/rpc/src/v1/helpers/mod.rs b/rpc/src/v1/helpers/mod.rs index 9adb5d68d4607c3e62abbc02de1fb52519e1a47f..ba8356334b318baa31c3594c8ba5ffb22f21d623 100644 --- a/rpc/src/v1/helpers/mod.rs +++ b/rpc/src/v1/helpers/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -18,7 +18,6 @@ pub mod errors; pub mod block_import; -pub mod dapps; pub mod dispatch; pub mod fake_sign; pub mod ipfs; @@ -39,12 +38,12 @@ 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, }; pub use self::signing_queue::{ - ConfirmationsQueue, ConfirmationReceiver, ConfirmationResult, + ConfirmationsQueue, ConfirmationReceiver, ConfirmationResult, ConfirmationSender, SigningQueue, QueueEvent, DefaultAccount, QUEUE_LIMIT as SIGNING_QUEUE_LIMIT, }; diff --git a/rpc/src/v1/helpers/network_settings.rs b/rpc/src/v1/helpers/network_settings.rs index a798286244d858305cc81624216dc3fd8f51f160..d011d2394fb5edb51a31b6eed8e8b5d8cf0ae0d3 100644 --- a/rpc/src/v1/helpers/network_settings.rs +++ b/rpc/src/v1/helpers/network_settings.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -13,6 +13,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . + //! Structure to hold network settings configured from CLI /// Networking & RPC settings diff --git a/rpc/src/v1/helpers/nonce.rs b/rpc/src/v1/helpers/nonce.rs index 06f38a85898dcb00e31795c7a0d29bf84ae18515..12dfd3d52034b0725e455bfdc0d8721b23754d2f 100644 --- a/rpc/src/v1/helpers/nonce.rs +++ b/rpc/src/v1/helpers/nonce.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 harity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/helpers/oneshot.rs b/rpc/src/v1/helpers/oneshot.rs index 89e90dbd18d29e69634e9caa891c473d03fe84a9..5ede0ae912fb3bbad6bd2a45320019970920c749 100644 --- a/rpc/src/v1/helpers/oneshot.rs +++ b/rpc/src/v1/helpers/oneshot.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/helpers/poll_filter.rs b/rpc/src/v1/helpers/poll_filter.rs index 7ef8db0f15f0b6ec7fae4dabbd9f3bb88707ed13..19979c814b8fa4e767dd3e60bb2209d878b78486 100644 --- a/rpc/src/v1/helpers/poll_filter.rs +++ b/rpc/src/v1/helpers/poll_filter.rs @@ -1,20 +1,58 @@ +// 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 . + //! 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), - /// Number of From block number, pending logs and log filter itself. - Logs(BlockNumber, HashSet, Filter) + /// 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) } /// Returns only last `n` logs diff --git a/rpc/src/v1/helpers/poll_manager.rs b/rpc/src/v1/helpers/poll_manager.rs index f367f669fdae20e5f1647d07539efe228844664c..03387a70939f28fa223eecdb9fc98554f18756fe 100644 --- a/rpc/src/v1/helpers/poll_manager.rs +++ b/rpc/src/v1/helpers/poll_manager.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -18,9 +18,6 @@ use transient_hashmap::{TransientHashMap, Timer, StandardTimer}; -/// Lifetime of poll (in seconds). -const POLL_LIFETIME: u32 = 60; - pub type PollId = usize; /// Indexes all poll requests. @@ -32,17 +29,17 @@ pub struct PollManager where T: Timer { } impl PollManager { - /// Creates new instance of indexer. - pub fn new() -> Self { - PollManager::new_with_timer(Default::default()) + /// Creates new instance of indexer + pub fn new(lifetime: u32) -> Self { + PollManager::new_with_timer(Default::default(), lifetime) } } impl PollManager where T: Timer { - pub fn new_with_timer(timer: T) -> Self { + pub fn new_with_timer(timer: T, lifetime: u32) -> Self { PollManager { - polls: TransientHashMap::new_with_timer(POLL_LIFETIME, timer), + polls: TransientHashMap::new_with_timer(lifetime, timer), next_available_id: 0, } } @@ -102,7 +99,7 @@ mod tests { time: &time, }; - let mut indexer = PollManager::new_with_timer(timer); + let mut indexer = PollManager::new_with_timer(timer,60); assert_eq!(indexer.create_poll(20), 0); assert_eq!(indexer.create_poll(20), 1); diff --git a/rpc/src/v1/helpers/requests.rs b/rpc/src/v1/helpers/requests.rs index 13bfbb1b38641bd046dc6f0f3bc5471506e4b51f..478f6785b4b16e85059d5681063ec9a78fc36d30 100644 --- a/rpc/src/v1/helpers/requests.rs +++ b/rpc/src/v1/helpers/requests.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/helpers/secretstore.rs b/rpc/src/v1/helpers/secretstore.rs index 019d2b1051fd1b57df678e74e9078544a48afa3a..f23222824fb943bec065231431b475dcebcab7ef 100644 --- a/rpc/src/v1/helpers/secretstore.rs +++ b/rpc/src/v1/helpers/secretstore.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/helpers/signer.rs b/rpc/src/v1/helpers/signer.rs index 6d9606f87803048c1732b7ee01ffc52e20356ad5..0ee14bad1b93ddd1deeae985731d8d12f63db70f 100644 --- a/rpc/src/v1/helpers/signer.rs +++ b/rpc/src/v1/helpers/signer.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -88,4 +88,3 @@ impl Deref for SignerService { &self.queue } } - diff --git a/rpc/src/v1/helpers/signing_queue.rs b/rpc/src/v1/helpers/signing_queue.rs index b73535ba4f9508c912b5fdf3817360d61d806b37..17b26b01ebba14eb42b8bdbef6805ebff857c6b4 100644 --- a/rpc/src/v1/helpers/signing_queue.rs +++ b/rpc/src/v1/helpers/signing_queue.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -75,16 +75,17 @@ pub trait SigningQueue: Send + Sync { /// `ConfirmationReceiver` is a `Future` awaiting for resolution of the given request. fn add_request(&self, request: ConfirmationPayload, origin: Origin) -> Result<(U256, ConfirmationReceiver), QueueAddError>; - /// Removes a request from the queue. /// Notifies possible token holders that request was rejected. - fn request_rejected(&self, id: U256) -> Option; + fn request_rejected(&self, sender: ConfirmationSender) -> Option; - /// Removes a request from the queue. /// Notifies possible token holders that request was confirmed and given hash was assigned. - fn request_confirmed(&self, id: U256, result: ConfirmationResult) -> Option; + fn request_confirmed(&self, sender: ConfirmationSender, result: ConfirmationResult) -> Option; - /// Returns a request if it is contained in the queue. - fn peek(&self, id: &U256) -> Option; + /// Put a request taken from `SigningQueue::take` back to the queue. + fn request_untouched(&self, sender: ConfirmationSender); + + /// Returns and removes a request if it is contained in the queue. + fn take(&self, id: &U256) -> Option; /// Return copy of all the requests in the queue. fn requests(&self) -> Vec; @@ -96,9 +97,12 @@ pub trait SigningQueue: Send + Sync { fn is_empty(&self) -> bool; } -struct ConfirmationSender { +/// Confirmation request information with result notifier. +pub struct ConfirmationSender { + /// Confirmation request information. + pub request: ConfirmationRequest, + sender: oneshot::Sender, - request: ConfirmationRequest, } /// Receiving end of the Confirmation channel; can be used as a `Future` to await for `ConfirmationRequest` @@ -122,38 +126,31 @@ impl ConfirmationsQueue { /// Notifies consumer that the communcation is over. /// No more events will be sent after this function is invoked. pub fn finish(&self) { - self.notify(QueueEvent::Finish); + self.notify_message(QueueEvent::Finish); self.on_event.write().clear(); } + /// Notifies `ConfirmationReceiver` holder about the result given a request. + fn notify_result(&self, sender: ConfirmationSender, result: Option) -> Option { + // notify receiver about the event + self.notify_message(result.clone().map_or_else( + || QueueEvent::RequestRejected(sender.request.id), + |_| QueueEvent::RequestConfirmed(sender.request.id) + )); + + // notify confirmation receiver about resolution + let result = result.ok_or(errors::request_rejected()); + sender.sender.send(result); + + Some(sender.request) + } + /// Notifies receiver about the event happening in this queue. - fn notify(&self, message: QueueEvent) { + fn notify_message(&self, message: QueueEvent) { for listener in &*self.on_event.read() { listener(message.clone()) } } - - /// Removes requests from this queue and notifies `ConfirmationReceiver` holder about the result. - /// Notifies also a receiver about that event. - fn remove(&self, id: U256, result: Option) -> Option { - let sender = self.queue.write().remove(&id); - - if let Some(sender) = sender { - // notify receiver about the event - self.notify(result.clone().map_or_else( - || QueueEvent::RequestRejected(id), - |_| QueueEvent::RequestConfirmed(id) - )); - - // notify confirmation receiver about resolution - let result = result.ok_or(errors::request_rejected()); - sender.sender.send(result); - - Some(sender.request) - } else { - None - } - } } impl Drop for ConfirmationsQueue { @@ -193,22 +190,26 @@ impl SigningQueue for ConfirmationsQueue { (id, receiver) }; // Notify listeners - self.notify(QueueEvent::NewRequest(id)); + self.notify_message(QueueEvent::NewRequest(id)); Ok(res) } - fn peek(&self, id: &U256) -> Option { - self.queue.read().get(id).map(|sender| sender.request.clone()) + fn take(&self, id: &U256) -> Option { + self.queue.write().remove(id) } - fn request_rejected(&self, id: U256) -> Option { - debug!(target: "own_tx", "Signer: Request rejected ({:?}).", id); - self.remove(id, None) + fn request_rejected(&self, sender: ConfirmationSender) -> Option { + debug!(target: "own_tx", "Signer: Request rejected ({:?}).", sender.request.id); + self.notify_result(sender, None) } - fn request_confirmed(&self, id: U256, result: ConfirmationResult) -> Option { - debug!(target: "own_tx", "Signer: Transaction confirmed ({:?}).", id); - self.remove(id, Some(result)) + fn request_confirmed(&self, sender: ConfirmationSender, result: ConfirmationResult) -> Option { + debug!(target: "own_tx", "Signer: Request confirmed ({:?}).", sender.request.id); + self.notify_result(sender, Some(result)) + } + + fn request_untouched(&self, sender: ConfirmationSender) { + self.queue.write().insert(sender.request.id, sender); } fn requests(&self) -> Vec { @@ -227,7 +228,6 @@ impl SigningQueue for ConfirmationsQueue { } } - #[cfg(test)] mod test { use std::sync::Arc; @@ -261,7 +261,8 @@ mod test { // when let (id, future) = queue.add_request(request, Default::default()).unwrap(); - queue.request_confirmed(id, Ok(ConfirmationResponse::SendTransaction(1.into()))); + let sender = queue.take(&id).unwrap(); + queue.request_confirmed(sender, Ok(ConfirmationResponse::SendTransaction(1.into()))); // then let confirmation = future.wait().unwrap(); diff --git a/rpc/src/v1/helpers/subscribers.rs b/rpc/src/v1/helpers/subscribers.rs index 11dd45d11b8f0c2a45ba6bb1bd400ae7582d0cdb..68712076438c9d2cb61333b31dd837e4744a6454 100644 --- a/rpc/src/v1/helpers/subscribers.rs +++ b/rpc/src/v1/helpers/subscribers.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -22,7 +22,6 @@ use jsonrpc_macros::pubsub::{Subscriber, Sink, SubscriptionId}; use rand::{Rng, StdRng}; use v1::types::H64; - #[derive(Debug, Clone, Hash, Eq, PartialEq)] pub struct Id(H64); impl str::FromStr for Id { diff --git a/rpc/src/v1/helpers/subscription_manager.rs b/rpc/src/v1/helpers/subscription_manager.rs index 5988824b6a4e63f47e5a3533c01aa050978d7b01..5f6d77d883088906b98240392005f3dd667e5437 100644 --- a/rpc/src/v1/helpers/subscription_manager.rs +++ b/rpc/src/v1/helpers/subscription_manager.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 32ba36deb863287942d81dd4a6914fdf0c2c804b..84c0aa6ed955653ddee49fb63f31b23c4d89a3ea 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -65,6 +65,8 @@ pub struct EthClientOptions { pub send_block_number_in_get_work: bool, /// Gas Price Percentile used as default gas price. pub gas_price_percentile: usize, + /// Set the timeout for the internal poll manager + pub poll_lifetime: u32 } impl EthClientOptions { @@ -83,6 +85,7 @@ impl Default for EthClientOptions { pending_nonce_from_queue: false, allow_pending_receipt_query: true, send_block_number_in_get_work: true, + poll_lifetime: 60u32, gas_price_percentile: 50, } } @@ -104,7 +107,6 @@ pub struct EthClient where external_miner: Arc, seed_compute: Mutex, options: EthClientOptions, - eip86_transition: u64, } #[derive(Debug)] @@ -164,18 +166,11 @@ impl EthClient`, errors if provider was not - /// set. - fn account_provider(&self) -> Result> { - Ok(self.accounts.clone()) - } - fn rich_block(&self, id: BlockNumberOrId, include_txs: bool) -> Result> { let client = &self.client; @@ -257,7 +252,7 @@ impl EthClient BlockTransactions::Full(block.view().localized_transactions().into_iter().map(|t| Transaction::from_localized(t, self.eip86_transition)).collect()), + true => BlockTransactions::Full(block.view().localized_transactions().into_iter().map(|t| Transaction::from_localized(t)).collect()), false => BlockTransactions::Hashes(block.transaction_hashes().into_iter().map(Into::into).collect()), }, extra_data: Bytes::new(view.extra_data()), @@ -271,7 +266,7 @@ impl EthClient Result> { let client_transaction = |id| match self.client.transaction(id) { - Some(t) => Ok(Some(Transaction::from_localized(t, self.eip86_transition))), + Some(t) => Ok(Some(Transaction::from_localized(t))), None => Ok(None), }; @@ -308,7 +303,7 @@ impl EthClient EthClient Result> { - let store = self.account_provider()?; - store + self.accounts .note_dapp_used(dapp.clone()) - .and_then(|_| store.dapp_addresses(dapp)) + .and_then(|_| self.accounts.dapp_addresses(dapp)) .map_err(|e| errors::account("Could not fetch accounts.", e)) } @@ -495,7 +489,6 @@ impl Eth for EthClient< _ => (false, None, None), }; - if warping || is_major_importing(Some(status.state), client.queue_info()) { let chain_info = client.chain_info(); let current_block = U256::from(chain_info.best_block_number); @@ -617,11 +610,9 @@ impl 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()) })) @@ -665,10 +656,9 @@ impl Eth for EthClient< fn transaction_by_hash(&self, hash: RpcH256) -> BoxFuture> { let hash: H256 = hash.into(); - let block_number = self.client.chain_info().best_block_number; let tx = try_bf!(self.transaction(PendingTransactionId::Hash(hash))).or_else(|| { self.miner.transaction(&hash) - .map(|t| Transaction::from_pending(t.pending().clone(), block_number + 1, self.eip86_transition)) + .map(|t| Transaction::from_pending(t.pending().clone())) }); Box::new(future::ok(tx)) @@ -751,9 +741,11 @@ impl Eth for EthClient< // check if we're still syncing and return empty strings in that case { - //TODO: check if initial sync is complete here - //let sync = self.sync; - if /*sync.status().state != SyncState::Idle ||*/ self.client.queue_info().total_queue_size() > MAX_QUEUE_SIZE_TO_MINE_ON { + let sync_status = self.sync.status(); + let queue_info = self.client.queue_info(); + let total_queue_size = queue_info.total_queue_size(); + + if is_major_importing(Some(sync_status.state), queue_info) || total_queue_size > MAX_QUEUE_SIZE_TO_MINE_ON { trace!(target: "miner", "Syncing. Cannot give any work."); return Err(errors::no_work()); } @@ -833,6 +825,7 @@ impl Eth for EthClient< &*self.client, &*self.miner, signed_transaction.into(), + false ) }) .map(Into::into) diff --git a/rpc/src/v1/impls/eth_filter.rs b/rpc/src/v1/impls/eth_filter.rs index 6ca1c355f3047bb9d90a3e66bae0a516c070e077..926439cfc918caa9f624664c6d0d16a7d5b534ab 100644 --- a/rpc/src/v1/impls/eth_filter.rs +++ b/rpc/src/v1/impls/eth_filter.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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. @@ -39,10 +39,10 @@ pub trait Filterable { fn best_block_number(&self) -> u64; /// Get a block hash by block id. - fn block_hash(&self, id: BlockId) -> Option; + 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,23 +51,26 @@ 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); } /// Eth filter rpc implementation for a full node. pub struct EthFilterClient { client: Arc, miner: Arc, - polls: Mutex>, + polls: Mutex>, } impl EthFilterClient { /// Creates new Eth filter client. - pub fn new(client: Arc, miner: Arc) -> Self { + pub fn new(client: Arc, miner: Arc, poll_lifetime: u32) -> Self { EthFilterClient { client: client, miner: miner, - polls: Mutex::new(PollManager::new()), + polls: Mutex::new(PollManager::new(poll_lifetime)), } } } @@ -80,15 +83,12 @@ impl Filterable for EthFilterClient where self.client.chain_info().best_block_number } - fn block_hash(&self, id: BlockId) -> Option { - self.client.block_hash(id).map(Into::into) + fn block_hash(&self, id: BlockId) -> Option { + self.client.block_hash(id) } - fn pending_transactions_hashes(&self) -> Vec { - self.miner.ready_transactions(&*self.client) - .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> { @@ -99,126 +99,165 @@ 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> { + let mut route = Vec::new(); + + let mut current_block_hash = block_hash; + let mut current_block_header = self.client.block_header(BlockId::Hash(current_block_hash))?; + while current_block_hash != self.client.block_hash(BlockId::Number(current_block_header.number()))? { + route.push(current_block_hash); + current_block_hash = current_block_header.parent_hash(); + current_block_header = self.client.block_header(BlockId::Hash(current_block_hash))?; + } + + Some(route) + }; + + let route = inner().unwrap_or_default(); + let route_len = route.len() as u64; + (route.into_iter().flat_map(|block_hash| { + let mut filter = filter.clone(); + filter.from_block = BlockId::Hash(block_hash); + filter.to_block = filter.from_block; + + self.client.logs(filter).into_iter().map(|log| { + let mut log: Log = log.into(); + log.log_type = "removed".into(); + log.removed = true; + + log + }) + }).collect(), route_len) + } +} 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, 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)) - .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 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(); - 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; - - // retrieve logs in range from_block..min(BlockId::Latest..to_block) - let limit = filter.limit; - Either::B(self.logs(filter) - .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 _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/eth_pubsub.rs b/rpc/src/v1/impls/eth_pubsub.rs index c0789910c335471498a03b1657ff4b0bc6f56778..9f592b1fa79eb183a86e8254b7a2ff79bd1d37b5 100644 --- a/rpc/src/v1/impls/eth_pubsub.rs +++ b/rpc/src/v1/impls/eth_pubsub.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -175,7 +175,7 @@ impl ChainNotificationHandler { } /// Notify all subscribers about new transaction hashes. - pub fn new_transactions(&self, hashes: &[H256]) { + pub fn notify_new_transactions(&self, hashes: &[H256]) { for subscriber in self.transactions_subscribers.read().values() { for hash in hashes { Self::notify(&self.remote, subscriber, pubsub::Result::TransactionHash((*hash).into())); @@ -256,6 +256,7 @@ impl ChainNotify for ChainNotificationHandler { &ChainRouteType::Retracted => Ok(self.client.logs(filter).into_iter().map(Into::into).map(|mut log: Log| { log.log_type = "removed".into(); + log.removed = true; log }).collect()), } diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index 10ad024f244fed00bbd5ee9984aa251cba20a456..042720c5cae475b04e273461e464367e7d8cfbcf 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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,8 @@ pub struct EthClient { transaction_queue: Arc>, accounts: Arc, cache: Arc>, - polls: Mutex>, + polls: Mutex>, + poll_lifetime: u32, gas_price_percentile: usize, } @@ -92,7 +94,8 @@ impl Clone for EthClient { transaction_queue: self.transaction_queue.clone(), accounts: self.accounts.clone(), cache: self.cache.clone(), - polls: Mutex::new(PollManager::new()), + polls: Mutex::new(PollManager::new(self.poll_lifetime)), + poll_lifetime: self.poll_lifetime, gas_price_percentile: self.gas_price_percentile, } } @@ -109,6 +112,7 @@ impl EthClient { accounts: Arc, cache: Arc>, gas_price_percentile: usize, + poll_lifetime: u32 ) -> Self { EthClient { sync, @@ -117,7 +121,8 @@ impl EthClient { transaction_queue, accounts, cache, - polls: Mutex::new(PollManager::new()), + polls: Mutex::new(PollManager::new(poll_lifetime)), + poll_lifetime, gas_price_percentile, } } @@ -137,7 +142,6 @@ impl EthClient { fn rich_block(&self, id: BlockId, include_txs: bool) -> BoxFuture { let (on_demand, sync) = (self.on_demand.clone(), self.sync.clone()); let (client, engine) = (self.client.clone(), self.client.engine().clone()); - let eip86_transition = self.client.eip86_transition(); // helper for filling out a rich block once we've got a block and a score. let fill_rich = move |block: encoded::Block, score: Option| { @@ -164,7 +168,7 @@ impl EthClient { seal_fields: header.seal().into_iter().cloned().map(Into::into).collect(), uncles: block.uncle_hashes().into_iter().map(Into::into).collect(), transactions: match include_txs { - true => BlockTransactions::Full(block.view().localized_transactions().into_iter().map(|t| Transaction::from_localized(t, eip86_transition)).collect()), + true => BlockTransactions::Full(block.view().localized_transactions().into_iter().map(|t| Transaction::from_localized(t)).collect()), _ => BlockTransactions::Hashes(block.transaction_hashes().into_iter().map(Into::into).collect()), }, extra_data: Bytes::new(header.extra_data().clone()), @@ -414,40 +418,34 @@ impl Eth for EthClient { fn transaction_by_hash(&self, hash: RpcH256) -> BoxFuture> { let hash = hash.into(); - let eip86 = self.client.eip86_transition(); { let tx_queue = self.transaction_queue.read(); if let Some(tx) = tx_queue.get(&hash) { return Box::new(future::ok(Some(Transaction::from_pending( tx.clone(), - self.client.chain_info().best_block_number, - eip86, )))); } } - Box::new(self.fetcher().transaction_by_hash(hash, eip86).map(|x| x.map(|(tx, _)| tx))) + Box::new(self.fetcher().transaction_by_hash(hash).map(|x| x.map(|(tx, _)| tx))) } fn transaction_by_block_hash_and_index(&self, hash: RpcH256, idx: Index) -> BoxFuture> { - let eip86 = self.client.eip86_transition(); Box::new(self.fetcher().block(BlockId::Hash(hash.into())).map(move |block| { - light_fetch::extract_transaction_at_index(block, idx.value(), eip86) + light_fetch::extract_transaction_at_index(block, idx.value()) })) } fn transaction_by_block_number_and_index(&self, num: BlockNumber, idx: Index) -> BoxFuture> { - let eip86 = self.client.eip86_transition(); Box::new(self.fetcher().block(Self::num_to_id(num)).map(move |block| { - light_fetch::extract_transaction_at_index(block, idx.value(), eip86) + light_fetch::extract_transaction_at_index(block, idx.value()) })) } fn transaction_receipt(&self, hash: RpcH256) -> BoxFuture> { - let eip86 = self.client.eip86_transition(); let fetcher = self.fetcher(); - Box::new(fetcher.transaction_by_hash(hash.clone().into(), eip86).and_then(move |tx| { + Box::new(fetcher.transaction_by_hash(hash.clone().into()).and_then(move |tx| { // the block hash included in the transaction object here has // already been checked for canonicality and whether it contains // the transaction. @@ -529,12 +527,12 @@ impl Eth for EthClient { impl Filterable for EthClient { fn best_block_number(&self) -> u64 { self.client.chain_info().best_block_number } - fn block_hash(&self, id: BlockId) -> Option { - self.client.block_hash(id).map(Into::into) + fn block_hash(&self, id: BlockId) -> Option<::ethereum_types::H256> { + 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> { @@ -545,9 +543,13 @@ impl Filterable for EthClient { Vec::new() // light clients don't mine. } - fn polls(&self) -> &Mutex> { + fn polls(&self) -> &Mutex> { &self.polls } + + fn removed_logs(&self, _block_hash: ::ethereum_types::H256, _filter: &EthcoreFilter) -> (Vec, u64) { + (Default::default(), 0) + } } fn extract_uncle_at_index(block: encoded::Block, index: Index, client: Arc) -> Option { diff --git a/rpc/src/v1/impls/light/mod.rs b/rpc/src/v1/impls/light/mod.rs index 38ba2438e24ee49c9349ed571fd78efdb54d963e..40f1df89907b46f05da3a7eacfe722d2f03f662f 100644 --- a/rpc/src/v1/impls/light/mod.rs +++ b/rpc/src/v1/impls/light/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/light/net.rs b/rpc/src/v1/impls/light/net.rs index 1b374247a3757d5cb82b76abc87b02a8c836568c..4dbc9d1908534952a9b8617cabc6634bba5a52ce 100644 --- a/rpc/src/v1/impls/light/net.rs +++ b/rpc/src/v1/impls/light/net.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index 025538fc427d512b14b975977ac6398bbf2d225c..2045a4a595f2c138bba43bddb4239d2b14979ac3 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -26,7 +26,6 @@ use ethstore::random_phrase; use sync::LightSyncProvider; use ethcore::account_provider::AccountProvider; use ethcore_logger::RotatingLogger; -use node_health::{NodeHealth, Health}; use ethcore::ids::BlockId; use light::client::LightChainClient; @@ -56,11 +55,8 @@ pub struct ParityClient { accounts: Arc, logger: Arc, settings: Arc, - health: NodeHealth, signer: Option>, - dapps_address: Option, ws_address: Option, - eip86_transition: u64, gas_price_percentile: usize, } @@ -72,9 +68,7 @@ impl ParityClient { accounts: Arc, logger: Arc, settings: Arc, - health: NodeHealth, signer: Option>, - dapps_address: Option, ws_address: Option, gas_price_percentile: usize, ) -> Self { @@ -83,11 +77,8 @@ impl ParityClient { accounts, logger, settings, - health, signer, - dapps_address, ws_address, - eip86_transition: client.eip86_transition(), client, gas_price_percentile, } @@ -264,13 +255,14 @@ impl Parity for ParityClient { .map(Into::into) } - fn pending_transactions(&self) -> Result> { + fn pending_transactions(&self, limit: Trailing) -> Result> { let txq = self.light_dispatch.transaction_queue.read(); let chain_info = self.light_dispatch.client.chain_info(); Ok( txq.ready_transactions(chain_info.best_block_number, chain_info.best_block_timestamp) .into_iter() - .map(|tx| Transaction::from_pending(tx, chain_info.best_block_number, self.eip86_transition)) + .take(limit.unwrap_or_else(usize::max_value)) + .map(|tx| Transaction::from_pending(tx)) .collect::>() ) } @@ -285,7 +277,7 @@ impl Parity for ParityClient { current .into_iter() .chain(future.into_iter()) - .map(|tx| Transaction::from_pending(tx, chain_info.best_block_number, self.eip86_transition)) + .map(|tx| Transaction::from_pending(tx)) .collect::>() ) } @@ -296,7 +288,7 @@ impl Parity for ParityClient { Ok( txq.future_transactions(chain_info.best_block_number, chain_info.best_block_timestamp) .into_iter() - .map(|tx| Transaction::from_pending(tx, chain_info.best_block_number, self.eip86_transition)) + .map(|tx| Transaction::from_pending(tx)) .collect::>() ) } @@ -304,8 +296,8 @@ impl Parity for ParityClient { fn pending_transactions_stats(&self) -> Result> { let stats = self.light_dispatch.sync.transactions_stats(); Ok(stats.into_iter() - .map(|(hash, stats)| (hash.into(), stats.into())) - .collect() + .map(|(hash, stats)| (hash.into(), stats.into())) + .collect() ) } @@ -328,11 +320,6 @@ impl Parity for ParityClient { Ok(map) } - fn dapps_url(&self) -> Result { - helpers::to_url(&self.dapps_address) - .ok_or_else(|| errors::dapps_disabled()) - } - fn ws_url(&self) -> Result { helpers::to_url(&self.ws_address) .ok_or_else(|| errors::ws_disabled()) @@ -439,9 +426,4 @@ impl Parity for ParityClient { fn call(&self, _meta: Self::Metadata, _requests: Vec, _block: Trailing) -> Result> { Err(errors::light_unimplemented(None)) } - - fn node_health(&self) -> BoxFuture { - Box::new(self.health.health() - .map_err(|err| errors::internal("Health API failure.", err))) - } } diff --git a/rpc/src/v1/impls/light/parity_set.rs b/rpc/src/v1/impls/light/parity_set.rs index 76c33cf4589ae4f18668400add623ccc21f51455..6eadea43ab5a5abe0c58ea880bdc1c7999d120c8 100644 --- a/rpc/src/v1/impls/light/parity_set.rs +++ b/rpc/src/v1/impls/light/parity_set.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -27,25 +27,22 @@ use hash::keccak_buffer; use jsonrpc_core::{Result, BoxFuture}; use jsonrpc_core::futures::Future; -use v1::helpers::dapps::DappsService; use v1::helpers::errors; use v1::traits::ParitySet; -use v1::types::{Bytes, H160, H256, U256, ReleaseInfo, Transaction, LocalDapp}; +use v1::types::{Bytes, H160, H256, U256, ReleaseInfo, Transaction}; /// Parity-specific rpc interface for operations altering the settings. pub struct ParitySetClient { net: Arc, - dapps: Option>, fetch: F, pool: CpuPool, } impl ParitySetClient { /// Creates new `ParitySetClient` with given `Fetch`. - pub fn new(net: Arc, dapps: Option>, fetch: F, p: CpuPool) -> Self { + pub fn new(net: Arc, fetch: F, p: CpuPool) -> Self { ParitySetClient { net: net, - dapps: dapps, fetch: fetch, pool: p, } @@ -140,14 +137,6 @@ impl ParitySet for ParitySetClient { Box::new(self.pool.spawn(future)) } - fn dapps_refresh(&self) -> Result { - self.dapps.as_ref().map(|dapps| dapps.refresh_local_dapps()).ok_or_else(errors::dapps_disabled) - } - - fn dapps_list(&self) -> Result> { - self.dapps.as_ref().map(|dapps| dapps.list_dapps()).ok_or_else(errors::dapps_disabled) - } - fn upgrade_ready(&self) -> Result> { Err(errors::light_unimplemented(None)) } diff --git a/rpc/src/v1/impls/light/trace.rs b/rpc/src/v1/impls/light/trace.rs index 1d2c7fcaa0ade2609598e33d38ca6a79facdb3ca..80cc63a4083e0e19d79334458759d7ae080a99f9 100644 --- a/rpc/src/v1/impls/light/trace.rs +++ b/rpc/src/v1/impls/light/trace.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -21,7 +21,7 @@ use jsonrpc_macros::Trailing; use v1::Metadata; use v1::traits::Traces; use v1::helpers::errors; -use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, TraceOptions, H256}; +use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, TraceResultsWithTransactionHash, TraceOptions, H256}; /// Traces api implementation. // TODO: all calling APIs should be possible w. proved remote TX execution. @@ -62,7 +62,7 @@ impl Traces for TracesClient { Err(errors::light_unimplemented(None)) } - fn replay_block_transactions(&self, _block_number: BlockNumber, _flags: TraceOptions) -> Result> { + fn replay_block_transactions(&self, _block_number: BlockNumber, _flags: TraceOptions) -> Result> { Err(errors::light_unimplemented(None)) } } diff --git a/rpc/src/v1/impls/mod.rs b/rpc/src/v1/impls/mod.rs index 4edaf6bcd2722742d76cb102d2926aa858b301bd..1349147207dbaf624a6ac77a2c617819d3358d9e 100644 --- a/rpc/src/v1/impls/mod.rs +++ b/rpc/src/v1/impls/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/net.rs b/rpc/src/v1/impls/net.rs index 3f42f01b9479d2b2e89a5994da67332ad92f8153..74521d81356e200f34e6c8be025d1ca3bc1828de 100644 --- a/rpc/src/v1/impls/net.rs +++ b/rpc/src/v1/impls/net.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index f5d4a58949e1ece604553fc6c24a4ffc20f1cf66..2bdf09df48652475cc7e220440fcbc7f93f4ca0f 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -30,14 +30,11 @@ use ethcore::account_provider::AccountProvider; use ethcore::client::{BlockChainClient, StateClient, Call}; use ethcore::ids::BlockId; use ethcore::miner::{self, MinerService}; -use ethcore::mode::Mode; use ethcore::state::StateInfo; use ethcore_logger::RotatingLogger; -use node_health::{NodeHealth, Health}; use updater::{Service as UpdateService}; - use jsonrpc_core::{BoxFuture, Result}; -use jsonrpc_core::futures::{future, Future}; +use jsonrpc_core::futures::future; use jsonrpc_macros::Trailing; use v1::helpers::{self, errors, fake_sign, ipfs, SigningQueue, SignerService, NetworkSettings}; use v1::metadata::Metadata; @@ -54,20 +51,17 @@ use v1::types::{ use Host; /// Parity implementation. -pub struct ParityClient { +pub struct ParityClient { client: Arc, miner: Arc, updater: Arc, sync: Arc, net: Arc, - health: NodeHealth, accounts: Arc, logger: Arc, settings: Arc, signer: Option>, - dapps_address: Option, ws_address: Option, - eip86_transition: u64, } impl ParityClient where @@ -80,37 +74,25 @@ impl ParityClient where sync: Arc, updater: Arc, net: Arc, - health: NodeHealth, accounts: Arc, logger: Arc, settings: Arc, signer: Option>, - dapps_address: Option, ws_address: Option, ) -> Self { - let eip86_transition = client.eip86_transition(); ParityClient { client, miner, sync, updater, net, - health, accounts, logger, settings, signer, - dapps_address, ws_address, - eip86_transition, } } - - /// Attempt to get the `Arc`, errors if provider was not - /// set. - fn account_provider(&self) -> Result> { - Ok(self.accounts.clone()) - } } impl Parity for ParityClient where @@ -124,15 +106,14 @@ impl Parity for ParityClient where fn accounts_info(&self, dapp: Trailing) -> Result> { let dapp = dapp.unwrap_or_default(); - let store = self.account_provider()?; - let dapp_accounts = store + let dapp_accounts = self.accounts .note_dapp_used(dapp.clone().into()) - .and_then(|_| store.dapp_addresses(dapp.into())) + .and_then(|_| self.accounts.dapp_addresses(dapp.into())) .map_err(|e| errors::account("Could not fetch accounts.", e))? .into_iter().collect::>(); - let info = store.accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?; - let other = store.addresses_info(); + let info = self.accounts.accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?; + let other = self.accounts.addresses_info(); Ok(info .into_iter() @@ -144,8 +125,7 @@ impl Parity for ParityClient where } fn hardware_accounts_info(&self) -> Result> { - let store = self.account_provider()?; - let info = store.hardware_accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?; + let info = self.accounts.hardware_accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?; Ok(info .into_iter() .map(|(a, v)| (H160::from(a), HwAccountInfo { name: v.name, manufacturer: v.meta })) @@ -154,14 +134,13 @@ impl Parity for ParityClient where } fn locked_hardware_accounts_info(&self) -> Result> { - let store = self.account_provider()?; - Ok(store.locked_hardware_accounts().map_err(|e| errors::account("Error communicating with hardware wallet.", e))?) + self.accounts.locked_hardware_accounts().map_err(|e| errors::account("Error communicating with hardware wallet.", e)) } fn default_account(&self, meta: Self::Metadata) -> Result { let dapp_id = meta.dapp_id(); - Ok(self.account_provider()? + Ok(self.accounts .dapp_default_address(dapp_id.into()) .map(Into::into) .ok() @@ -313,25 +292,27 @@ impl Parity for ParityClient where .map(Into::into) } - fn pending_transactions(&self) -> Result> { - let block_number = self.client.chain_info().best_block_number; - let ready_transactions = self.miner.ready_transactions(&*self.client); + fn pending_transactions(&self, limit: Trailing) -> Result> { + let ready_transactions = self.miner.ready_transactions( + &*self.client, + limit.unwrap_or_else(usize::max_value), + miner::PendingOrdering::Priority, + ); Ok(ready_transactions - .into_iter() - .map(|t| Transaction::from_pending(t.pending().clone(), block_number, self.eip86_transition)) - .collect() - ) + .into_iter() + .map(|t| Transaction::from_pending(t.pending().clone())) + .collect() + ) } fn all_transactions(&self) -> Result> { - let block_number = self.client.chain_info().best_block_number; let all_transactions = self.miner.queued_transactions(); Ok(all_transactions - .into_iter() - .map(|t| Transaction::from_pending(t.pending().clone(), block_number, self.eip86_transition)) - .collect() + .into_iter() + .map(|t| Transaction::from_pending(t.pending().clone())) + .collect() ) } @@ -342,26 +323,20 @@ impl Parity for ParityClient where fn pending_transactions_stats(&self) -> Result> { let stats = self.sync.transactions_stats(); Ok(stats.into_iter() - .map(|(hash, stats)| (hash.into(), stats.into())) - .collect() + .map(|(hash, stats)| (hash.into(), stats.into())) + .collect() ) } fn local_transactions(&self) -> Result> { let transactions = self.miner.local_transactions(); - let block_number = self.client.chain_info().best_block_number; Ok(transactions - .into_iter() - .map(|(hash, status)| (hash.into(), LocalTransactionStatus::from(status, block_number, self.eip86_transition))) - .collect() + .into_iter() + .map(|(hash, status)| (hash.into(), LocalTransactionStatus::from(status))) + .collect() ) } - fn dapps_url(&self) -> Result { - helpers::to_url(&self.dapps_address) - .ok_or_else(|| errors::dapps_disabled()) - } - fn ws_url(&self) -> Result { helpers::to_url(&self.ws_address) .ok_or_else(|| errors::ws_disabled()) @@ -374,12 +349,7 @@ impl Parity for ParityClient where } fn mode(&self) -> Result { - Ok(match self.client.mode() { - Mode::Off => "offline", - Mode::Dark(..) => "dark", - Mode::Passive(..) => "passive", - Mode::Active => "active", - }.into()) + Ok(self.client.mode().to_string()) } fn enode(&self) -> Result { @@ -486,9 +456,4 @@ impl Parity for ParityClient where .map(|res| res.into_iter().map(|res| res.output.into()).collect()) .map_err(errors::call) } - - fn node_health(&self) -> BoxFuture { - Box::new(self.health.health() - .map_err(|err| errors::internal("Health API failure.", err))) - } } diff --git a/rpc/src/v1/impls/parity_accounts.rs b/rpc/src/v1/impls/parity_accounts.rs index adb97db28de808747c801b9f257adf97ae75b67d..f9be594ad8b4d0658460fa20a2b2d6a0dee21523 100644 --- a/rpc/src/v1/impls/parity_accounts.rs +++ b/rpc/src/v1/impls/parity_accounts.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -22,11 +22,11 @@ use ethereum_types::Address; use ethkey::{Brain, Generator, Secret}; use ethstore::KeyFile; use ethcore::account_provider::AccountProvider; - use jsonrpc_core::Result; use v1::helpers::errors; use v1::traits::ParityAccounts; use v1::types::{H160 as RpcH160, H256 as RpcH256, H520 as RpcH520, DappId, Derive, DeriveHierarchical, DeriveHash, ExtAccountInfo}; +use ethkey::Password; /// Account management (personal) rpc implementation. pub struct ParityAccountsClient { @@ -40,19 +40,12 @@ impl ParityAccountsClient { accounts: store.clone(), } } - - /// Attempt to get the `Arc`, errors if provider was not - /// set. - fn account_provider(&self) -> Result> { - Ok(self.accounts.clone()) - } } impl ParityAccounts for ParityAccountsClient { fn all_accounts_info(&self) -> Result> { - let store = self.account_provider()?; - let info = store.accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?; - let other = store.addresses_info(); + let info = self.accounts.accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?; + let other = self.accounts.addresses_info(); let account_iter = info .into_iter() @@ -81,235 +74,204 @@ impl ParityAccounts for ParityAccountsClient { Ok(accounts) } - fn new_account_from_phrase(&self, phrase: String, pass: String) -> Result { - let store = self.account_provider()?; - + fn new_account_from_phrase(&self, phrase: String, pass: Password) -> Result { let brain = Brain::new(phrase).generate().unwrap(); - store.insert_account(brain.secret().clone(), &pass) + self.accounts.insert_account(brain.secret().clone(), &pass) .map(Into::into) .map_err(|e| errors::account("Could not create account.", e)) } - fn new_account_from_wallet(&self, json: String, pass: String) -> Result { - let store = self.account_provider()?; - - store.import_presale(json.as_bytes(), &pass) - .or_else(|_| store.import_wallet(json.as_bytes(), &pass, true)) + fn new_account_from_wallet(&self, json: String, pass: Password) -> Result { + self.accounts.import_presale(json.as_bytes(), &pass) + .or_else(|_| self.accounts.import_wallet(json.as_bytes(), &pass, true)) .map(Into::into) .map_err(|e| errors::account("Could not create account.", e)) } - fn new_account_from_secret(&self, secret: RpcH256, pass: String) -> Result { - let store = self.account_provider()?; - + fn new_account_from_secret(&self, secret: RpcH256, pass: Password) -> Result { let secret = Secret::from_unsafe_slice(&secret.0) .map_err(|e| errors::account("Could not create account.", e))?; - store.insert_account(secret, &pass) + self.accounts.insert_account(secret, &pass) .map(Into::into) .map_err(|e| errors::account("Could not create account.", e)) } - fn test_password(&self, account: RpcH160, password: String) -> Result { + fn test_password(&self, account: RpcH160, password: Password) -> Result { let account: Address = account.into(); - self.account_provider()? + self.accounts .test_password(&account, &password) .map_err(|e| errors::account("Could not fetch account info.", e)) } - fn change_password(&self, account: RpcH160, password: String, new_password: String) -> Result { + fn change_password(&self, account: RpcH160, password: Password, new_password: Password) -> Result { let account: Address = account.into(); - self.account_provider()? + self.accounts .change_password(&account, password, new_password) .map(|_| true) .map_err(|e| errors::account("Could not fetch account info.", e)) } - fn kill_account(&self, account: RpcH160, password: String) -> Result { + fn kill_account(&self, account: RpcH160, password: Password) -> Result { let account: Address = account.into(); - self.account_provider()? + self.accounts .kill_account(&account, &password) .map(|_| true) .map_err(|e| errors::account("Could not delete account.", e)) } fn remove_address(&self, addr: RpcH160) -> Result { - let store = self.account_provider()?; let addr: Address = addr.into(); - store.remove_address(addr); + self.accounts.remove_address(addr); Ok(true) } fn set_account_name(&self, addr: RpcH160, name: String) -> Result { - let store = self.account_provider()?; let addr: Address = addr.into(); - store.set_account_name(addr.clone(), name.clone()) - .unwrap_or_else(|_| store.set_address_name(addr, name)); + self.accounts.set_account_name(addr.clone(), name.clone()) + .unwrap_or_else(|_| self.accounts.set_address_name(addr, name)); Ok(true) } fn set_account_meta(&self, addr: RpcH160, meta: String) -> Result { - let store = self.account_provider()?; let addr: Address = addr.into(); - store.set_account_meta(addr.clone(), meta.clone()) - .unwrap_or_else(|_| store.set_address_meta(addr, meta)); + self.accounts.set_account_meta(addr.clone(), meta.clone()) + .unwrap_or_else(|_| self.accounts.set_address_meta(addr, meta)); Ok(true) } fn set_dapp_addresses(&self, dapp: DappId, addresses: Option>) -> Result { - let store = self.account_provider()?; - - store.set_dapp_addresses(dapp.into(), addresses.map(into_vec)) + self.accounts.set_dapp_addresses(dapp.into(), addresses.map(into_vec)) .map_err(|e| errors::account("Couldn't set dapp addresses.", e)) .map(|_| true) } fn dapp_addresses(&self, dapp: DappId) -> Result> { - let store = self.account_provider()?; - - store.dapp_addresses(dapp.into()) + self.accounts.dapp_addresses(dapp.into()) .map_err(|e| errors::account("Couldn't get dapp addresses.", e)) .map(into_vec) } fn set_dapp_default_address(&self, dapp: DappId, address: RpcH160) -> Result { - let store = self.account_provider()?; - - store.set_dapp_default_address(dapp.into(), address.into()) + self.accounts.set_dapp_default_address(dapp.into(), address.into()) .map_err(|e| errors::account("Couldn't set dapp default address.", e)) .map(|_| true) } fn dapp_default_address(&self, dapp: DappId) -> Result { - let store = self.account_provider()?; - - store.dapp_default_address(dapp.into()) + self.accounts.dapp_default_address(dapp.into()) .map_err(|e| errors::account("Couldn't get dapp default address.", e)) .map(Into::into) } fn set_new_dapps_addresses(&self, addresses: Option>) -> Result { - let store = self.account_provider()?; - - store + self.accounts .set_new_dapps_addresses(addresses.map(into_vec)) .map_err(|e| errors::account("Couldn't set dapps addresses.", e)) .map(|_| true) } fn new_dapps_addresses(&self) -> Result>> { - let store = self.account_provider()?; - - store.new_dapps_addresses() + self.accounts.new_dapps_addresses() .map_err(|e| errors::account("Couldn't get dapps addresses.", e)) .map(|accounts| accounts.map(into_vec)) } fn set_new_dapps_default_address(&self, address: RpcH160) -> Result { - let store = self.account_provider()?; - - store.set_new_dapps_default_address(address.into()) + self.accounts.set_new_dapps_default_address(address.into()) .map_err(|e| errors::account("Couldn't set new dapps default address.", e)) .map(|_| true) } fn new_dapps_default_address(&self) -> Result { - let store = self.account_provider()?; - - store.new_dapps_default_address() + self.accounts.new_dapps_default_address() .map_err(|e| errors::account("Couldn't get new dapps default address.", e)) .map(Into::into) } fn recent_dapps(&self) -> Result> { - let store = self.account_provider()?; - - store.recent_dapps() + self.accounts.recent_dapps() .map_err(|e| errors::account("Couldn't get recent dapps.", e)) .map(|map| map.into_iter().map(|(k, v)| (k.into(), v)).collect()) } fn import_geth_accounts(&self, addresses: Vec) -> Result> { - let store = self.account_provider()?; - - store + self.accounts .import_geth_accounts(into_vec(addresses), false) .map(into_vec) .map_err(|e| errors::account("Couldn't import Geth accounts", e)) } fn geth_accounts(&self) -> Result> { - let store = self.account_provider()?; - - Ok(into_vec(store.list_geth_accounts(false))) + Ok(into_vec(self.accounts.list_geth_accounts(false))) } - fn create_vault(&self, name: String, password: String) -> Result { - self.account_provider()? + fn create_vault(&self, name: String, password: Password) -> Result { + self.accounts .create_vault(&name, &password) .map_err(|e| errors::account("Could not create vault.", e)) .map(|_| true) } - fn open_vault(&self, name: String, password: String) -> Result { - self.account_provider()? + fn open_vault(&self, name: String, password: Password) -> Result { + self.accounts .open_vault(&name, &password) .map_err(|e| errors::account("Could not open vault.", e)) .map(|_| true) } fn close_vault(&self, name: String) -> Result { - self.account_provider()? + self.accounts .close_vault(&name) .map_err(|e| errors::account("Could not close vault.", e)) .map(|_| true) } fn list_vaults(&self) -> Result> { - self.account_provider()? + self.accounts .list_vaults() .map_err(|e| errors::account("Could not list vaults.", e)) } fn list_opened_vaults(&self) -> Result> { - self.account_provider()? + self.accounts .list_opened_vaults() .map_err(|e| errors::account("Could not list vaults.", e)) } - fn change_vault_password(&self, name: String, new_password: String) -> Result { - self.account_provider()? + fn change_vault_password(&self, name: String, new_password: Password) -> Result { + self.accounts .change_vault_password(&name, &new_password) .map_err(|e| errors::account("Could not change vault password.", e)) .map(|_| true) } fn change_vault(&self, address: RpcH160, new_vault: String) -> Result { - self.account_provider()? + self.accounts .change_vault(address.into(), &new_vault) .map_err(|e| errors::account("Could not change vault.", e)) .map(|_| true) } fn get_vault_meta(&self, name: String) -> Result { - self.account_provider()? + self.accounts .get_vault_meta(&name) .map_err(|e| errors::account("Could not get vault metadata.", e)) } fn set_vault_meta(&self, name: String, meta: String) -> Result { - self.account_provider()? + self.accounts .set_vault_meta(&name, &meta) .map_err(|e| errors::account("Could not update vault metadata.", e)) .map(|_| true) } - fn derive_key_index(&self, addr: RpcH160, password: String, derivation: DeriveHierarchical, save_as_account: bool) -> Result { + fn derive_key_index(&self, addr: RpcH160, password: Password, derivation: DeriveHierarchical, save_as_account: bool) -> Result { let addr: Address = addr.into(); - self.account_provider()? + self.accounts .derive_account( &addr, Some(password), @@ -320,9 +282,9 @@ impl ParityAccounts for ParityAccountsClient { .map_err(|e| errors::account("Could not derive account.", e)) } - fn derive_key_hash(&self, addr: RpcH160, password: String, derivation: DeriveHash, save_as_account: bool) -> Result { + fn derive_key_hash(&self, addr: RpcH160, password: Password, derivation: DeriveHash, save_as_account: bool) -> Result { let addr: Address = addr.into(); - self.account_provider()? + self.accounts .derive_account( &addr, Some(password), @@ -333,9 +295,9 @@ impl ParityAccounts for ParityAccountsClient { .map_err(|e| errors::account("Could not derive account.", e)) } - fn export_account(&self, addr: RpcH160, password: String) -> Result { + fn export_account(&self, addr: RpcH160, password: Password) -> Result { let addr = addr.into(); - self.account_provider()? + self.accounts .export_account( &addr, password, @@ -344,8 +306,8 @@ impl ParityAccounts for ParityAccountsClient { .map_err(|e| errors::account("Could not export account.", e)) } - fn sign_message(&self, addr: RpcH160, password: String, message: RpcH256) -> Result { - self.account_provider()? + fn sign_message(&self, addr: RpcH160, password: Password, message: RpcH256) -> Result { + self.accounts .sign( addr.into(), Some(password), @@ -356,8 +318,7 @@ impl ParityAccounts for ParityAccountsClient { } fn hardware_pin_matrix_ack(&self, path: String, pin: String) -> Result { - let store = self.account_provider()?; - Ok(store.hardware_pin_matrix_ack(&path, &pin).map_err(|e| errors::account("Error communicating with hardware wallet.", e))?) + self.accounts.hardware_pin_matrix_ack(&path, &pin).map_err(|e| errors::account("Error communicating with hardware wallet.", e)) } } diff --git a/rpc/src/v1/impls/parity_set.rs b/rpc/src/v1/impls/parity_set.rs index 612e6aa78b7bf77d2178d6737ebb98dea9478a08..9bbb7ceab1456cc302af49799512cb0372acb63c 100644 --- a/rpc/src/v1/impls/parity_set.rs +++ b/rpc/src/v1/impls/parity_set.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -17,10 +17,10 @@ /// Parity-specific rpc interface for operations altering the settings. use std::io; use std::sync::Arc; +use std::time::Duration; -use ethcore::client::BlockChainClient; +use ethcore::client::{BlockChainClient, Mode}; use ethcore::miner::MinerService; -use ethcore::mode::Mode; use sync::ManageNetwork; use fetch::{self, Fetch}; use futures_cpupool::CpuPool; @@ -29,10 +29,9 @@ use updater::{Service as UpdateService}; use jsonrpc_core::{BoxFuture, Result}; use jsonrpc_core::futures::Future; -use v1::helpers::dapps::DappsService; use v1::helpers::errors; use v1::traits::ParitySet; -use v1::types::{Bytes, H160, H256, U256, ReleaseInfo, Transaction, LocalDapp}; +use v1::types::{Bytes, H160, H256, U256, ReleaseInfo, Transaction}; /// Parity-specific rpc interface for operations altering the settings. pub struct ParitySetClient { @@ -40,10 +39,8 @@ pub struct ParitySetClient { miner: Arc, updater: Arc, net: Arc, - dapps: Option>, fetch: F, pool: CpuPool, - eip86_transition: u64, } impl ParitySetClient @@ -55,7 +52,6 @@ impl ParitySetClient miner: &Arc, updater: &Arc, net: &Arc, - dapps: Option>, fetch: F, pool: CpuPool, ) -> Self { @@ -64,10 +60,8 @@ impl ParitySetClient miner: miner.clone(), updater: updater.clone(), net: net.clone(), - dapps: dapps, fetch: fetch, pool: pool, - eip86_transition: client.eip86_transition(), } } } @@ -119,7 +113,7 @@ impl ParitySet for ParitySetClient where } fn set_engine_signer(&self, address: H160, password: String) -> Result { - self.miner.set_author(address.into(), Some(password)).map_err(Into::into).map_err(errors::password)?; + self.miner.set_author(address.into(), Some(password.into())).map_err(Into::into).map_err(errors::password)?; Ok(true) } @@ -160,8 +154,8 @@ impl ParitySet for ParitySetClient where fn set_mode(&self, mode: String) -> Result { self.client.set_mode(match mode.as_str() { "offline" => Mode::Off, - "dark" => Mode::Dark(300), - "passive" => Mode::Passive(300, 3600), + "dark" => Mode::Dark(Duration::from_secs(300)), + "passive" => Mode::Passive(Duration::from_secs(300), Duration::from_secs(3600)), "active" => Mode::Active, e => { return Err(errors::invalid_params("mode", e.to_owned())); }, }); @@ -186,14 +180,6 @@ impl ParitySet for ParitySetClient where Box::new(self.pool.spawn(future)) } - fn dapps_refresh(&self) -> Result { - self.dapps.as_ref().map(|dapps| dapps.refresh_local_dapps()).ok_or_else(errors::dapps_disabled) - } - - fn dapps_list(&self) -> Result> { - self.dapps.as_ref().map(|dapps| dapps.list_dapps()).ok_or_else(errors::dapps_disabled) - } - fn upgrade_ready(&self) -> Result> { Ok(self.updater.upgrade_ready().map(Into::into)) } @@ -203,11 +189,10 @@ impl ParitySet for ParitySetClient where } fn remove_transaction(&self, hash: H256) -> Result> { - let block_number = self.client.chain_info().best_block_number; let hash = hash.into(); Ok(self.miner.remove_transaction(&hash) - .map(|t| Transaction::from_pending(t.pending().clone(), block_number + 1, self.eip86_transition)) + .map(|t| Transaction::from_pending(t.pending().clone())) ) } } diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index da5ef983a24c586a79492f5c7c97f2f38f15bb0a..8cb98a66b1e5eafe8bdfd4e69ea728a6bc5815e8 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -55,16 +55,12 @@ impl PersonalClient { allow_perm_unlock, } } - - fn account_provider(&self) -> Result> { - Ok(self.accounts.clone()) - } } impl PersonalClient { fn do_sign_transaction(&self, meta: Metadata, request: TransactionRequest, password: String) -> BoxFuture<(PendingTransaction, D)> { let dispatcher = self.dispatcher.clone(); - let accounts = try_bf!(self.account_provider()); + let accounts = self.accounts.clone(); let default = match request.from.as_ref() { Some(account) => Ok(account.clone().into()), @@ -81,7 +77,7 @@ impl PersonalClient { Box::new(dispatcher.fill_optional_fields(request.into(), default, false) .and_then(move |filled| { let condition = filled.condition.clone().map(Into::into); - dispatcher.sign(accounts, filled, SignWith::Password(password)) + dispatcher.sign(accounts, filled, SignWith::Password(password.into())) .map(|tx| tx.into_value()) .map(move |tx| PendingTransaction::new(tx, condition)) .map(move |tx| (tx, dispatcher)) @@ -94,22 +90,19 @@ impl Personal for PersonalClient { type Metadata = Metadata; fn accounts(&self) -> Result> { - let store = self.account_provider()?; - let accounts = store.accounts().map_err(|e| errors::account("Could not fetch accounts.", e))?; + let accounts = self.accounts.accounts().map_err(|e| errors::account("Could not fetch accounts.", e))?; Ok(accounts.into_iter().map(Into::into).collect::>()) } fn new_account(&self, pass: String) -> Result { - let store = self.account_provider()?; - - store.new_account(&pass) + self.accounts.new_account(&pass.into()) .map(Into::into) .map_err(|e| errors::account("Could not create account.", e)) } fn unlock_account(&self, account: RpcH160, account_pass: String, duration: Option) -> Result { let account: Address = account.into(); - let store = self.account_provider()?; + let store = self.accounts.clone(); let duration = match duration { None => None, Some(duration) => { @@ -124,14 +117,14 @@ impl Personal for PersonalClient { }; let r = match (self.allow_perm_unlock, duration) { - (false, None) => store.unlock_account_temporarily(account, account_pass), + (false, None) => store.unlock_account_temporarily(account, account_pass.into()), (false, _) => return Err(errors::unsupported( "Time-unlocking is only supported in --geth compatibility mode.", Some("Restart your client with --geth flag or use personal_sendTransaction instead."), )), - (true, Some(0)) => store.unlock_account_permanently(account, account_pass), - (true, Some(d)) => store.unlock_account_timed(account, account_pass, Duration::from_secs(d.into())), - (true, None) => store.unlock_account_timed(account, account_pass, Duration::from_secs(300)), + (true, Some(0)) => store.unlock_account_permanently(account, account_pass.into()), + (true, Some(d)) => store.unlock_account_timed(account, account_pass.into(), Duration::from_secs(d.into())), + (true, None) => store.unlock_account_timed(account, account_pass.into(), Duration::from_secs(300)), }; match r { Ok(_) => Ok(true), @@ -141,13 +134,13 @@ impl Personal for PersonalClient { fn sign(&self, data: RpcBytes, account: RpcH160, password: String) -> BoxFuture { let dispatcher = self.dispatcher.clone(); - let accounts = try_bf!(self.account_provider()); + let accounts = self.accounts.clone(); let payload = RpcConfirmationPayload::EthSignMessage((account.clone(), data).into()); Box::new(dispatch::from_rpc(payload, account.into(), &dispatcher) .and_then(|payload| { - dispatch::execute(dispatcher, accounts, payload, dispatch::SignWith::Password(password)) + dispatch::execute(dispatcher, accounts, payload, dispatch::SignWith::Password(password.into())) }) .map(|v| v.into_value()) .then(|res| match res { diff --git a/rpc/src/v1/impls/private.rs b/rpc/src/v1/impls/private.rs index 4034d2b9a16e451b75a183938db3216a94f7919c..a1110eed1131e5387704b8b8c253dacce232101f 100644 --- a/rpc/src/v1/impls/private.rs +++ b/rpc/src/v1/impls/private.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/pubsub.rs b/rpc/src/v1/impls/pubsub.rs index 59eef19533fb005d8d10ce2c4f9d4db5456f3f80..564c8b90d5ea9e539290137269e79cc5ac8559de 100644 --- a/rpc/src/v1/impls/pubsub.rs +++ b/rpc/src/v1/impls/pubsub.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/rpc.rs b/rpc/src/v1/impls/rpc.rs index 3c76a316464a42677abfdf9c5772a6957c3b321f..9f15cc1a384bf39aa1ed5c7e954d287b9929cc16 100644 --- a/rpc/src/v1/impls/rpc.rs +++ b/rpc/src/v1/impls/rpc.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/secretstore.rs b/rpc/src/v1/impls/secretstore.rs index f85fa6f584c762040016c4a3842551291158ea32..cbb7580e6ae44b7b64b73499a841a9cf989aef28 100644 --- a/rpc/src/v1/impls/secretstore.rs +++ b/rpc/src/v1/impls/secretstore.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -29,6 +29,7 @@ use v1::helpers::secretstore::{generate_document_key, encrypt_document, decrypt_document, decrypt_document_with_shadow, ordered_servers_keccak}; use v1::traits::SecretStore; use v1::types::{H160, H256, H512, Bytes, EncryptedDocumentKey}; +use ethkey::Password; /// Parity implementation. pub struct SecretStoreClient { @@ -43,45 +44,37 @@ impl SecretStoreClient { } } - /// Attempt to get the `Arc`, errors if provider was not - /// set. - fn account_provider(&self) -> Result> { - Ok(self.accounts.clone()) - } - /// Decrypt public key using account' private key - fn decrypt_key(&self, address: H160, password: String, key: Bytes) -> Result> { - let store = self.account_provider()?; - store.decrypt(address.into(), Some(password), &DEFAULT_MAC, &key.0) + fn decrypt_key(&self, address: H160, password: Password, key: Bytes) -> Result> { + self.accounts.decrypt(address.into(), Some(password), &DEFAULT_MAC, &key.0) .map_err(|e| errors::account("Could not decrypt key.", e)) } /// Decrypt secret key using account' private key - fn decrypt_secret(&self, address: H160, password: String, key: Bytes) -> Result { + fn decrypt_secret(&self, address: H160, password: Password, key: Bytes) -> Result { self.decrypt_key(address, password, key) .and_then(|s| Secret::from_unsafe_slice(&s).map_err(|e| errors::account("invalid secret", e))) } } impl SecretStore for SecretStoreClient { - fn generate_document_key(&self, address: H160, password: String, server_key_public: H512) -> Result { - let store = self.account_provider()?; - let account_public = store.account_public(address.into(), &password) + fn generate_document_key(&self, address: H160, password: Password, server_key_public: H512) -> Result { + let account_public = self.accounts.account_public(address.into(), &password) .map_err(|e| errors::account("Could not read account public.", e))?; generate_document_key(account_public, server_key_public.into()) } - fn encrypt(&self, address: H160, password: String, key: Bytes, data: Bytes) -> Result { + fn encrypt(&self, address: H160, password: Password, key: Bytes, data: Bytes) -> Result { encrypt_document(self.decrypt_key(address, password, key)?, data.0) .map(Into::into) } - fn decrypt(&self, address: H160, password: String, key: Bytes, data: Bytes) -> Result { + fn decrypt(&self, address: H160, password: Password, key: Bytes, data: Bytes) -> Result { decrypt_document(self.decrypt_key(address, password, key)?, data.0) .map(Into::into) } - fn shadow_decrypt(&self, address: H160, password: String, decrypted_secret: H512, common_point: H512, decrypt_shadows: Vec, data: Bytes) -> Result { + fn shadow_decrypt(&self, address: H160, password: Password, decrypted_secret: H512, common_point: H512, decrypt_shadows: Vec, data: Bytes) -> Result { let mut shadows = Vec::with_capacity(decrypt_shadows.len()); for decrypt_shadow in decrypt_shadows { shadows.push(self.decrypt_secret(address.clone(), password.clone(), decrypt_shadow)?); @@ -95,9 +88,8 @@ impl SecretStore for SecretStoreClient { Ok(ordered_servers_keccak(servers_set)) } - fn sign_raw_hash(&self, address: H160, password: String, raw_hash: H256) -> Result { - let store = self.account_provider()?; - store + fn sign_raw_hash(&self, address: H160, password: Password, raw_hash: H256) -> Result { + self.accounts .sign(address.into(), Some(password), raw_hash.into()) .map(|s| Bytes::new((*s).to_vec())) .map_err(|e| errors::account("Could not sign raw hash.", e)) diff --git a/rpc/src/v1/impls/signer.rs b/rpc/src/v1/impls/signer.rs index eafa07ad4d62726d5b985f389c3c6e1fab87ef54..8ed046b88c3dad5fb4b6ec720f9c8222de19f090 100644 --- a/rpc/src/v1/impls/signer.rs +++ b/rpc/src/v1/impls/signer.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -77,25 +77,20 @@ impl SignerClient { } } - fn account_provider(&self) -> Result> { - Ok(self.accounts.clone()) - } - fn confirm_internal(&self, id: U256, modification: TransactionModification, f: F) -> BoxFuture> where F: FnOnce(D, Arc, ConfirmationPayload) -> T, T: IntoFuture, Error=Error>, T::Future: Send + 'static { let id = id.into(); - let accounts = try_bf!(self.account_provider()); let dispatcher = self.dispatcher.clone(); let signer = self.signer.clone(); - Box::new(signer.peek(&id).map(|confirmation| { - let mut payload = confirmation.payload.clone(); + Box::new(signer.take(&id).map(|sender| { + let mut payload = sender.request.payload.clone(); // Modify payload if let ConfirmationPayload::SendTransaction(ref mut request) = payload { - if let Some(sender) = modification.sender.clone() { + if let Some(sender) = modification.sender { request.from = sender.into(); // Altering sender should always reset the nonce. request.nonce = None; @@ -110,11 +105,13 @@ impl SignerClient { request.condition = condition.clone().map(Into::into); } } - let fut = f(dispatcher, accounts, payload); + let fut = f(dispatcher, self.accounts.clone(), payload); Either::A(fut.into_future().then(move |result| { // Execute if let Ok(ref response) = result { - signer.request_confirmed(id, Ok((*response).clone())); + signer.request_confirmed(sender, Ok((*response).clone())); + } else { + signer.request_untouched(sender); } result @@ -172,7 +169,7 @@ impl Signer for SignerClient { -> BoxFuture { Box::new(self.confirm_internal(id, modification, move |dis, accounts, payload| { - dispatch::execute(dis, accounts, payload, dispatch::SignWith::Password(pass)) + dispatch::execute(dis, accounts, payload, dispatch::SignWith::Password(pass.into())) }).map(|v| v.into_value())) } @@ -180,7 +177,7 @@ impl Signer for SignerClient { -> BoxFuture { Box::new(self.confirm_internal(id, modification, move |dis, accounts, payload| { - dispatch::execute(dis, accounts, payload, dispatch::SignWith::Token(token)) + dispatch::execute(dis, accounts, payload, dispatch::SignWith::Token(token.into())) }).and_then(|v| match v { WithToken::No(_) => Err(errors::internal("Unexpected response without token.", "")), WithToken::Yes(response, token) => Ok(ConfirmationResponseWithToken { @@ -193,8 +190,9 @@ impl Signer for SignerClient { fn confirm_request_raw(&self, id: U256, bytes: Bytes) -> Result { let id = id.into(); - self.signer.peek(&id).map(|confirmation| { - let result = match confirmation.payload { + self.signer.take(&id).map(|sender| { + let payload = sender.request.payload.clone(); + let result = match payload { ConfirmationPayload::SendTransaction(request) => { Self::verify_transaction(bytes, request, |pending_transaction| { self.dispatcher.dispatch_transaction(pending_transaction) @@ -223,14 +221,16 @@ impl Signer for SignerClient { }, }; if let Ok(ref response) = result { - self.signer.request_confirmed(id, Ok(response.clone())); + self.signer.request_confirmed(sender, Ok(response.clone())); + } else { + self.signer.request_untouched(sender); } result }).unwrap_or_else(|| Err(errors::invalid_params("Unknown RequestID", id))) } fn reject_request(&self, id: U256) -> Result { - let res = self.signer.request_rejected(id.into()); + let res = self.signer.take(&id.into()).map(|sender| self.signer.request_rejected(sender)); Ok(res.is_some()) } diff --git a/rpc/src/v1/impls/signing.rs b/rpc/src/v1/impls/signing.rs index 71cf18a06bb50a7afca00203e63aefeb5d21aca6..b22bbc80dd882fb6cc3f6437fe39fda50cc4ca82 100644 --- a/rpc/src/v1/impls/signing.rs +++ b/rpc/src/v1/impls/signing.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -108,12 +108,8 @@ impl SigningQueueClient { } } - fn account_provider(&self) -> Result> { - Ok(self.accounts.clone()) - } - fn dispatch(&self, payload: RpcConfirmationPayload, default_account: DefaultAccount, origin: Origin) -> BoxFuture { - let accounts = try_bf!(self.account_provider()); + let accounts = self.accounts.clone(); let default_account = match default_account { DefaultAccount::Provided(acc) => acc, DefaultAccount::ForDapp(dapp) => accounts.dapp_default_address(dapp).ok().unwrap_or_default(), @@ -143,8 +139,7 @@ impl ParitySigning for SigningQueueClient { type Metadata = Metadata; fn compose_transaction(&self, meta: Metadata, transaction: RpcTransactionRequest) -> BoxFuture { - let accounts = try_bf!(self.account_provider()); - let default_account = accounts.dapp_default_address(meta.dapp_id().into()).ok().unwrap_or_default(); + let default_account = self.accounts.dapp_default_address(meta.dapp_id().into()).ok().unwrap_or_default(); Box::new(self.dispatcher.fill_optional_fields(transaction.into(), default_account, true).map(Into::into)) } diff --git a/rpc/src/v1/impls/signing_unsafe.rs b/rpc/src/v1/impls/signing_unsafe.rs index 75f5f5e2bf2928154ad3e9282bca2f2fd7526a1b..6016cbbfc0b65428c32b3087d927300c22c0bc08 100644 --- a/rpc/src/v1/impls/signing_unsafe.rs +++ b/rpc/src/v1/impls/signing_unsafe.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -51,12 +51,8 @@ impl SigningUnsafeClient { } } - fn account_provider(&self) -> Result> { - Ok(self.accounts.clone()) - } - fn handle(&self, payload: RpcConfirmationPayload, account: DefaultAccount) -> BoxFuture { - let accounts = try_bf!(self.account_provider()); + let accounts = self.accounts.clone(); let default = match account { DefaultAccount::Provided(acc) => acc, DefaultAccount::ForDapp(dapp) => accounts.dapp_default_address(dapp).ok().unwrap_or_default(), @@ -107,7 +103,7 @@ impl ParitySigning for SigningUnsafeClient { type Metadata = Metadata; fn compose_transaction(&self, meta: Metadata, transaction: RpcTransactionRequest) -> BoxFuture { - let accounts = try_bf!(self.account_provider()); + let accounts = self.accounts.clone(); let default_account = accounts.dapp_default_address(meta.dapp_id().into()).ok().unwrap_or_default(); Box::new(self.dispatcher.fill_optional_fields(transaction.into(), default_account, true).map(Into::into)) } diff --git a/rpc/src/v1/impls/traces.rs b/rpc/src/v1/impls/traces.rs index 0130b3b9c13a362d32124918c9f94e48a56cc0c2..ee7d7154cb50e8a83d7475f12bd97fab43c20651 100644 --- a/rpc/src/v1/impls/traces.rs +++ b/rpc/src/v1/impls/traces.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -27,7 +27,7 @@ use jsonrpc_macros::Trailing; use v1::Metadata; use v1::traits::Traces; use v1::helpers::{errors, fake_sign}; -use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, TraceOptions, H256, block_number_to_id}; +use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, TraceResultsWithTransactionHash, TraceOptions, H256, block_number_to_id}; fn to_call_analytics(flags: TraceOptions) -> CallAnalytics { CallAnalytics { @@ -164,7 +164,7 @@ impl Traces for TracesClient where .map_err(errors::call) } - fn replay_block_transactions(&self, block_number: BlockNumber, flags: TraceOptions) -> Result> { + fn replay_block_transactions(&self, block_number: BlockNumber, flags: TraceOptions) -> Result> { let id = match block_number { BlockNumber::Num(num) => BlockId::Number(num), BlockNumber::Earliest => BlockId::Earliest, @@ -174,7 +174,7 @@ impl Traces for TracesClient where }; self.client.replay_block_transactions(id, to_call_analytics(flags)) - .map(|results| results.into_iter().map(TraceResults::from).collect()) + .map(|results| results.into_iter().map(TraceResultsWithTransactionHash::from).collect()) .map_err(errors::call) } } diff --git a/rpc/src/v1/impls/web3.rs b/rpc/src/v1/impls/web3.rs index 6fd6ff7a463e1d3da83100d50ee37cb8dbb5733e..aa304472856f78a506ce34b50bb0b527d873e1f8 100644 --- a/rpc/src/v1/impls/web3.rs +++ b/rpc/src/v1/impls/web3.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/informant.rs b/rpc/src/v1/informant.rs index 9a9cde3837cdd57f5c5f47ca42867fba61224557..07a70eeb10ed7a46813b7ada58a0cd5fb4e9d926 100644 --- a/rpc/src/v1/informant.rs +++ b/rpc/src/v1/informant.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/metadata.rs b/rpc/src/v1/metadata.rs index f0644d455c02e429db746c390bd86196db018dca..970ec60e486dd4b2829106dec822b5c1bff7e2f0 100644 --- a/rpc/src/v1/metadata.rs +++ b/rpc/src/v1/metadata.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/mod.rs b/rpc/src/v1/mod.rs index 154317eb2f49ed3ec19d756d9f327bcbd3f8579a..a0b74aa5aa4f57e1fc694a152e7818208690e40f 100644 --- a/rpc/src/v1/mod.rs +++ b/rpc/src/v1/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -53,9 +53,3 @@ pub mod signer { pub use super::helpers::{SigningQueue, SignerService, ConfirmationsQueue}; pub use super::types::{ConfirmationRequest, TransactionModification, U256, TransactionCondition}; } - -/// Dapps integration utilities -pub mod dapps { - pub use super::helpers::dapps::DappsService; - pub use super::types::LocalDapp; -} diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index e0931ae6bfa8dc0edb2743930260466ea038ea03..217e032902cef8a183402ed9fcd74259b51340b2 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -1,4 +1,4 @@ -// Copyright 2016 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -20,17 +20,16 @@ use std::sync::Arc; use ethereum_types::{H256, Address}; use ethcore::account_provider::AccountProvider; -use ethcore::block::Block; use ethcore::client::{BlockChainClient, Client, ClientConfig, ChainInfo, ImportBlock}; use ethcore::ethereum; use ethcore::ids::BlockId; use ethcore::miner::Miner; use ethcore::spec::{Genesis, Spec}; -use ethcore::views::BlockView; +use ethcore::test_helpers; +use ethcore::verification::queue::kind::blocks::Unverified; use ethjson::blockchain::BlockChain; use ethjson::state::test::ForkSpec; use io::IoChannel; -use kvdb_memorydb; use miner::external::ExternalMiner; use parking_lot::Mutex; @@ -85,9 +84,9 @@ impl EthTester { fn from_chain(chain: &BlockChain) -> Self { let tester = Self::from_spec(make_spec(chain)); - for b in &chain.blocks_rlp() { - if Block::is_good(&b) { - let _ = tester.client.import_block(b.clone()); + for b in chain.blocks_rlp() { + if let Ok(block) = Unverified::from_rlp(b) { + let _ = tester.client.import_block(block); tester.client.flush_queue(); tester.client.import_verified_blocks(); } @@ -108,7 +107,7 @@ impl EthTester { let client = Client::new( ClientConfig::default(), &spec, - Arc::new(kvdb_memorydb::create(::ethcore::db::NUM_COLUMNS.unwrap_or(0))), + test_helpers::new_db(), miner_service.clone(), IoChannel::disconnected(), ).unwrap(); @@ -317,7 +316,7 @@ const POSITIVE_NONCE_SPEC: &'static [u8] = br#"{ fn eth_transaction_count() { let secret = "8a283037bb19c4fed7b1c569e40c7dcff366165eb869110a1b11532963eb9cb2".parse().unwrap(); let tester = EthTester::from_spec(Spec::load(&env::temp_dir(), TRANSACTION_COUNT_SPEC).expect("invalid chain spec")); - let address = tester.accounts.insert_account(secret, "").unwrap(); + let address = tester.accounts.insert_account(secret, &"".into()).unwrap(); tester.accounts.unlock_account_permanently(address, "".into()).unwrap(); let req_before = r#"{ @@ -423,11 +422,11 @@ fn verify_transaction_counts(name: String, chain: BlockChain) { let tester = EthTester::from_chain(&chain); let mut id = 1; - for b in chain.blocks_rlp().iter().filter(|b| Block::is_good(b)).map(|b| view!(BlockView, b)) { - let count = b.transactions_count(); + for b in chain.blocks_rlp().into_iter().filter_map(|b| Unverified::from_rlp(b).ok()) { + let count = b.transactions.len(); - let hash = b.hash(); - let number = b.header_view().number(); + let hash = b.header.hash(); + let number = b.header.number(); let (req, res) = by_hash(hash, count, &mut id); assert_eq!(tester.handler.handle_request_sync(&req), Some(res)); diff --git a/rpc/src/v1/tests/helpers/dapps.rs b/rpc/src/v1/tests/helpers/dapps.rs deleted file mode 100644 index 10c54cf4c2476324e53b21b303c5f88a68d29e8b..0000000000000000000000000000000000000000 --- a/rpc/src/v1/tests/helpers/dapps.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Test implementation of dapps service. - -use v1::types::LocalDapp; -use v1::helpers::dapps::DappsService; - -/// Test implementation of dapps service. Will always return the same list of dapps. -#[derive(Default, Clone)] -pub struct TestDappsService; - -impl DappsService for TestDappsService { - fn list_dapps(&self) -> Vec { - vec![LocalDapp { - id: "skeleton".into(), - name: "Skeleton".into(), - description: "A skeleton dapp".into(), - version: "0.1".into(), - author: "Parity Technologies Ltd".into(), - icon_url: "title.png".into(), - local_url: None, - }] - } - - fn refresh_local_dapps(&self) -> bool { - true - } -} diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index 6781d10b95b793c79c1c45a015ad382f0468b85c..a57e5d5f22065ee503655c905c5eac53e2d7c0bd 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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; @@ -27,7 +27,7 @@ use ethcore::engines::EthEngine; use ethcore::error::Error; use ethcore::header::{BlockNumber, Header}; use ethcore::ids::BlockId; -use ethcore::miner::{MinerService, AuthoringParams}; +use ethcore::miner::{self, MinerService, AuthoringParams}; use ethcore::receipt::{Receipt, RichReceipt}; use ethereum_types::{H256, U256, Address}; use miner::pool::local_transactions::Status as LocalTransactionStatus; @@ -35,6 +35,7 @@ use miner::pool::{verifier, VerifiedTransaction, QueueStatus}; use parking_lot::{RwLock, Mutex}; use transaction::{self, UnverifiedTransaction, SignedTransaction, PendingTransaction}; use txpool; +use ethkey::Password; /// Test miner service. pub struct TestMinerService { @@ -49,7 +50,7 @@ pub struct TestMinerService { /// Next nonces. pub next_nonces: RwLock>, /// Password held by Engine. - pub password: RwLock, + pub password: RwLock, authoring_params: RwLock, } @@ -62,7 +63,7 @@ impl Default for TestMinerService { local_transactions: Mutex::new(BTreeMap::new()), pending_receipts: Mutex::new(BTreeMap::new()), next_nonces: RwLock::new(HashMap::new()), - password: RwLock::new(String::new()), + password: RwLock::new("".into()), authoring_params: RwLock::new(AuthoringParams { author: Address::zero(), gas_range_target: (12345.into(), 54321.into()), @@ -119,7 +120,7 @@ impl MinerService for TestMinerService { self.authoring_params.read().clone() } - fn set_author(&self, author: Address, password: Option) -> Result<(), AccountError> { + fn set_author(&self, author: Address, password: Option) -> Result<(), AccountError> { self.authoring_params.write().author = author; if let Some(password) = password { *self.password.write() = password; @@ -155,7 +156,14 @@ impl MinerService for TestMinerService { } /// Imports transactions to transaction queue. - fn import_own_transaction(&self, chain: &C, pending: PendingTransaction) + fn import_own_transaction(&self, _chain: &C, _pending: PendingTransaction) + -> Result<(), transaction::Error> { + // this function is no longer called directly from RPC + unimplemented!(); + } + + /// Imports transactions to queue - treats as local based on trusted flag, config, and tx source + fn import_claimed_local_transaction(&self, chain: &C, pending: PendingTransaction, _trusted: bool) -> Result<(), transaction::Error> { // keep the pending nonces up to date @@ -181,8 +189,8 @@ impl MinerService for TestMinerService { fn work_package(&self, chain: &C) -> Option<(H256, BlockNumber, u64, U256)> { let params = self.authoring_params(); - let open_block = chain.prepare_open_block(params.author, params.gas_range_target, params.extra_data); - let closed = open_block.close(); + let open_block = chain.prepare_open_block(params.author, params.gas_range_target, params.extra_data).unwrap(); + let closed = open_block.close().unwrap(); let header = closed.header(); Some((header.hash(), header.number(), header.timestamp(), *header.difficulty())) @@ -208,10 +216,14 @@ impl MinerService for TestMinerService { self.local_transactions.lock().iter().map(|(hash, stats)| (*hash, stats.clone())).collect() } - fn ready_transactions(&self, _chain: &C) -> Vec> { + fn ready_transactions(&self, _chain: &C, _max_len: usize, _ordering: miner::PendingOrdering) -> Vec> { 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)) @@ -252,6 +264,7 @@ impl MinerService for TestMinerService { minimal_gas_price: 0x1312d00.into(), block_gas_limit: 5_000_000.into(), tx_gas_limit: 5_000_000.into(), + no_early_reject: false, }, status: txpool::LightStatus { mem_usage: 1_000, diff --git a/rpc/src/v1/tests/helpers/mod.rs b/rpc/src/v1/tests/helpers/mod.rs index 8e1aeeb147d4647968d888a452902fd4817cad10..ba87428b98928892731ba775c9e28c2852db45a5 100644 --- a/rpc/src/v1/tests/helpers/mod.rs +++ b/rpc/src/v1/tests/helpers/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -16,13 +16,11 @@ //! Test rpc services. -mod dapps; mod miner_service; mod snapshot_service; mod sync_provider; mod update_service; -pub use self::dapps::TestDappsService; pub use self::miner_service::TestMinerService; pub use self::snapshot_service::TestSnapshotService; pub use self::sync_provider::{Config, TestSyncProvider}; diff --git a/rpc/src/v1/tests/helpers/snapshot_service.rs b/rpc/src/v1/tests/helpers/snapshot_service.rs index 91cd14d73f15e3895d7fcbc4b8295a37deafa7c6..4e45488dbe519af47408fffbeaca6821c404a45f 100644 --- a/rpc/src/v1/tests/helpers/snapshot_service.rs +++ b/rpc/src/v1/tests/helpers/snapshot_service.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/tests/helpers/sync_provider.rs b/rpc/src/v1/tests/helpers/sync_provider.rs index a5ca4a4b367fae776e15090729f1e2a0791c110f..b65e543e557a86fa3f2174d418ee1c3565a429b1 100644 --- a/rpc/src/v1/tests/helpers/sync_provider.rs +++ b/rpc/src/v1/tests/helpers/sync_provider.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -75,7 +75,7 @@ impl SyncProvider for TestSyncProvider { vec![ PeerInfo { id: Some("node1".to_owned()), - client_version: "Parity/1".to_owned(), + client_version: "Parity-Ethereum/1".to_owned(), capabilities: vec!["eth/62".to_owned(), "eth/63".to_owned()], remote_address: "127.0.0.1:7777".to_owned(), local_address: "127.0.0.1:8888".to_owned(), @@ -88,7 +88,7 @@ impl SyncProvider for TestSyncProvider { }, PeerInfo { id: None, - client_version: "Parity/2".to_owned(), + client_version: "Parity-Ethereum/2".to_owned(), capabilities: vec!["eth/63".to_owned(), "eth/64".to_owned()], remote_address: "Handshake".to_owned(), local_address: "127.0.0.1:3333".to_owned(), @@ -123,4 +123,3 @@ impl SyncProvider for TestSyncProvider { ] } } - diff --git a/rpc/src/v1/tests/helpers/update_service.rs b/rpc/src/v1/tests/helpers/update_service.rs index eaa3b06fbea3c0d8fab241ffc017d869424c19b3..3c4d0b1d7de12de46bba8c884e8ab4ed56306421 100644 --- a/rpc/src/v1/tests/helpers/update_service.rs +++ b/rpc/src/v1/tests/helpers/update_service.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index a6c877243912edaee332f71421c529cb0e0d0ce6..7213ad63da476d26e70de547ca6be7ba1fcffbb7 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -19,7 +19,7 @@ use std::collections::HashMap; use std::sync::Arc; use std::time::{Instant, Duration, SystemTime, UNIX_EPOCH}; -use ethereum_types::{H256, U256, Address}; +use ethereum_types::{H160, H256, U256, Address}; use parking_lot::Mutex; use ethcore::account_provider::AccountProvider; use ethcore::client::{BlockChainClient, BlockId, EachBlockWith, Executed, TestBlockChainClient, TransactionId}; @@ -92,8 +92,9 @@ impl EthTester { let hashrates = Arc::new(Mutex::new(HashMap::new())); let external_miner = Arc::new(ExternalMiner::new(hashrates.clone())); let gas_price_percentile = options.gas_price_percentile; + let poll_lifetime = options.poll_lifetime; let eth = EthClient::new(&client, &snapshot, &sync, &opt_ap, &miner, &external_miner, options).to_delegate(); - let filter = EthFilterClient::new(client.clone(), miner.clone()).to_delegate(); + let filter = EthFilterClient::new(client.clone(), miner.clone(), poll_lifetime).to_delegate(); let reservations = Arc::new(Mutex::new(nonce::Reservations::new())); let dispatcher = FullDispatcher::new(client.clone(), miner.clone(), reservations, gas_price_percentile); @@ -149,7 +150,6 @@ fn rpc_eth_syncing() { // causes TestBlockChainClient to return 1000 for its best block number. tester.add_blocks(1000, EachBlockWith::Nothing); - let true_res = r#"{"jsonrpc":"2.0","result":{"currentBlock":"0x3e8","highestBlock":"0x9c4","startingBlock":"0x0","warpChunksAmount":null,"warpChunksProcessed":null},"id":1}"#; assert_eq!(tester.io.handle_request_sync(request), Some(true_res.to_owned())); @@ -221,13 +221,12 @@ fn rpc_eth_logs() { log_index: 1, }]); - let request1 = r#"{"jsonrpc": "2.0", "method": "eth_getLogs", "params": [{}], "id": 1}"#; let request2 = r#"{"jsonrpc": "2.0", "method": "eth_getLogs", "params": [{"limit":1}], "id": 1}"#; let request3 = r#"{"jsonrpc": "2.0", "method": "eth_getLogs", "params": [{"limit":0}], "id": 1}"#; - let response1 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x0","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"mined"},{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x1","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x1","type":"mined"}],"id":1}"#; - let response2 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x1","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x1","type":"mined"}],"id":1}"#; + let response1 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x0","removed":false,"topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"mined"},{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x1","removed":false,"topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x1","type":"mined"}],"id":1}"#; + let response2 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x1","removed":false,"topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x1","type":"mined"}],"id":1}"#; let response3 = r#"{"jsonrpc":"2.0","result":[],"id":1}"#; assert_eq!(tester.io.handle_request_sync(request1), Some(response1.to_owned())); @@ -276,8 +275,8 @@ fn rpc_logs_filter() { let request_changes1 = r#"{"jsonrpc": "2.0", "method": "eth_getFilterChanges", "params": ["0x0"], "id": 1}"#; let request_changes2 = r#"{"jsonrpc": "2.0", "method": "eth_getFilterChanges", "params": ["0x1"], "id": 1}"#; - let response1 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x0","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"mined"},{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x1","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x1","type":"mined"}],"id":1}"#; - let response2 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x1","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x1","type":"mined"}],"id":1}"#; + let response1 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x0","removed":false,"topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"mined"},{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x1","removed":false,"topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x1","type":"mined"}],"id":1}"#; + let response2 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x1","removed":false,"topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x1","type":"mined"}],"id":1}"#; assert_eq!(tester.io.handle_request_sync(request_changes1), Some(response1.to_owned())); assert_eq!(tester.io.handle_request_sync(request_changes2), Some(response2.to_owned())); @@ -329,7 +328,7 @@ fn rpc_eth_submit_hashrate() { fn rpc_eth_sign() { let tester = EthTester::default(); - let account = tester.accounts_provider.insert_account(Secret::from([69u8; 32]), "abcd").unwrap(); + let account = tester.accounts_provider.insert_account(Secret::from([69u8; 32]), &"abcd".into()).unwrap(); tester.accounts_provider.unlock_account_permanently(account, "abcd".into()).unwrap(); let _message = "0cc175b9c0f1b6a831c399e26977266192eb5ffee6ae2fec3ad71c777531578f".from_hex().unwrap(); @@ -363,11 +362,11 @@ fn rpc_eth_author() { assert_eq!(tester.io.handle_request_sync(req), Some(make_res(Address::zero()))); // Account set - return first account - let addr = tester.accounts_provider.new_account("123").unwrap(); + let addr = tester.accounts_provider.new_account(&"123".into()).unwrap(); assert_eq!(tester.io.handle_request_sync(req), Some(make_res(addr))); for i in 0..20 { - let addr = tester.accounts_provider.new_account(&format!("{}", i)).unwrap(); + let addr = tester.accounts_provider.new_account(&format!("{}", i).into()).unwrap(); tester.miner.set_author(addr.clone(), None).unwrap(); assert_eq!(tester.io.handle_request_sync(req), Some(make_res(addr))); @@ -395,7 +394,7 @@ fn rpc_eth_gas_price() { #[test] fn rpc_eth_accounts() { let tester = EthTester::default(); - let address = tester.accounts_provider.new_account("").unwrap(); + let address = tester.accounts_provider.new_account(&"".into()).unwrap(); tester.accounts_provider.set_new_dapps_addresses(None).unwrap(); tester.accounts_provider.set_address_name(1.into(), "1".into()); tester.accounts_provider.set_address_name(10.into(), "10".into()); @@ -582,7 +581,6 @@ fn rpc_eth_pending_transaction_by_hash() { assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); } - #[test] fn rpc_eth_uncle_count_by_block_hash() { let request = r#"{ @@ -806,7 +804,7 @@ fn rpc_eth_estimate_gas_default_block() { #[test] fn rpc_eth_send_transaction() { let tester = EthTester::default(); - let address = tester.accounts_provider.new_account("").unwrap(); + let address = tester.accounts_provider.new_account(&"".into()).unwrap(); tester.accounts_provider.unlock_account_permanently(address, "".into()).unwrap(); let request = r#"{ "jsonrpc": "2.0", @@ -857,7 +855,7 @@ fn rpc_eth_send_transaction() { #[test] fn rpc_eth_sign_transaction() { let tester = EthTester::default(); - let address = tester.accounts_provider.new_account("").unwrap(); + let address = tester.accounts_provider.new_account(&"".into()).unwrap(); tester.accounts_provider.unlock_account_permanently(address, "".into()).unwrap(); let request = r#"{ "jsonrpc": "2.0", @@ -914,7 +912,7 @@ fn rpc_eth_sign_transaction() { #[test] fn rpc_eth_send_transaction_with_bad_to() { let tester = EthTester::default(); - let address = tester.accounts_provider.new_account("").unwrap(); + let address = tester.accounts_provider.new_account(&"".into()).unwrap(); let request = r#"{ "jsonrpc": "2.0", "method": "eth_sendTransaction", @@ -933,11 +931,10 @@ fn rpc_eth_send_transaction_with_bad_to() { assert_eq!(tester.io.handle_request_sync(&request), Some(response.into())); } - #[test] fn rpc_eth_send_transaction_error() { let tester = EthTester::default(); - let address = tester.accounts_provider.new_account("").unwrap(); + let address = tester.accounts_provider.new_account(&"".into()).unwrap(); let request = r#"{ "jsonrpc": "2.0", "method": "eth_sendTransaction", @@ -975,7 +972,7 @@ fn rpc_eth_send_raw_transaction_error() { #[test] fn rpc_eth_send_raw_transaction() { let tester = EthTester::default(); - let address = tester.accounts_provider.new_account("abcd").unwrap(); + let address = tester.accounts_provider.new_account(&"abcd".into()).unwrap(); tester.accounts_provider.unlock_account_permanently(address, "abcd".into()).unwrap(); let t = Transaction { @@ -1008,6 +1005,8 @@ fn rpc_eth_send_raw_transaction() { #[test] fn rpc_eth_transaction_receipt() { let receipt = LocalizedReceipt { + from: H160::from_str("b60e8dd61c5d32be8058bb8eb970870f07233155").unwrap(), + to: Some(H160::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()), transaction_hash: H256::zero(), transaction_index: 0, block_hash: H256::from_str("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5").unwrap(), @@ -1045,7 +1044,7 @@ fn rpc_eth_transaction_receipt() { "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"], "id": 1 }"#; - let response = r#"{"jsonrpc":"2.0","result":{"blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","contractAddress":null,"cumulativeGasUsed":"0x20","gasUsed":"0x10","logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","data":"0x","logIndex":"0x1","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"mined"}],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","root":"0x0000000000000000000000000000000000000000000000000000000000000000","status":null,"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0"},"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":{"blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","contractAddress":null,"cumulativeGasUsed":"0x20","from":"0xb60e8dd61c5d32be8058bb8eb970870f07233155","gasUsed":"0x10","logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","data":"0x","logIndex":"0x1","removed":false,"topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"mined"}],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","root":"0x0000000000000000000000000000000000000000000000000000000000000000","status":null,"to":"0xd46e8dd67c5d32be8058bb8eb970870f07244567","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0"},"id":1}"#; assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); } diff --git a/rpc/src/v1/tests/mocked/eth_pubsub.rs b/rpc/src/v1/tests/mocked/eth_pubsub.rs index 936695a9a136f2c8a3d148a3307f68c94839db7b..9233435bf41c7b276cf770c21a25221f671ba733 100644 --- a/rpc/src/v1/tests/mocked/eth_pubsub.rs +++ b/rpc/src/v1/tests/mocked/eth_pubsub.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -131,7 +131,7 @@ fn should_subscribe_to_logs() { // Check notifications (enacted) handler.new_blocks(vec![], vec![], ChainRoute::new(vec![(h1, ChainRouteType::Enacted)]), vec![], vec![], DURATION_ZERO); let (res, receiver) = receiver.into_future().wait().unwrap(); - let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"address":"0x0000000000000000000000000000000000000005","blockHash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","blockNumber":"0x1","data":"0x","logIndex":"0x0","topics":["0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000"],"transactionHash":""#.to_owned() + let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"address":"0x0000000000000000000000000000000000000005","blockHash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","blockNumber":"0x1","data":"0x","logIndex":"0x0","removed":false,"topics":["0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000"],"transactionHash":""#.to_owned() + &format!("0x{:x}", tx_hash) + r#"","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"mined"},"subscription":"0x416d77337e24399d"}}"#; assert_eq!(res, Some(response.into())); @@ -139,12 +139,11 @@ fn should_subscribe_to_logs() { // Check notifications (retracted) handler.new_blocks(vec![], vec![], ChainRoute::new(vec![(h1, ChainRouteType::Retracted)]), vec![], vec![], DURATION_ZERO); let (res, receiver) = receiver.into_future().wait().unwrap(); - let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"address":"0x0000000000000000000000000000000000000005","blockHash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","blockNumber":"0x1","data":"0x","logIndex":"0x0","topics":["0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000"],"transactionHash":""#.to_owned() + let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"address":"0x0000000000000000000000000000000000000005","blockHash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","blockNumber":"0x1","data":"0x","logIndex":"0x0","removed":true,"topics":["0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000"],"transactionHash":""#.to_owned() + &format!("0x{:x}", tx_hash) + r#"","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"removed"},"subscription":"0x416d77337e24399d"}}"#; assert_eq!(res, Some(response.into())); - // And unsubscribe let request = r#"{"jsonrpc": "2.0", "method": "eth_unsubscribe", "params": ["0x416d77337e24399d"], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; @@ -154,7 +153,6 @@ fn should_subscribe_to_logs() { assert_eq!(res, None); } - #[test] fn should_subscribe_to_pending_transactions() { // given @@ -183,7 +181,7 @@ fn should_subscribe_to_pending_transactions() { assert_eq!(io.handle_request_sync(request, metadata.clone()), Some(response.to_owned())); // Send new transactions - handler.new_transactions(&[5.into(), 7.into()]); + handler.notify_new_transactions(&[5.into(), 7.into()]); let (res, receiver) = receiver.into_future().wait().unwrap(); let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":"0x0000000000000000000000000000000000000000000000000000000000000005","subscription":"0x416d77337e24399d"}}"#; diff --git a/rpc/src/v1/tests/mocked/manage_network.rs b/rpc/src/v1/tests/mocked/manage_network.rs index da4f1aa51188fc1f1771b96fd616c53d1a3bb14e..a742f03c2f9b8777e3cd29a92fd624be5ef15102 100644 --- a/rpc/src/v1/tests/mocked/manage_network.rs +++ b/rpc/src/v1/tests/mocked/manage_network.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/tests/mocked/mod.rs b/rpc/src/v1/tests/mocked/mod.rs index ae51c2be67ecff8174b2c45031cb3777d12c5fe2..a3de3b3b71b977c24af9a18938fe8085c9e29359 100644 --- a/rpc/src/v1/tests/mocked/mod.rs +++ b/rpc/src/v1/tests/mocked/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/tests/mocked/net.rs b/rpc/src/v1/tests/mocked/net.rs index 0f77dfb11a542bab242473273f124a534387c9da..b94bf2b11387014ff02ffb1843dd41ca5b90706c 100644 --- a/rpc/src/v1/tests/mocked/net.rs +++ b/rpc/src/v1/tests/mocked/net.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/tests/mocked/parity.rs b/rpc/src/v1/tests/mocked/parity.rs index c27615a589cd530acdfd0310f41a2c7bd2681434..300badd742de12699ec4483dba44eef5ef229421 100644 --- a/rpc/src/v1/tests/mocked/parity.rs +++ b/rpc/src/v1/tests/mocked/parity.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -21,8 +21,6 @@ use ethcore_logger::RotatingLogger; use ethereum_types::{Address, U256, H256}; use ethstore::ethkey::{Generator, Random}; use miner::pool::local_transactions::Status as LocalTransactionStatus; -use node_health::{self, NodeHealth}; -use parity_reactor; use sync::ManageNetwork; use jsonrpc_core::IoHandler; @@ -40,12 +38,10 @@ pub struct Dependencies { pub client: Arc, pub sync: Arc, pub updater: Arc, - pub health: NodeHealth, pub logger: Arc, pub settings: Arc, pub network: Arc, pub accounts: Arc, - pub dapps_address: Option, pub ws_address: Option, } @@ -58,11 +54,6 @@ impl Dependencies { network_id: 3, num_peers: 120, })), - health: NodeHealth::new( - Arc::new(FakeSync), - node_health::TimeChecker::new::(&[], node_health::CpuPool::new(1)), - parity_reactor::Remote::new_sync(), - ), updater: Arc::new(TestUpdater::default()), logger: Arc::new(RotatingLogger::new("rpc=trace".to_owned())), settings: Arc::new(NetworkSettings { @@ -75,26 +66,21 @@ impl Dependencies { }), network: Arc::new(TestManageNetwork), accounts: Arc::new(AccountProvider::transient_provider()), - dapps_address: Some("127.0.0.1:18080".into()), ws_address: Some("127.0.0.1:18546".into()), } } pub fn client(&self, signer: Option>) -> TestParityClient { - let opt_accounts = self.accounts.clone(); - ParityClient::new( self.client.clone(), self.miner.clone(), self.sync.clone(), self.updater.clone(), self.network.clone(), - self.health.clone(), - opt_accounts.clone(), + self.accounts.clone(), self.logger.clone(), self.settings.clone(), signer, - self.dapps_address.clone(), self.ws_address.clone(), ) } @@ -112,19 +98,12 @@ impl Dependencies { } } -#[derive(Debug)] -struct FakeSync; -impl node_health::SyncStatus for FakeSync { - fn is_major_importing(&self) -> bool { false } - fn peers(&self) -> (usize, usize) { (4, 25) } -} - #[test] fn rpc_parity_accounts_info() { let deps = Dependencies::new(); let io = deps.default_client(); - deps.accounts.new_account("").unwrap(); + deps.accounts.new_account(&"".into()).unwrap(); let accounts = deps.accounts.accounts().unwrap(); assert_eq!(accounts.len(), 1); let address = accounts[0]; @@ -150,7 +129,6 @@ fn rpc_parity_default_account() { let deps = Dependencies::new(); let io = deps.default_client(); - // Check empty let address = Address::default(); let request = r#"{"jsonrpc": "2.0", "method": "parity_defaultAccount", "params": [], "id": 1}"#; @@ -158,7 +136,7 @@ fn rpc_parity_default_account() { assert_eq!(io.handle_request_sync(request), Some(response)); // With account - deps.accounts.new_account("").unwrap(); + deps.accounts.new_account(&"".into()).unwrap(); let accounts = deps.accounts.accounts().unwrap(); assert_eq!(accounts.len(), 1); let address = accounts[0]; @@ -332,7 +310,7 @@ fn rpc_parity_net_peers() { let io = deps.default_client(); let request = r#"{"jsonrpc": "2.0", "method": "parity_netPeers", "params":[], "id": 1}"#; - let response = r#"{"jsonrpc":"2.0","result":{"active":0,"connected":120,"max":50,"peers":[{"caps":["eth/62","eth/63"],"id":"node1","name":"Parity/1","network":{"localAddress":"127.0.0.1:8888","remoteAddress":"127.0.0.1:7777"},"protocols":{"eth":{"difficulty":"0x28","head":"0000000000000000000000000000000000000000000000000000000000000032","version":62},"pip":null}},{"caps":["eth/63","eth/64"],"id":null,"name":"Parity/2","network":{"localAddress":"127.0.0.1:3333","remoteAddress":"Handshake"},"protocols":{"eth":{"difficulty":null,"head":"000000000000000000000000000000000000000000000000000000000000003c","version":64},"pip":null}}]},"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":{"active":0,"connected":120,"max":50,"peers":[{"caps":["eth/62","eth/63"],"id":"node1","name":"Parity-Ethereum/1","network":{"localAddress":"127.0.0.1:8888","remoteAddress":"127.0.0.1:7777"},"protocols":{"eth":{"difficulty":"0x28","head":"0000000000000000000000000000000000000000000000000000000000000032","version":62},"pip":null}},{"caps":["eth/63","eth/64"],"id":null,"name":"Parity-Ethereum/2","network":{"localAddress":"127.0.0.1:3333","remoteAddress":"Handshake"},"protocols":{"eth":{"difficulty":null,"head":"000000000000000000000000000000000000000000000000000000000000003c","version":64},"pip":null}}]},"id":1}"#; assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); } @@ -431,24 +409,6 @@ fn rpc_parity_ws_address() { assert_eq!(io2.handle_request_sync(request), Some(response2.to_owned())); } -#[test] -fn rpc_parity_dapps_address() { - // given - let mut deps = Dependencies::new(); - let io1 = deps.default_client(); - deps.dapps_address = None; - let io2 = deps.default_client(); - - // when - let request = r#"{"jsonrpc": "2.0", "method": "parity_dappsUrl", "params": [], "id": 1}"#; - let response1 = r#"{"jsonrpc":"2.0","result":"127.0.0.1:18080","id":1}"#; - let response2 = r#"{"jsonrpc":"2.0","error":{"code":-32000,"message":"Dapps Server is disabled. This API is not available."},"id":1}"#; - - // then - assert_eq!(io1.handle_request_sync(request), Some(response1.to_owned())); - assert_eq!(io2.handle_request_sync(request), Some(response2.to_owned())); -} - #[test] fn rpc_parity_next_nonce() { let deps = Dependencies::new(); @@ -578,14 +538,3 @@ fn rpc_parity_call() { assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); } - -#[test] -fn rpc_parity_node_health() { - let deps = Dependencies::new(); - let io = deps.default_client(); - - let request = r#"{"jsonrpc": "2.0", "method": "parity_nodeHealth", "params":[], "id": 1}"#; - let response = r#"{"jsonrpc":"2.0","result":{"peers":{"details":[4,25],"message":"","status":"ok"},"sync":{"details":false,"message":"","status":"ok"},"time":{"details":0,"message":"","status":"ok"}},"id":1}"#; - - assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); -} diff --git a/rpc/src/v1/tests/mocked/parity_accounts.rs b/rpc/src/v1/tests/mocked/parity_accounts.rs index c30b4b9ced2c5e0872d0045aa07897ab5a18aab4..699ba01f8edc5a8a1c5404406047d2ba0a2f1d77 100644 --- a/rpc/src/v1/tests/mocked/parity_accounts.rs +++ b/rpc/src/v1/tests/mocked/parity_accounts.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -64,7 +64,7 @@ fn setup_with_vaults_support(temp_path: &str) -> ParityAccountsTester { #[test] fn should_be_able_to_get_account_info() { let tester = setup(); - tester.accounts.new_account("").unwrap(); + tester.accounts.new_account(&"".into()).unwrap(); let accounts = tester.accounts.accounts().unwrap(); assert_eq!(accounts.len(), 1); let address = accounts[0]; @@ -82,7 +82,7 @@ fn should_be_able_to_get_account_info() { #[test] fn should_be_able_to_set_name() { let tester = setup(); - tester.accounts.new_account("").unwrap(); + tester.accounts.new_account(&"".into()).unwrap(); let accounts = tester.accounts.accounts().unwrap(); assert_eq!(accounts.len(), 1); let address = accounts[0]; @@ -103,7 +103,7 @@ fn should_be_able_to_set_name() { #[test] fn should_be_able_to_set_meta() { let tester = setup(); - tester.accounts.new_account("").unwrap(); + tester.accounts.new_account(&"".into()).unwrap(); let accounts = tester.accounts.accounts().unwrap(); assert_eq!(accounts.len(), 1); let address = accounts[0]; @@ -206,7 +206,6 @@ fn rpc_parity_set_and_get_new_dapps_default_address() { assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); } - #[test] fn rpc_parity_recent_dapps() { // given @@ -225,7 +224,7 @@ fn rpc_parity_recent_dapps() { #[test] fn should_be_able_to_kill_account() { let tester = setup(); - tester.accounts.new_account("password").unwrap(); + tester.accounts.new_account(&"password".into()).unwrap(); let accounts = tester.accounts.accounts().unwrap(); assert_eq!(accounts.len(), 1); let address = accounts[0]; @@ -283,7 +282,7 @@ fn rpc_parity_new_vault() { assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); assert!(tester.accounts.close_vault("vault1").is_ok()); - assert!(tester.accounts.open_vault("vault1", "password1").is_ok()); + assert!(tester.accounts.open_vault("vault1", &"password1".into()).is_ok()); } #[test] @@ -291,7 +290,7 @@ fn rpc_parity_open_vault() { let tempdir = TempDir::new("").unwrap(); let tester = setup_with_vaults_support(tempdir.path().to_str().unwrap()); - assert!(tester.accounts.create_vault("vault1", "password1").is_ok()); + assert!(tester.accounts.create_vault("vault1", &"password1".into()).is_ok()); assert!(tester.accounts.close_vault("vault1").is_ok()); let request = r#"{"jsonrpc": "2.0", "method": "parity_openVault", "params":["vault1", "password1"], "id": 1}"#; @@ -305,7 +304,7 @@ fn rpc_parity_close_vault() { let tempdir = TempDir::new("").unwrap(); let tester = setup_with_vaults_support(tempdir.path().to_str().unwrap()); - assert!(tester.accounts.create_vault("vault1", "password1").is_ok()); + assert!(tester.accounts.create_vault("vault1", &"password1".into()).is_ok()); let request = r#"{"jsonrpc": "2.0", "method": "parity_closeVault", "params":["vault1"], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; @@ -318,7 +317,7 @@ fn rpc_parity_change_vault_password() { let tempdir = TempDir::new("").unwrap(); let tester = setup_with_vaults_support(tempdir.path().to_str().unwrap()); - assert!(tester.accounts.create_vault("vault1", "password1").is_ok()); + assert!(tester.accounts.create_vault("vault1", &"password1".into()).is_ok()); let request = r#"{"jsonrpc": "2.0", "method": "parity_changeVaultPassword", "params":["vault1", "password2"], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; @@ -331,8 +330,8 @@ fn rpc_parity_change_vault() { let tempdir = TempDir::new("").unwrap(); let tester = setup_with_vaults_support(tempdir.path().to_str().unwrap()); - let (address, _) = tester.accounts.new_account_and_public("root_password").unwrap(); - assert!(tester.accounts.create_vault("vault1", "password1").is_ok()); + let (address, _) = tester.accounts.new_account_and_public(&"root_password".into()).unwrap(); + assert!(tester.accounts.create_vault("vault1", &"password1".into()).is_ok()); let request = format!(r#"{{"jsonrpc": "2.0", "method": "parity_changeVault", "params":["0x{:x}", "vault1"], "id": 1}}"#, address); let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; @@ -345,9 +344,9 @@ fn rpc_parity_vault_adds_vault_field_to_acount_meta() { let tempdir = TempDir::new("").unwrap(); let tester = setup_with_vaults_support(tempdir.path().to_str().unwrap()); - let (address1, _) = tester.accounts.new_account_and_public("root_password1").unwrap(); + let (address1, _) = tester.accounts.new_account_and_public(&"root_password1".into()).unwrap(); let uuid1 = tester.accounts.account_meta(address1.clone()).unwrap().uuid.unwrap(); - assert!(tester.accounts.create_vault("vault1", "password1").is_ok()); + assert!(tester.accounts.create_vault("vault1", &"password1".into()).is_ok()); assert!(tester.accounts.change_vault(address1, "vault1").is_ok()); let request = r#"{"jsonrpc": "2.0", "method": "parity_allAccountsInfo", "params":[], "id": 1}"#; @@ -369,8 +368,8 @@ fn rpc_parity_list_vaults() { let tempdir = TempDir::new("").unwrap(); let tester = setup_with_vaults_support(tempdir.path().to_str().unwrap()); - assert!(tester.accounts.create_vault("vault1", "password1").is_ok()); - assert!(tester.accounts.create_vault("vault2", "password2").is_ok()); + assert!(tester.accounts.create_vault("vault1", &"password1".into()).is_ok()); + assert!(tester.accounts.create_vault("vault2", &"password2".into()).is_ok()); let request = r#"{"jsonrpc": "2.0", "method": "parity_listVaults", "params":[], "id": 1}"#; let response1 = r#"{"jsonrpc":"2.0","result":["vault1","vault2"],"id":1}"#; @@ -386,9 +385,9 @@ fn rpc_parity_list_opened_vaults() { let tempdir = TempDir::new("").unwrap(); let tester = setup_with_vaults_support(tempdir.path().to_str().unwrap()); - assert!(tester.accounts.create_vault("vault1", "password1").is_ok()); - assert!(tester.accounts.create_vault("vault2", "password2").is_ok()); - assert!(tester.accounts.create_vault("vault3", "password3").is_ok()); + assert!(tester.accounts.create_vault("vault1", &"password1".into()).is_ok()); + assert!(tester.accounts.create_vault("vault2", &"password2".into()).is_ok()); + assert!(tester.accounts.create_vault("vault3", &"password3".into()).is_ok()); assert!(tester.accounts.close_vault("vault2").is_ok()); let request = r#"{"jsonrpc": "2.0", "method": "parity_listOpenedVaults", "params":[], "id": 1}"#; @@ -405,7 +404,7 @@ fn rpc_parity_get_set_vault_meta() { let tempdir = TempDir::new("").unwrap(); let tester = setup_with_vaults_support(tempdir.path().to_str().unwrap()); - assert!(tester.accounts.create_vault("vault1", "password1").is_ok()); + assert!(tester.accounts.create_vault("vault1", &"password1".into()).is_ok()); // when no meta set let request = r#"{"jsonrpc": "2.0", "method": "parity_getVaultMeta", "params":["vault1"], "id": 1}"#; @@ -442,7 +441,7 @@ fn derive_key_hash() { let hash = tester.accounts .insert_account( "0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a".parse().unwrap(), - "password1") + &"password1".into()) .expect("account should be inserted ok"); assert_eq!(hash, "c171033d5cbff7175f29dfd3a63dda3d6f8f385e".parse().unwrap()); @@ -462,7 +461,7 @@ fn derive_key_index() { let hash = tester.accounts .insert_account( "0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a".parse().unwrap(), - "password1") + &"password1".into()) .expect("account should be inserted ok"); assert_eq!(hash, "c171033d5cbff7175f29dfd3a63dda3d6f8f385e".parse().unwrap()); @@ -474,13 +473,12 @@ fn derive_key_index() { assert_eq!(res, Some(response.into())); } - #[test] fn should_export_account() { // given let tester = setup(); let wallet = r#"{"id":"6a186c80-7797-cff2-bc2e-7c1d6a6cc76e","version":3,"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"a1c6ff99070f8032ca1c4e8add006373"},"ciphertext":"df27e3db64aa18d984b6439443f73660643c2d119a6f0fa2fa9a6456fc802d75","kdf":"pbkdf2","kdfparams":{"c":10240,"dklen":32,"prf":"hmac-sha256","salt":"ddc325335cda5567a1719313e73b4842511f3e4a837c9658eeb78e51ebe8c815"},"mac":"3dc888ae79cbb226ff9c455669f6cf2d79be72120f2298f6cb0d444fddc0aa3d"},"address":"0042e5d2a662eeaca8a7e828c174f98f35d8925b","name":"parity-export-test","meta":"{\"passwordHint\":\"parity-export-test\",\"timestamp\":1490017814987}"}"#; - tester.accounts.import_wallet(wallet.as_bytes(), "parity-export-test", false).unwrap(); + tester.accounts.import_wallet(wallet.as_bytes(), &"parity-export-test".into(), false).unwrap(); let accounts = tester.accounts.accounts().unwrap(); assert_eq!(accounts.len(), 1); @@ -527,7 +525,7 @@ fn should_sign_message() { let hash = tester.accounts .insert_account( "0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a".parse().unwrap(), - "password1") + &"password1".into()) .expect("account should be inserted ok"); assert_eq!(hash, "c171033d5cbff7175f29dfd3a63dda3d6f8f385e".parse().unwrap()); diff --git a/rpc/src/v1/tests/mocked/parity_set.rs b/rpc/src/v1/tests/mocked/parity_set.rs index 78c73f9479418280a4cb0032140ba9a66235d57b..5aca2827e12e69c842a7c3db3d4e997d0647fe38 100644 --- a/rpc/src/v1/tests/mocked/parity_set.rs +++ b/rpc/src/v1/tests/mocked/parity_set.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -26,7 +26,7 @@ use futures_cpupool::CpuPool; use jsonrpc_core::IoHandler; use v1::{ParitySet, ParitySetClient}; -use v1::tests::helpers::{TestMinerService, TestUpdater, TestDappsService}; +use v1::tests::helpers::{TestMinerService, TestUpdater}; use super::manage_network::TestManageNetwork; use fake_fetch::FakeFetch; @@ -55,9 +55,8 @@ fn parity_set_client( updater: &Arc, net: &Arc, ) -> TestParitySetClient { - let dapps_service = Arc::new(TestDappsService); let pool = CpuPool::new(1); - ParitySetClient::new(client, miner, updater, &(net.clone() as Arc), Some(dapps_service), FakeFetch::new(Some(1)), pool) + ParitySetClient::new(client, miner, updater, &(net.clone() as Arc), FakeFetch::new(Some(1)), pool) } #[test] @@ -178,10 +177,9 @@ fn rpc_parity_set_engine_signer() { assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); assert_eq!(miner.authoring_params().author, Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); - assert_eq!(*miner.password.read(), "password".to_string()); + assert_eq!(*miner.password.read(), "password".into()); } - #[test] fn rpc_parity_set_transactions_limit() { let miner = miner_service(); @@ -240,18 +238,3 @@ fn rpc_parity_remove_transaction() { miner.pending_transactions.lock().insert(hash, signed); assert_eq!(io.handle_request_sync(&request), Some(response.to_owned())); } - -#[test] -fn rpc_parity_set_dapps_list() { - let miner = miner_service(); - let client = client_service(); - let network = network_service(); - let updater = updater_service(); - let mut io = IoHandler::new(); - io.extend_with(parity_set_client(&client, &miner, &updater, &network).to_delegate()); - - let request = r#"{"jsonrpc": "2.0", "method": "parity_dappsList", "params":[], "id": 1}"#; - let response = r#"{"jsonrpc":"2.0","result":[{"author":"Parity Technologies Ltd","description":"A skeleton dapp","iconUrl":"title.png","id":"skeleton","localUrl":null,"name":"Skeleton","version":"0.1"}],"id":1}"#; - - assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); -} diff --git a/rpc/src/v1/tests/mocked/personal.rs b/rpc/src/v1/tests/mocked/personal.rs index 323f9fe1376faca4a5cd8b2c2f59e694db0448ab..a60914823cccf44572f086fde1e25db7da01e80c 100644 --- a/rpc/src/v1/tests/mocked/personal.rs +++ b/rpc/src/v1/tests/mocked/personal.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -52,13 +52,12 @@ fn miner_service() -> Arc { fn setup() -> PersonalTester { let accounts = accounts_provider(); - let opt_accounts = accounts.clone(); let client = blockchain_client(); let miner = miner_service(); let reservations = Arc::new(Mutex::new(nonce::Reservations::new())); let dispatcher = FullDispatcher::new(client, miner.clone(), reservations, 50); - let personal = PersonalClient::new(&opt_accounts, dispatcher, false); + let personal = PersonalClient::new(&accounts, dispatcher, false); let mut io = IoHandler::default(); io.extend_with(personal.to_delegate()); @@ -75,7 +74,7 @@ fn setup() -> PersonalTester { #[test] fn accounts() { let tester = setup(); - let address = tester.accounts.new_account("").unwrap(); + let address = tester.accounts.new_account(&"".into()).unwrap(); let request = r#"{"jsonrpc": "2.0", "method": "personal_listAccounts", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":[""#.to_owned() + &format!("0x{:x}", address) + r#""],"id":1}"#; @@ -100,7 +99,7 @@ fn new_account() { fn invalid_password_test(method: &str) { let tester = setup(); - let address = tester.accounts.new_account("password123").unwrap(); + let address = tester.accounts.new_account(&"password123".into()).unwrap(); let request = r#"{ "jsonrpc": "2.0", @@ -123,7 +122,7 @@ fn invalid_password_test(method: &str) #[test] fn sign() { let tester = setup(); - let address = tester.accounts.new_account("password123").unwrap(); + let address = tester.accounts.new_account(&"password123".into()).unwrap(); let data = vec![5u8]; let request = r#"{ @@ -149,7 +148,7 @@ fn sign() { #[test] fn sign_with_invalid_password() { let tester = setup(); - let address = tester.accounts.new_account("password123").unwrap(); + let address = tester.accounts.new_account(&"password123".into()).unwrap(); let request = r#"{ "jsonrpc": "2.0", @@ -189,7 +188,7 @@ fn sign_and_send_transaction() { fn sign_and_send_test(method: &str) { let tester = setup(); - let address = tester.accounts.new_account("password123").unwrap(); + let address = tester.accounts.new_account(&"password123".into()).unwrap(); let request = r#"{ "jsonrpc": "2.0", @@ -242,7 +241,7 @@ fn sign_and_send_test(method: &str) { #[test] fn ec_recover() { let tester = setup(); - let address = tester.accounts.new_account("password123").unwrap(); + let address = tester.accounts.new_account(&"password123".into()).unwrap(); let data = vec![5u8]; let hash = eth_data_hash(data.clone()); @@ -288,7 +287,7 @@ fn ec_recover_invalid_signature() { #[test] fn should_unlock_not_account_temporarily_if_allow_perm_is_disabled() { let tester = setup(); - let address = tester.accounts.new_account("password123").unwrap(); + let address = tester.accounts.new_account(&"password123".into()).unwrap(); let request = r#"{ "jsonrpc": "2.0", @@ -309,7 +308,7 @@ fn should_unlock_not_account_temporarily_if_allow_perm_is_disabled() { #[test] fn should_unlock_account_permanently() { let tester = setup(); - let address = tester.accounts.new_account("password123").unwrap(); + let address = tester.accounts.new_account(&"password123".into()).unwrap(); let request = r#"{ "jsonrpc": "2.0", diff --git a/rpc/src/v1/tests/mocked/pubsub.rs b/rpc/src/v1/tests/mocked/pubsub.rs index 99b34366c8f99ca72e8cdf76ad4559f7701dd5e5..a21f8a49033e6ded5f5f1d87f8731c68ad91a28f 100644 --- a/rpc/src/v1/tests/mocked/pubsub.rs +++ b/rpc/src/v1/tests/mocked/pubsub.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -75,4 +75,3 @@ fn should_subscribe_to_a_method() { let (res, _receiver) = receiver.into_future().wait().unwrap(); assert_eq!(res, None); } - diff --git a/rpc/src/v1/tests/mocked/rpc.rs b/rpc/src/v1/tests/mocked/rpc.rs index d0a6d2fab44150368128857a74ecc20944d8ea71..ed6503cea5fa100ca41323661331d8a1a15fa35d 100644 --- a/rpc/src/v1/tests/mocked/rpc.rs +++ b/rpc/src/v1/tests/mocked/rpc.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -18,7 +18,6 @@ use std::collections::BTreeMap; use jsonrpc_core::IoHandler; use v1::{Rpc, RpcClient}; - fn rpc_client() -> RpcClient { let mut modules = BTreeMap::new(); modules.insert("rpc".to_owned(), "1.0".to_owned()); diff --git a/rpc/src/v1/tests/mocked/secretstore.rs b/rpc/src/v1/tests/mocked/secretstore.rs index 6ee9b6c24582d6e141f8e1f0e91966497dd0afc8..7e28a52838e608bf9adcd4c8a97386038620e551 100644 --- a/rpc/src/v1/tests/mocked/secretstore.rs +++ b/rpc/src/v1/tests/mocked/secretstore.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -57,7 +57,7 @@ fn rpc_secretstore_encrypt_and_decrypt() { // insert new account let secret = "c1f1cfe279a5c350d13795bce162941967340c8a228e6ba175489afc564a5bef".parse().unwrap(); - deps.accounts.insert_account(secret, "password").unwrap(); + deps.accounts.insert_account(secret, &"password".into()).unwrap(); // execute encryption request let encryption_request = r#"{"jsonrpc": "2.0", "method": "secretstore_encrypt", "params":[ @@ -87,7 +87,7 @@ fn rpc_secretstore_shadow_decrypt() { // insert new account let secret = "82758356bf46b42710d3946a8efa612b7bf5e125e4d49f28facf1139db4a46f4".parse().unwrap(); - deps.accounts.insert_account(secret, "password").unwrap(); + deps.accounts.insert_account(secret, &"password".into()).unwrap(); // execute decryption request let decryption_request = r#"{"jsonrpc": "2.0", "method": "secretstore_shadowDecrypt", "params":[ @@ -131,7 +131,7 @@ fn rpc_secretstore_sign_raw_hash() { // insert new account let secret = "82758356bf46b42710d3946a8efa612b7bf5e125e4d49f28facf1139db4a46f4".parse().unwrap(); let key_pair = KeyPair::from_secret(secret).unwrap(); - deps.accounts.insert_account(key_pair.secret().clone(), "password").unwrap(); + deps.accounts.insert_account(key_pair.secret().clone(), &"password".into()).unwrap(); // execute signing request let signing_request = r#"{"jsonrpc": "2.0", "method": "secretstore_signRawHash", "params":[ @@ -154,7 +154,7 @@ fn rpc_secretstore_generate_document_key() { // insert new account let secret = "82758356bf46b42710d3946a8efa612b7bf5e125e4d49f28facf1139db4a46f4".parse().unwrap(); let key_pair = KeyPair::from_secret(secret).unwrap(); - deps.accounts.insert_account(key_pair.secret().clone(), "password").unwrap(); + deps.accounts.insert_account(key_pair.secret().clone(), &"password".into()).unwrap(); // execute generation request let generation_request = r#"{"jsonrpc": "2.0", "method": "secretstore_generateDocumentKey", "params":[ diff --git a/rpc/src/v1/tests/mocked/signer.rs b/rpc/src/v1/tests/mocked/signer.rs index 8881dc41c35aa57157e48fde4de1a150c77f2272..52d5f7d8d35e6aecf660941094a732245a313710 100644 --- a/rpc/src/v1/tests/mocked/signer.rs +++ b/rpc/src/v1/tests/mocked/signer.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -58,7 +58,6 @@ fn miner_service() -> Arc { fn signer_tester() -> SignerTester { let signer = Arc::new(SignerService::new_test(false)); let accounts = accounts_provider(); - let opt_accounts = accounts.clone(); let client = blockchain_client(); let miner = miner_service(); let reservations = Arc::new(Mutex::new(nonce::Reservations::new())); @@ -66,7 +65,7 @@ fn signer_tester() -> SignerTester { let dispatcher = FullDispatcher::new(client, miner.clone(), reservations, 50); let mut io = IoHandler::default(); - io.extend_with(SignerClient::new(&opt_accounts, dispatcher, &signer, event_loop.remote()).to_delegate()); + io.extend_with(SignerClient::new(&accounts, dispatcher, &signer, event_loop.remote()).to_delegate()); SignerTester { signer: signer, @@ -76,7 +75,6 @@ fn signer_tester() -> SignerTester { } } - #[test] fn should_return_list_of_items_to_confirm() { // given @@ -107,7 +105,6 @@ fn should_return_list_of_items_to_confirm() { assert_eq!(tester.io.handle_request_sync(&request), Some(response.to_owned())); } - #[test] fn should_reject_transaction_from_queue_without_dispatching() { // given @@ -181,7 +178,7 @@ fn should_not_remove_sign_if_password_is_invalid() { fn should_confirm_transaction_and_dispatch() { //// given let tester = signer_tester(); - let address = tester.accounts.new_account("test").unwrap(); + let address = tester.accounts.new_account(&"test".into()).unwrap(); let recipient = Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap(); let _confirmation_future = tester.signer.add_request(ConfirmationPayload::SendTransaction(FilledTransactionRequest { from: address, @@ -250,7 +247,7 @@ fn should_alter_the_sender_and_nonce() { data: vec![] }; - let address = tester.accounts.new_account("test").unwrap(); + let address = tester.accounts.new_account(&"test".into()).unwrap(); let signature = tester.accounts.sign(address, Some("test".into()), t.hash(None)).unwrap(); let t = t.with_signature(signature, None); @@ -277,7 +274,7 @@ fn should_alter_the_sender_and_nonce() { fn should_confirm_transaction_with_token() { // given let tester = signer_tester(); - let address = tester.accounts.new_account("test").unwrap(); + let address = tester.accounts.new_account(&"test".into()).unwrap(); let recipient = Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap(); let _confirmation_future = tester.signer.add_request(ConfirmationPayload::SendTransaction(FilledTransactionRequest { from: address, @@ -308,7 +305,7 @@ fn should_confirm_transaction_with_token() { let request = r#"{ "jsonrpc":"2.0", "method":"signer_confirmRequestWithToken", - "params":["0x1", {"gasPrice":"0x1000"}, ""#.to_owned() + &token + r#""], + "params":["0x1", {"gasPrice":"0x1000"}, ""#.to_owned() + token.as_str() + r#""], "id":1 }"#; let response = r#"{"jsonrpc":"2.0","result":{"result":""#.to_owned() + @@ -326,7 +323,7 @@ fn should_confirm_transaction_with_token() { fn should_confirm_transaction_with_rlp() { // given let tester = signer_tester(); - let address = tester.accounts.new_account("test").unwrap(); + let address = tester.accounts.new_account(&"test".into()).unwrap(); let recipient = Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap(); let _confirmation_future = tester.signer.add_request(ConfirmationPayload::SendTransaction(FilledTransactionRequest { from: address, @@ -373,7 +370,7 @@ fn should_confirm_transaction_with_rlp() { fn should_return_error_when_sender_does_not_match() { // given let tester = signer_tester(); - let address = tester.accounts.new_account("test").unwrap(); + let address = tester.accounts.new_account(&"test".into()).unwrap(); let recipient = Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap(); let _confirmation_future = tester.signer.add_request(ConfirmationPayload::SendTransaction(FilledTransactionRequest { from: Address::default(), @@ -420,7 +417,7 @@ fn should_return_error_when_sender_does_not_match() { fn should_confirm_sign_transaction_with_rlp() { // given let tester = signer_tester(); - let address = tester.accounts.new_account("test").unwrap(); + let address = tester.accounts.new_account(&"test".into()).unwrap(); let recipient = Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap(); let _confirmation_future = tester.signer.add_request(ConfirmationPayload::SignTransaction(FilledTransactionRequest { from: address, @@ -485,7 +482,7 @@ fn should_confirm_sign_transaction_with_rlp() { fn should_confirm_data_sign_with_signature() { // given let tester = signer_tester(); - let address = tester.accounts.new_account("test").unwrap(); + let address = tester.accounts.new_account(&"test".into()).unwrap(); let _confirmation_future = tester.signer.add_request(ConfirmationPayload::EthSignMessage( address, vec![1, 2, 3, 4].into(), @@ -515,7 +512,7 @@ fn should_confirm_data_sign_with_signature() { fn should_confirm_decrypt_with_phrase() { // given let tester = signer_tester(); - let address = tester.accounts.new_account("test").unwrap(); + let address = tester.accounts.new_account(&"test".into()).unwrap(); let _confirmation_future = tester.signer.add_request(ConfirmationPayload::Decrypt( address, vec![1, 2, 3, 4].into(), diff --git a/rpc/src/v1/tests/mocked/signing.rs b/rpc/src/v1/tests/mocked/signing.rs index 84cf2e376e4845a3d87d33fca7b2d96ffb171ab3..c063ee09601b5879646ef1c3ab0f6368bc7dbbaa 100644 --- a/rpc/src/v1/tests/mocked/signing.rs +++ b/rpc/src/v1/tests/mocked/signing.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -56,7 +56,6 @@ impl Default for SigningTester { let client = Arc::new(TestBlockChainClient::default()); let miner = Arc::new(TestMinerService::default()); let accounts = Arc::new(AccountProvider::transient_provider()); - let opt_accounts = accounts.clone(); let reservations = Arc::new(Mutex::new(nonce::Reservations::new())); let mut io = IoHandler::default(); @@ -64,9 +63,9 @@ impl Default for SigningTester { let remote = Remote::new_thread_per_future(); - let rpc = SigningQueueClient::new(&signer, dispatcher.clone(), remote.clone(), &opt_accounts); + let rpc = SigningQueueClient::new(&signer, dispatcher.clone(), remote.clone(), &accounts); io.extend_with(EthSigning::to_delegate(rpc)); - let rpc = SigningQueueClient::new(&signer, dispatcher, remote, &opt_accounts); + let rpc = SigningQueueClient::new(&signer, dispatcher, remote, &accounts); io.extend_with(ParitySigning::to_delegate(rpc)); SigningTester { @@ -110,7 +109,8 @@ fn should_add_sign_to_queue() { ::std::thread::spawn(move || loop { if signer.requests().len() == 1 { // respond - signer.request_confirmed(1.into(), Ok(ConfirmationResponse::Signature(0.into()))); + let sender = signer.take(&1.into()).unwrap(); + signer.request_confirmed(sender, Ok(ConfirmationResponse::Signature(0.into()))); break } ::std::thread::sleep(Duration::from_millis(100)) @@ -188,7 +188,8 @@ fn should_check_status_of_request_when_its_resolved() { "id": 1 }"#; tester.io.handle_request_sync(&request).expect("Sent"); - tester.signer.request_confirmed(1.into(), Ok(ConfirmationResponse::Signature(1.into()))); + let sender = tester.signer.take(&1.into()).unwrap(); + tester.signer.request_confirmed(sender, Ok(ConfirmationResponse::Signature(1.into()))); // This is not ideal, but we need to give futures some time to be executed, and they need to run in a separate thread thread::sleep(Duration::from_millis(20)); @@ -211,7 +212,7 @@ fn should_sign_if_account_is_unlocked() { // given let tester = eth_signing(); let data = vec![5u8]; - let acc = tester.accounts.insert_account(Secret::from([69u8; 32]), "test").unwrap(); + let acc = tester.accounts.insert_account(Secret::from([69u8; 32]), &"test".into()).unwrap(); tester.accounts.unlock_account_permanently(acc, "test".into()).unwrap(); // when @@ -259,7 +260,8 @@ fn should_add_transaction_to_queue() { ::std::thread::spawn(move || loop { if signer.requests().len() == 1 { // respond - signer.request_confirmed(1.into(), Ok(ConfirmationResponse::SendTransaction(0.into()))); + let sender = signer.take(&1.into()).unwrap(); + signer.request_confirmed(sender, Ok(ConfirmationResponse::SendTransaction(0.into()))); break } ::std::thread::sleep(Duration::from_millis(100)) @@ -273,7 +275,7 @@ fn should_add_transaction_to_queue() { fn should_add_sign_transaction_to_the_queue() { // given let tester = eth_signing(); - let address = tester.accounts.new_account("test").unwrap(); + let address = tester.accounts.new_account(&"test".into()).unwrap(); assert_eq!(tester.signer.requests().len(), 0); @@ -335,8 +337,9 @@ fn should_add_sign_transaction_to_the_queue() { ::std::thread::spawn(move || loop { if signer.requests().len() == 1 { // respond - signer.request_confirmed(1.into(), Ok(ConfirmationResponse::SignTransaction( - RichRawTransaction::from_signed(t.into(), 0x0, u64::max_value()) + let sender = signer.take(&1.into()).unwrap(); + signer.request_confirmed(sender, Ok(ConfirmationResponse::SignTransaction( + RichRawTransaction::from_signed(t.into()) ))); break } @@ -351,7 +354,7 @@ fn should_add_sign_transaction_to_the_queue() { fn should_dispatch_transaction_if_account_is_unlock() { // given let tester = eth_signing(); - let acc = tester.accounts.new_account("test").unwrap(); + let acc = tester.accounts.new_account(&"test".into()).unwrap(); tester.accounts.unlock_account_permanently(acc, "test".into()).unwrap(); let t = Transaction { @@ -390,10 +393,9 @@ fn should_decrypt_message_if_account_is_unlocked() { let mut tester = eth_signing(); let parity = parity::Dependencies::new(); tester.io.extend_with(parity.client(None).to_delegate()); - let (address, public) = tester.accounts.new_account_and_public("test").unwrap(); + let (address, public) = tester.accounts.new_account_and_public(&"test".into()).unwrap(); tester.accounts.unlock_account_permanently(address, "test".into()).unwrap(); - // First encrypt message let request = format!("{}0x{:x}{}", r#"{"jsonrpc": "2.0", "method": "parity_encryptMessage", "params":[""#, @@ -442,7 +444,8 @@ fn should_add_decryption_to_the_queue() { ::std::thread::spawn(move || loop { if signer.requests().len() == 1 { // respond - signer.request_confirmed(1.into(), Ok(ConfirmationResponse::Decrypt(vec![0x1, 0x2].into()))); + let sender = signer.take(&1.into()).unwrap(); + signer.request_confirmed(sender, Ok(ConfirmationResponse::Decrypt(vec![0x1, 0x2].into()))); break } ::std::thread::sleep(Duration::from_millis(10)) @@ -473,7 +476,6 @@ fn should_compose_transaction() { + &from + r#"","gas":"0x5208","gasPrice":"0x4a817c800","nonce":"0x0","to":null,"value":"0x5"},"id":1}"#; - // then let res = tester.io.handle_request(&request).wait().unwrap(); assert_eq!(res, Some(response.to_owned())); diff --git a/rpc/src/v1/tests/mocked/traces.rs b/rpc/src/v1/tests/mocked/traces.rs index 0b2e7d5ccb84ead1dd078937b8658d0a8da1f7bb..48c96377923b0a6a48f2418dcac9b291622bfaf1 100644 --- a/rpc/src/v1/tests/mocked/traces.rs +++ b/rpc/src/v1/tests/mocked/traces.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -238,7 +238,7 @@ fn rpc_trace_replay_block_transactions() { let tester = io(); let request = r#"{"jsonrpc":"2.0","method":"trace_replayBlockTransactions","params":["0x10", ["trace", "stateDiff", "vmTrace"]],"id":1}"#; - let response = r#"{"jsonrpc":"2.0","result":[{"output":"0x010203","stateDiff":null,"trace":[],"vmTrace":null}],"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":[{"output":"0x010203","stateDiff":null,"trace":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000005","vmTrace":null}],"id":1}"#; assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); } diff --git a/rpc/src/v1/tests/mocked/web3.rs b/rpc/src/v1/tests/mocked/web3.rs index 3c78d67ad388b88b82257e382ee565da144d3702..e16c5f4926fd086e3291515a4a3d3486a485d7da 100644 --- a/rpc/src/v1/tests/mocked/web3.rs +++ b/rpc/src/v1/tests/mocked/web3.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/tests/mod.rs b/rpc/src/v1/tests/mod.rs index 31ac1c5410cb6a1275165ac755c54dc8226abe4a..471569e52319155f1c807dee81e4160cbc29d650 100644 --- a/rpc/src/v1/tests/mod.rs +++ b/rpc/src/v1/tests/mod.rs @@ -1,3 +1,19 @@ +// 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 . + //! RPC unit test moduleS pub mod helpers; diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index f4ea1e10d6dbe3708617ebd59fcd3fada561d54a..48e315ce7e9f0a68d533bb563d92de79111bcb06 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/eth_pubsub.rs b/rpc/src/v1/traits/eth_pubsub.rs index cfbe4c54bcb617006d99b532593b7347ce7bf053..38babeef42c85c9bbe686920346ae79fdeab7e2f 100644 --- a/rpc/src/v1/traits/eth_pubsub.rs +++ b/rpc/src/v1/traits/eth_pubsub.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/eth_signing.rs b/rpc/src/v1/traits/eth_signing.rs index 9830ac54d8272c100867fc64e381adb56dbc9a41..27657475bab4b6e60e913e41e88988acca1f3449 100644 --- a/rpc/src/v1/traits/eth_signing.rs +++ b/rpc/src/v1/traits/eth_signing.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/mod.rs b/rpc/src/v1/traits/mod.rs index 26a43fa3f833e2a52034410c7444d41905331e32..62edac8ed666ba55ad0abdbf6ea91dd9b2d3f734 100644 --- a/rpc/src/v1/traits/mod.rs +++ b/rpc/src/v1/traits/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/net.rs b/rpc/src/v1/traits/net.rs index bc2068ff9ab7eaf5d6505a13702ce3db1e66fe91..d70a4653a6e01ba10487b03f796fa331fa531803 100644 --- a/rpc/src/v1/traits/net.rs +++ b/rpc/src/v1/traits/net.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/parity.rs b/rpc/src/v1/traits/parity.rs index 83d8b19811cf2f2191b3302a36633fb17c713440..1cc6aca9629fc344c861bbaa42cfe59d0921233a 100644 --- a/rpc/src/v1/traits/parity.rs +++ b/rpc/src/v1/traits/parity.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -21,7 +21,6 @@ use std::collections::BTreeMap; use jsonrpc_core::{BoxFuture, Result}; use jsonrpc_macros::Trailing; -use node_health::Health; use v1::types::{ H160, H256, H512, U256, U64, Bytes, CallRequest, Peers, Transaction, RpcSettings, Histogram, @@ -141,7 +140,7 @@ build_rpc_trait! { /// Returns all pending transactions from transaction queue. #[rpc(name = "parity_pendingTransactions")] - fn pending_transactions(&self) -> Result>; + fn pending_transactions(&self, Trailing) -> Result>; /// Returns all transactions from transaction queue. /// @@ -161,10 +160,6 @@ build_rpc_trait! { #[rpc(name = "parity_localTransactions")] fn local_transactions(&self) -> Result>; - /// Returns current Dapps Server interface and port or an error if dapps server is disabled. - #[rpc(name = "parity_dappsUrl")] - fn dapps_url(&self) -> Result; - /// Returns current WS Server interface and port or an error if ws server is disabled. #[rpc(name = "parity_wsUrl")] fn ws_url(&self) -> Result; @@ -223,9 +218,5 @@ build_rpc_trait! { /// Call contract, returning the output data. #[rpc(meta, name = "parity_call")] fn call(&self, Self::Metadata, Vec, Trailing) -> Result>; - - /// Returns node's health report. - #[rpc(name = "parity_nodeHealth")] - fn node_health(&self) -> BoxFuture; } } diff --git a/rpc/src/v1/traits/parity_accounts.rs b/rpc/src/v1/traits/parity_accounts.rs index 494f1576cbd903b0902c5b0ae2ac076ec10bb79c..c7bc21771b82906b56ed7ce479979c1b784be0f8 100644 --- a/rpc/src/v1/traits/parity_accounts.rs +++ b/rpc/src/v1/traits/parity_accounts.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -18,6 +18,7 @@ use std::collections::BTreeMap; use jsonrpc_core::Result; +use ethkey::Password; use ethstore::KeyFile; use v1::types::{H160, H256, H520, DappId, DeriveHash, DeriveHierarchical, ExtAccountInfo}; @@ -31,32 +32,32 @@ build_rpc_trait! { /// Creates new account from the given phrase using standard brainwallet mechanism. /// Second parameter is password for the new account. #[rpc(name = "parity_newAccountFromPhrase")] - fn new_account_from_phrase(&self, String, String) -> Result; + fn new_account_from_phrase(&self, String, Password) -> Result; /// Creates new account from the given JSON wallet. /// Second parameter is password for the wallet and the new account. #[rpc(name = "parity_newAccountFromWallet")] - fn new_account_from_wallet(&self, String, String) -> Result; + fn new_account_from_wallet(&self, String, Password) -> Result; /// Creates new account from the given raw secret. /// Second parameter is password for the new account. #[rpc(name = "parity_newAccountFromSecret")] - fn new_account_from_secret(&self, H256, String) -> Result; + fn new_account_from_secret(&self, H256, Password) -> Result; /// Returns true if given `password` would unlock given `account`. /// Arguments: `account`, `password`. #[rpc(name = "parity_testPassword")] - fn test_password(&self, H160, String) -> Result; + fn test_password(&self, H160, Password) -> Result; /// Changes an account's password. /// Arguments: `account`, `password`, `new_password`. #[rpc(name = "parity_changePassword")] - fn change_password(&self, H160, String, String) -> Result; + fn change_password(&self, H160, Password, Password) -> Result; /// Permanently deletes an account. /// Arguments: `account`, `password`. #[rpc(name = "parity_killAccount")] - fn kill_account(&self, H160, String) -> Result; + fn kill_account(&self, H160, Password) -> Result; /// Permanently deletes an address from the addressbook /// Arguments: `address` @@ -132,11 +133,11 @@ build_rpc_trait! { /// Create new vault. #[rpc(name = "parity_newVault")] - fn create_vault(&self, String, String) -> Result; + fn create_vault(&self, String, Password) -> Result; /// Open existing vault. #[rpc(name = "parity_openVault")] - fn open_vault(&self, String, String) -> Result; + fn open_vault(&self, String, Password) -> Result; /// Close previously opened vault. #[rpc(name = "parity_closeVault")] @@ -152,7 +153,7 @@ build_rpc_trait! { /// Change vault password. #[rpc(name = "parity_changeVaultPassword")] - fn change_vault_password(&self, String, String) -> Result; + fn change_vault_password(&self, String, Password) -> Result; /// Change vault of the given address. #[rpc(name = "parity_changeVault")] @@ -169,21 +170,21 @@ build_rpc_trait! { /// Derive new address from given account address using specific hash. /// Resulting address can be either saved as a new account (with the same password). #[rpc(name = "parity_deriveAddressHash")] - fn derive_key_hash(&self, H160, String, DeriveHash, bool) -> Result; + fn derive_key_hash(&self, H160, Password, DeriveHash, bool) -> Result; /// Derive new address from given account address using /// hierarchical derivation (sequence of 32-bit integer indices). /// Resulting address can be either saved as a new account (with the same password). #[rpc(name = "parity_deriveAddressIndex")] - fn derive_key_index(&self, H160, String, DeriveHierarchical, bool) -> Result; + fn derive_key_index(&self, H160, Password, DeriveHierarchical, bool) -> Result; /// Exports an account with given address if provided password matches. #[rpc(name = "parity_exportAccount")] - fn export_account(&self, H160, String) -> Result; + fn export_account(&self, H160, Password) -> Result; /// Sign raw hash with the key corresponding to address and password. #[rpc(name = "parity_signMessage")] - fn sign_message(&self, H160, String, H256) -> Result; + fn sign_message(&self, H160, Password, H256) -> Result; /// Send a PinMatrixAck to a hardware wallet, unlocking it #[rpc(name = "parity_hardwarePinMatrixAck")] diff --git a/rpc/src/v1/traits/parity_set.rs b/rpc/src/v1/traits/parity_set.rs index 40aad1a4bd909b16bbbc2d56a430be74026b4e6b..707758920f6bcf932a72b7682ce0934f4eba65e4 100644 --- a/rpc/src/v1/traits/parity_set.rs +++ b/rpc/src/v1/traits/parity_set.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -18,7 +18,7 @@ use jsonrpc_core::{BoxFuture, Result}; -use v1::types::{Bytes, H160, H256, U256, ReleaseInfo, Transaction, LocalDapp}; +use v1::types::{Bytes, H160, H256, U256, ReleaseInfo, Transaction}; build_rpc_trait! { /// Parity-specific rpc interface for operations altering the settings. @@ -95,14 +95,6 @@ build_rpc_trait! { #[rpc(name = "parity_hashContent")] fn hash_content(&self, String) -> BoxFuture; - /// Returns true if refresh successful, error if unsuccessful or server is disabled. - #[rpc(name = "parity_dappsRefresh")] - fn dapps_refresh(&self) -> Result; - - /// Returns a list of local dapps - #[rpc(name = "parity_dappsList")] - fn dapps_list(&self) -> Result>; - /// Is there a release ready for install? #[rpc(name = "parity_upgradeReady")] fn upgrade_ready(&self) -> Result>; diff --git a/rpc/src/v1/traits/parity_signing.rs b/rpc/src/v1/traits/parity_signing.rs index 8015b04317bb755d6fb5933ee9a1e7951ace48bf..208422222ec538eb522677961d15ba1a6a38b9f2 100644 --- a/rpc/src/v1/traits/parity_signing.rs +++ b/rpc/src/v1/traits/parity_signing.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/personal.rs b/rpc/src/v1/traits/personal.rs index 7c187fcffe9bd22954a36f24fd5c443375a40a22..7187219105aa6801b4f681dfe4c2bb60fa878b89 100644 --- a/rpc/src/v1/traits/personal.rs +++ b/rpc/src/v1/traits/personal.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/private.rs b/rpc/src/v1/traits/private.rs index 7106e0bf43e1b1d9f1306bf2cdb4e89af319ca46..b7b1aa20a78297a764ec2f6135c133f03a52a825 100644 --- a/rpc/src/v1/traits/private.rs +++ b/rpc/src/v1/traits/private.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/pubsub.rs b/rpc/src/v1/traits/pubsub.rs index 0b77fc64d6e309ca178e8bf0f0ce25caad47ae80..840de8d4b0fd3e5ad9cef25cb67068eeb6baf0e5 100644 --- a/rpc/src/v1/traits/pubsub.rs +++ b/rpc/src/v1/traits/pubsub.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/rpc.rs b/rpc/src/v1/traits/rpc.rs index a813aa94e67c4dcc6b41984a4e2d728676e00bf6..8c0b3c2c90520e4580982c51598a39bc447f0343 100644 --- a/rpc/src/v1/traits/rpc.rs +++ b/rpc/src/v1/traits/rpc.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/secretstore.rs b/rpc/src/v1/traits/secretstore.rs index 6d2e5669c007ac4f2f88ea3202608c1d5671a215..83f63b2802bb0ee30557480b4da50e340aa525e6 100644 --- a/rpc/src/v1/traits/secretstore.rs +++ b/rpc/src/v1/traits/secretstore.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -18,6 +18,7 @@ use std::collections::BTreeSet; use jsonrpc_core::Result; +use ethkey::Password; use v1::types::{H160, H256, H512, Bytes, EncryptedDocumentKey}; @@ -27,22 +28,22 @@ build_rpc_trait! { /// Generate document key to store in secret store. /// Arguments: `account`, `password`, `server_key_public`. #[rpc(name = "secretstore_generateDocumentKey")] - fn generate_document_key(&self, H160, String, H512) -> Result; + fn generate_document_key(&self, H160, Password, H512) -> Result; /// Encrypt data with key, received from secret store. /// Arguments: `account`, `password`, `key`, `data`. #[rpc(name = "secretstore_encrypt")] - fn encrypt(&self, H160, String, Bytes, Bytes) -> Result; + fn encrypt(&self, H160, Password, Bytes, Bytes) -> Result; /// Decrypt data with key, received from secret store. /// Arguments: `account`, `password`, `key`, `data`. #[rpc(name = "secretstore_decrypt")] - fn decrypt(&self, H160, String, Bytes, Bytes) -> Result; + fn decrypt(&self, H160, Password, Bytes, Bytes) -> Result; /// Decrypt data with shadow key, received from secret store. /// Arguments: `account`, `password`, `decrypted_secret`, `common_point`, `decrypt_shadows`, `data`. #[rpc(name = "secretstore_shadowDecrypt")] - fn shadow_decrypt(&self, H160, String, H512, H512, Vec, Bytes) -> Result; + fn shadow_decrypt(&self, H160, Password, H512, H512, Vec, Bytes) -> Result; /// Calculates the hash (keccak256) of servers set for using in ServersSetChange session. /// Returned hash must be signed later by using `secretstore_signRawHash` method. @@ -54,6 +55,6 @@ build_rpc_trait! { /// Passed hash is treated as an input to the `sign` function (no prefixes added, no hash function is applied). /// Arguments: `account`, `password`, `raw_hash`. #[rpc(name = "secretstore_signRawHash")] - fn sign_raw_hash(&self, H160, String, H256) -> Result; + fn sign_raw_hash(&self, H160, Password, H256) -> Result; } } diff --git a/rpc/src/v1/traits/signer.rs b/rpc/src/v1/traits/signer.rs index b7f60619e805619220fcc083c552beb1368dd5df..4ede0ce534a99c677ced8f0ef304d6f1258b56c7 100644 --- a/rpc/src/v1/traits/signer.rs +++ b/rpc/src/v1/traits/signer.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/traces.rs b/rpc/src/v1/traits/traces.rs index 1fe01f47ef66869ea0ffc65ce1101304bffa8e95..91d460864971009bd320e07ae4f90b7a9615eb9a 100644 --- a/rpc/src/v1/traits/traces.rs +++ b/rpc/src/v1/traits/traces.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -18,7 +18,7 @@ use jsonrpc_core::Result; use jsonrpc_macros::Trailing; -use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, H256, TraceOptions}; +use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, TraceResultsWithTransactionHash, H256, TraceOptions}; build_rpc_trait! { /// Traces specific rpc interface. @@ -59,6 +59,6 @@ build_rpc_trait! { /// Executes all the transactions at the given block and returns a number of possible traces for each transaction. #[rpc(name = "trace_replayBlockTransactions")] - fn replay_block_transactions(&self, BlockNumber, TraceOptions) -> Result>; + fn replay_block_transactions(&self, BlockNumber, TraceOptions) -> Result>; } } diff --git a/rpc/src/v1/traits/web3.rs b/rpc/src/v1/traits/web3.rs index e4fb8b0d1fbe6b0ce8c1312b2d87d8029a456929..713cd9a32d3ffd38d7a0293f4c91c5c4bc3c598f 100644 --- a/rpc/src/v1/traits/web3.rs +++ b/rpc/src/v1/traits/web3.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/account_info.rs b/rpc/src/v1/types/account_info.rs index f9cabb450bd28159c4ba76c685a158519e8665f5..5a0e2952a18b8d69270973f1672789a597bcd76e 100644 --- a/rpc/src/v1/types/account_info.rs +++ b/rpc/src/v1/types/account_info.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -41,4 +41,3 @@ pub struct HwAccountInfo { /// Device manufacturer. pub manufacturer: String, } - diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index 486e3b9c140a6d578572b9f1cc6b6bc2cd74c647..9ae870dc5584af1dade04f221d91be676a01a1bd 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/block_number.rs b/rpc/src/v1/types/block_number.rs index b6c1860f5ba4202c4048f3d7163ee8f76eb791d6..b92a0d4a3fe0f3d142a08b436e8bb9987dc09fdc 100644 --- a/rpc/src/v1/types/block_number.rs +++ b/rpc/src/v1/types/block_number.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -135,4 +135,3 @@ mod tests { block_number_to_id(BlockNumber::Pending); } } - diff --git a/rpc/src/v1/types/bytes.rs b/rpc/src/v1/types/bytes.rs index fdbcb729bbf615b604560b1800cb92ce23a4feb8..0bd62c601c96ab9c40853287b36ec734fbaaf910 100644 --- a/rpc/src/v1/types/bytes.rs +++ b/rpc/src/v1/types/bytes.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -86,7 +86,6 @@ impl<'a> Visitor<'a> for BytesVisitor { } } - #[cfg(test)] mod tests { use super::*; @@ -118,4 +117,3 @@ mod tests { assert_eq!(bytes6, Bytes(vec![0x1, 0x23])); } } - diff --git a/rpc/src/v1/types/call_request.rs b/rpc/src/v1/types/call_request.rs index 71b562e45a71036af6901f2177455555390d0ebd..39d4d17b785dd540bf36aeeba00cc3c2c96ff166 100644 --- a/rpc/src/v1/types/call_request.rs +++ b/rpc/src/v1/types/call_request.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/confirmations.rs b/rpc/src/v1/types/confirmations.rs index 5dcb11316c2c5d4bda9aa33b213c830596c4bfb8..477546aa4f912e53abae9bdc6ae36f463d6676ec 100644 --- a/rpc/src/v1/types/confirmations.rs +++ b/rpc/src/v1/types/confirmations.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -23,6 +23,7 @@ use bytes::ToPretty; use v1::types::{U256, TransactionRequest, RichRawTransaction, H160, H256, H520, Bytes, TransactionCondition, Origin}; use v1::helpers; +use ethkey::Password; /// Confirmation waiting in a queue #[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] @@ -149,12 +150,12 @@ impl Serialize for ConfirmationResponse { } /// Confirmation response with additional token for further requests -#[derive(Debug, Clone, PartialEq, Serialize)] +#[derive(Clone, PartialEq, Serialize)] pub struct ConfirmationResponseWithToken { /// Actual response pub result: ConfirmationResponse, /// New token - pub token: String, + pub token: Password, } /// Confirmation payload, i.e. the thing to be confirmed diff --git a/rpc/src/v1/types/consensus_status.rs b/rpc/src/v1/types/consensus_status.rs index 96657adbc9185ba8da97fa3a2949ddf80b80359d..0cbdf1f007864be6f3d83ba425e6fee23bc9324b 100644 --- a/rpc/src/v1/types/consensus_status.rs +++ b/rpc/src/v1/types/consensus_status.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/dapps.rs b/rpc/src/v1/types/dapps.rs deleted file mode 100644 index 418717fccfb9735b47d97aa7a6e3cfb72b3d0e9c..0000000000000000000000000000000000000000 --- a/rpc/src/v1/types/dapps.rs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2015-2017 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 . - -/// Local Dapp -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct LocalDapp { - /// ID of local dapp - pub id: String, - /// Dapp name - pub name: String, - /// Dapp description - pub description: String, - /// Dapp version string - pub version: String, - /// Dapp author - pub author: String, - /// Dapp icon - #[serde(rename="iconUrl")] - pub icon_url: String, - /// Local development Url - #[serde(rename="localUrl")] - pub local_url: Option, -} - -#[cfg(test)] -mod tests { - use serde_json; - use super::LocalDapp; - - #[test] - fn dapp_serialization() { - let s = r#"{"id":"skeleton","name":"Skeleton","description":"A skeleton dapp","version":"0.1","author":"Parity Technologies Ltd","iconUrl":"title.png","localUrl":"http://localhost:5000"}"#; - - let dapp = LocalDapp { - id: "skeleton".into(), - name: "Skeleton".into(), - description: "A skeleton dapp".into(), - version: "0.1".into(), - author: "Parity Technologies Ltd".into(), - icon_url: "title.png".into(), - local_url: Some("http://localhost:5000".into()), - }; - - let serialized = serde_json::to_string(&dapp).unwrap(); - assert_eq!(serialized, s); - } -} diff --git a/rpc/src/v1/types/derivation.rs b/rpc/src/v1/types/derivation.rs index 76becbaebe041cf6d4b7f66c9385489c3dcf0f71..0e39b65322f80c11d11218107ef81d78a5ecd839 100644 --- a/rpc/src/v1/types/derivation.rs +++ b/rpc/src/v1/types/derivation.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/filter.rs b/rpc/src/v1/types/filter.rs index 52217459c1f81ccdb6eff58b39177476fa41a5d7..dd8b823e879bcb823affc702f31e88f7f7e25b82 100644 --- a/rpc/src/v1/types/filter.rs +++ b/rpc/src/v1/types/filter.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/hash.rs b/rpc/src/v1/types/hash.rs index e3cc73e2720dbd3a3d0f11772022434f953a6c42..07c7ef24f45178353858c4149f79ad5aae8f34aa 100644 --- a/rpc/src/v1/types/hash.rs +++ b/rpc/src/v1/types/hash.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/histogram.rs b/rpc/src/v1/types/histogram.rs index 26bbc7d2de4272e8c15d75da3d7f079f302e2110..2b71b88bf6f5c40a28d5d1259d84f5c7c1b8aff1 100644 --- a/rpc/src/v1/types/histogram.rs +++ b/rpc/src/v1/types/histogram.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -12,7 +12,7 @@ // 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 . +// along with Parity. If not, see . //! Gas prices histogram. diff --git a/rpc/src/v1/types/index.rs b/rpc/src/v1/types/index.rs index 4e44ce49cea2c0a4e9c1d8a39e3b7a3f3fa2b826..4c8af6000451f34cf3353a1f377ba8da1a0370cc 100644 --- a/rpc/src/v1/types/index.rs +++ b/rpc/src/v1/types/index.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -73,4 +73,3 @@ mod tests { assert_eq!(deserialized, vec![Index(10), Index(10)]); } } - diff --git a/rpc/src/v1/types/log.rs b/rpc/src/v1/types/log.rs index e178516d6d11f1c02b79abc55848c6911861fe18..950b649d7d0b3cdb3205d27175dcfc444fe7f4f5 100644 --- a/rpc/src/v1/types/log.rs +++ b/rpc/src/v1/types/log.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -47,6 +47,9 @@ pub struct Log { /// Log Type #[serde(rename="type")] pub log_type: String, + /// Whether Log Type is Removed (Geth Compatibility Field) + #[serde(default)] + pub removed: bool, } impl From for Log { @@ -62,6 +65,7 @@ impl From for Log { log_index: Some(e.log_index.into()), transaction_log_index: Some(e.transaction_log_index.into()), log_type: "mined".to_owned(), + removed: false, } } } @@ -79,6 +83,7 @@ impl From for Log { log_index: None, transaction_log_index: None, log_type: "pending".to_owned(), + removed: false, } } } @@ -91,7 +96,7 @@ mod tests { #[test] fn log_serialization() { - let s = r#"{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"data":"0x","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","logIndex":"0x1","transactionLogIndex":"0x1","type":"mined"}"#; + let s = r#"{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"data":"0x","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","logIndex":"0x1","transactionLogIndex":"0x1","type":"mined","removed":false}"#; let log = Log { address: H160::from_str("33990122638b9132ca29c723bdf037f1a891a70c").unwrap(), @@ -107,6 +112,7 @@ mod tests { transaction_log_index: Some(1.into()), log_index: Some(U256::from(1)), log_type: "mined".to_owned(), + removed: false, }; let serialized = serde_json::to_string(&log).unwrap(); diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index e7f764b8b1b8804f32ecc8012d9a94f7ff7553c6..0f21e2f7b5b14024ad14b79221e2b19c7c61733b 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . - //! RPC types mod account_info; @@ -24,7 +23,6 @@ mod bytes; mod call_request; mod confirmations; mod consensus_status; -mod dapps; mod derivation; mod filter; mod hash; @@ -58,7 +56,6 @@ pub use self::confirmations::{ TransactionModification, SignRequest, DecryptRequest, Either }; pub use self::consensus_status::*; -pub use self::dapps::LocalDapp; pub use self::derivation::{DeriveHash, DeriveHierarchical, Derive}; pub use self::filter::{Filter, FilterChanges}; pub use self::hash::{H64, H160, H256, H512, H520, H2048}; @@ -74,7 +71,7 @@ pub use self::sync::{ SyncStatus, SyncInfo, Peers, PeerInfo, PeerNetworkInfo, PeerProtocolsInfo, TransactionStats, ChainStatus, EthProtocolInfo, PipProtocolInfo, }; -pub use self::trace::{LocalizedTrace, TraceResults}; +pub use self::trace::{LocalizedTrace, TraceResults, TraceResultsWithTransactionHash}; pub use self::trace_filter::TraceFilter; pub use self::transaction::{Transaction, RichRawTransaction, LocalTransactionStatus}; pub use self::transaction_request::TransactionRequest; diff --git a/rpc/src/v1/types/node_kind.rs b/rpc/src/v1/types/node_kind.rs index 5c96fafc6306f19d3b4eb95f861712d4c0746639..8061d82808f28eae5031f8fe50657a463427717c 100644 --- a/rpc/src/v1/types/node_kind.rs +++ b/rpc/src/v1/types/node_kind.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/private_receipt.rs b/rpc/src/v1/types/private_receipt.rs index 328013d7f60ebe318bf7d21dc1f94eba04ec509a..7e758af3a5f5d7334b5aa1160ad23103745581c2 100644 --- a/rpc/src/v1/types/private_receipt.rs +++ b/rpc/src/v1/types/private_receipt.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -51,4 +51,3 @@ pub struct PrivateTransactionReceiptAndTransaction { #[serde(rename="transaction")] pub transaction: TransactionRequest, } - diff --git a/rpc/src/v1/types/provenance.rs b/rpc/src/v1/types/provenance.rs index 6bcd43a21fa697367de71d8776e79c46cb885984..328f2ded3e6e1d21c27be857379282e9e4af710c 100644 --- a/rpc/src/v1/types/provenance.rs +++ b/rpc/src/v1/types/provenance.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/pubsub.rs b/rpc/src/v1/types/pubsub.rs index dfac5a0abb561a333a094bce7ea3b859a39af5ca..ea01d6427bd2941ee2df57ebab1246fe0b09877c 100644 --- a/rpc/src/v1/types/pubsub.rs +++ b/rpc/src/v1/types/pubsub.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/receipt.rs b/rpc/src/v1/types/receipt.rs index e20856b8225993dd027a5a1ed80fa6c8d55503a3..9688f7d371634419df07430d11018905db9d2a39 100644 --- a/rpc/src/v1/types/receipt.rs +++ b/rpc/src/v1/types/receipt.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -29,6 +29,10 @@ pub struct Receipt { /// Block hash #[serde(rename="blockHash")] pub block_hash: Option, + /// Sender + pub from: Option, + /// Recipient + pub to: Option, /// Block number #[serde(rename="blockNumber")] pub block_number: Option, @@ -73,6 +77,8 @@ impl Receipt { impl From for Receipt { fn from(r: LocalizedReceipt) -> Self { Receipt { + to: r.to.map(Into::into), + from: Some(r.from.into()), transaction_hash: Some(r.transaction_hash.into()), transaction_index: Some(r.transaction_index.into()), block_hash: Some(r.block_hash.into()), @@ -91,6 +97,8 @@ impl From for Receipt { impl From for Receipt { fn from(r: RichReceipt) -> Self { Receipt { + from: None, + to: None, transaction_hash: Some(r.transaction_hash.into()), transaction_index: Some(r.transaction_index.into()), block_hash: None, @@ -109,6 +117,8 @@ impl From for Receipt { impl From for Receipt { fn from(r: EthReceipt) -> Self { Receipt { + from: None, + to: None, transaction_hash: None, transaction_index: None, block_hash: None, @@ -131,9 +141,11 @@ mod tests { #[test] fn receipt_serialization() { - let s = r#"{"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","cumulativeGasUsed":"0x20","gasUsed":"0x10","contractAddress":null,"logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"data":"0x","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","logIndex":"0x1","transactionLogIndex":null,"type":"mined"}],"root":"0x000000000000000000000000000000000000000000000000000000000000000a","logsBloom":"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f","status":"0x1"}"#; + let s = r#"{"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","from":null,"to":null,"blockNumber":"0x4510c","cumulativeGasUsed":"0x20","gasUsed":"0x10","contractAddress":null,"logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"data":"0x","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","logIndex":"0x1","transactionLogIndex":null,"type":"mined","removed":false}],"root":"0x000000000000000000000000000000000000000000000000000000000000000a","logsBloom":"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f","status":"0x1"}"#; let receipt = Receipt { + from: None, + to: None, transaction_hash: Some(0.into()), transaction_index: Some(0.into()), block_hash: Some("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5".parse().unwrap()), @@ -155,6 +167,7 @@ mod tests { transaction_log_index: None, log_index: Some(1.into()), log_type: "mined".into(), + removed: false, }], logs_bloom: 15.into(), state_root: Some(10.into()), @@ -165,4 +178,3 @@ mod tests { assert_eq!(serialized, s); } } - diff --git a/rpc/src/v1/types/rpc_settings.rs b/rpc/src/v1/types/rpc_settings.rs index bc5bf72171c03feeb46f544d0d776e3574fc067f..3be781f20617fc6c32d00abb3d66fe6961855a95 100644 --- a/rpc/src/v1/types/rpc_settings.rs +++ b/rpc/src/v1/types/rpc_settings.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -12,7 +12,7 @@ // 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 . +// along with Parity. If not, see . //! RPC Settings data. diff --git a/rpc/src/v1/types/secretstore.rs b/rpc/src/v1/types/secretstore.rs index 4388b308ba2053c95b4c62d92738ea54ad0a0fcc..22b61b5e15266f67ffeb8f1bd6280b5ce03b11f9 100644 --- a/rpc/src/v1/types/secretstore.rs +++ b/rpc/src/v1/types/secretstore.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/sync.rs b/rpc/src/v1/types/sync.rs index cbac3e1bbb7202f9fb7c46d063880ab0a6c46b40..ec43fb27d65314e9b81a358b2a03238b45985e6e 100644 --- a/rpc/src/v1/types/sync.rs +++ b/rpc/src/v1/types/sync.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/trace.rs b/rpc/src/v1/types/trace.rs index 6eb222f5e63092cca6ea75dc830ea08268417f64..5a69e74d196a153f8aedd5270c867229e702fa99 100644 --- a/rpc/src/v1/types/trace.rs +++ b/rpc/src/v1/types/trace.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -22,6 +22,7 @@ use ethcore::trace as et; use ethcore::state_diff; use ethcore::account_diff; use ethcore::client::Executed; +use ethereum_types::H256 as EthH256; use vm; use v1::types::{Bytes, H160, H256, U256}; @@ -327,7 +328,6 @@ impl From for RewardType { } } - /// Reward action #[derive(Debug, Serialize)] pub struct Reward { @@ -632,6 +632,36 @@ impl From for TraceResults { } } +#[derive(Debug, Serialize)] +/// A diff of some chunk of memory. +pub struct TraceResultsWithTransactionHash { + /// The output of the call/create + pub output: Bytes, + /// The transaction trace. + pub trace: Vec, + /// The transaction trace. + #[serde(rename="vmTrace")] + pub vm_trace: Option, + /// The transaction trace. + #[serde(rename="stateDiff")] + pub state_diff: Option, + /// The transaction Hash. + #[serde(rename="transactionHash")] + pub transaction_hash: H256, +} + +impl From<(EthH256, Executed)> for TraceResultsWithTransactionHash { + fn from(t: (EthH256, Executed)) -> Self { + TraceResultsWithTransactionHash { + output: t.1.output.into(), + trace: t.1.trace.into_iter().map(Into::into).collect(), + vm_trace: t.1.vm_trace.map(Into::into), + state_diff: t.1.state_diff.map(Into::into), + transaction_hash: t.0.into(), + } + } +} + #[cfg(test)] mod tests { use serde_json; diff --git a/rpc/src/v1/types/trace_filter.rs b/rpc/src/v1/types/trace_filter.rs index 3a64f5248895361ad33944f43300e4dce659b14a..83247dade02ae3376da73eba04f3f70bdc8f999d 100644 --- a/rpc/src/v1/types/trace_filter.rs +++ b/rpc/src/v1/types/trace_filter.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index 0ac3e3745424ab3260a4705cc60d584b10ad5645..4266f60b6231157bb150516fec04daf4e8dca489 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -161,8 +161,8 @@ pub struct RichRawTransaction { impl RichRawTransaction { /// Creates new `RichRawTransaction` from `SignedTransaction`. - pub fn from_signed(tx: SignedTransaction, block_number: u64, eip86_transition: u64) -> Self { - let tx = Transaction::from_signed(tx, block_number, eip86_transition); + pub fn from_signed(tx: SignedTransaction) -> Self { + let tx = Transaction::from_signed(tx); RichRawTransaction { raw: tx.raw.clone(), transaction: tx, @@ -172,9 +172,9 @@ impl RichRawTransaction { impl Transaction { /// Convert `LocalizedTransaction` into RPC Transaction. - pub fn from_localized(mut t: LocalizedTransaction, eip86_transition: u64) -> Transaction { + pub fn from_localized(mut t: LocalizedTransaction) -> Transaction { let signature = t.signature(); - let scheme = if t.block_number >= eip86_transition { CreateContractAddress::FromCodeHash } else { CreateContractAddress::FromSenderAndNonce }; + let scheme = CreateContractAddress::FromSenderAndNonce; Transaction { hash: t.hash().into(), nonce: t.nonce.into(), @@ -206,9 +206,9 @@ impl Transaction { } /// Convert `SignedTransaction` into RPC Transaction. - pub fn from_signed(t: SignedTransaction, block_number: u64, eip86_transition: u64) -> Transaction { + pub fn from_signed(t: SignedTransaction) -> Transaction { let signature = t.signature(); - let scheme = if block_number >= eip86_transition { CreateContractAddress::FromCodeHash } else { CreateContractAddress::FromSenderAndNonce }; + let scheme = CreateContractAddress::FromSenderAndNonce; Transaction { hash: t.hash().into(), nonce: t.nonce.into(), @@ -240,8 +240,8 @@ impl Transaction { } /// Convert `PendingTransaction` into RPC Transaction. - pub fn from_pending(t: PendingTransaction, block_number: u64, eip86_transition: u64) -> Transaction { - let mut r = Transaction::from_signed(t.transaction, block_number, eip86_transition); + pub fn from_pending(t: PendingTransaction) -> Transaction { + let mut r = Transaction::from_signed(t.transaction); r.condition = t.condition.map(|b| b.into()); r } @@ -249,9 +249,9 @@ impl Transaction { impl LocalTransactionStatus { /// Convert `LocalTransactionStatus` into RPC `LocalTransactionStatus`. - pub fn from(s: miner::pool::local_transactions::Status, block_number: u64, eip86_transition: u64) -> Self { + pub fn from(s: miner::pool::local_transactions::Status) -> Self { let convert = |tx: Arc| { - Transaction::from_signed(tx.signed().clone(), block_number, eip86_transition) + Transaction::from_signed(tx.signed().clone()) }; use miner::pool::local_transactions::Status::*; match s { @@ -327,4 +327,3 @@ mod tests { ); } } - diff --git a/rpc/src/v1/types/transaction_condition.rs b/rpc/src/v1/types/transaction_condition.rs index 541bd364a3696bf63c697f4008afdebec22919cd..65642224c2e62b663da8c714327a0e639e84124b 100644 --- a/rpc/src/v1/types/transaction_condition.rs +++ b/rpc/src/v1/types/transaction_condition.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -64,4 +64,3 @@ mod tests { assert_eq!(transaction::Condition::Timestamp(100), TransactionCondition::Timestamp(100).into()); } } - diff --git a/rpc/src/v1/types/transaction_request.rs b/rpc/src/v1/types/transaction_request.rs index 2d4c86c7e7711e4e12ac73ec686560d9db6d2e5f..4fa47b5acd6ed5c031f7298c334452517c069a6f 100644 --- a/rpc/src/v1/types/transaction_request.rs +++ b/rpc/src/v1/types/transaction_request.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -69,14 +69,20 @@ impl fmt::Display for TransactionRequest { f, "{} ETH from {} to 0x{:?}", Colour::White.bold().paint(format_ether(eth)), - Colour::White.bold().paint(format!("0x{:?}", self.from)), + Colour::White.bold().paint( + self.from.as_ref() + .map(|f| format!("0x{:?}", f)) + .unwrap_or_else(|| "?".to_string())), to ), None => write!( f, "{} ETH from {} for contract creation", Colour::White.bold().paint(format_ether(eth)), - Colour::White.bold().paint(format!("0x{:?}", self.from)), + Colour::White.bold().paint( + self.from.as_ref() + .map(|f| format!("0x{:?}", f)) + .unwrap_or_else(|| "?".to_string())), ), } } @@ -127,7 +133,6 @@ impl Into for TransactionRequest { } } - #[cfg(test)] mod tests { use std::str::FromStr; diff --git a/rpc/src/v1/types/uint.rs b/rpc/src/v1/types/uint.rs index 4e2a189a63f91a5e3153735bcc90ce5694238d9c..cb6dd5d3fdb1f61c893c0e5315b4b82842967e5d 100644 --- a/rpc/src/v1/types/uint.rs +++ b/rpc/src/v1/types/uint.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/work.rs b/rpc/src/v1/types/work.rs index 3664892df77200c7d8a0170c6c9d09e4d60c1ba8..5fdc117a202e0a6dfce317b25f24eda3edf20a55 100644 --- a/rpc/src/v1/types/work.rs +++ b/rpc/src/v1/types/work.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -40,4 +40,3 @@ impl Serialize for Work { } } } - diff --git a/rpc_cli/src/lib.rs b/rpc_cli/src/lib.rs index f322129d1c137eca1394e6f4fea41b2b4fa624a8..e4554d6ed5169ca8cba24c447e55f57d2af54d1c 100644 --- a/rpc_cli/src/lib.rs +++ b/rpc_cli/src/lib.rs @@ -1,3 +1,19 @@ +// 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 . + extern crate futures; extern crate rpassword; diff --git a/rpc_client/Cargo.toml b/rpc_client/Cargo.toml index 81776b3e15df18618c1b871f930d220f4f43a071..6b0f4c2cc5e8a37859d4f265c412b15656abea3b 100644 --- a/rpc_client/Cargo.toml +++ b/rpc_client/Cargo.toml @@ -13,8 +13,8 @@ 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" } -keccak-hash = { path = "../util/hash" } +keccak-hash = { git = "https://github.com/paritytech/parity-common" } diff --git a/rpc_client/src/client.rs b/rpc_client/src/client.rs index 17a8d9d7248a2f37a3b341d0bacff82512cb5d32..93abdac88ed842a1a256bedf597dbdeb414bb98c 100644 --- a/rpc_client/src/client.rs +++ b/rpc_client/src/client.rs @@ -1,3 +1,19 @@ +// 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 . + use std::fmt::{Debug, Formatter, Error as FmtError}; use std::io::{BufReader, BufRead}; use std::sync::Arc; diff --git a/rpc_client/src/lib.rs b/rpc_client/src/lib.rs index 49f537708ef7c11534ad2d5d416b5f88c292f2bb..98614bd7634c2198efa35ee63d4e020c2649e5ef 100644 --- a/rpc_client/src/lib.rs +++ b/rpc_client/src/lib.rs @@ -1,3 +1,19 @@ +// 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 . + pub mod client; pub mod signer_client; diff --git a/rpc_client/src/signer_client.rs b/rpc_client/src/signer_client.rs index cee063109bc26e8b683773360f5232f3e6f5a7a2..e7a241137f685d5e0aa901c74ec86417497d2451 100644 --- a/rpc_client/src/signer_client.rs +++ b/rpc_client/src/signer_client.rs @@ -1,3 +1,19 @@ +// 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 . + use client::{Rpc, RpcError}; use rpc::signer::{ConfirmationRequest, TransactionModification, U256, TransactionCondition}; use serde; diff --git a/scripts/add_license.sh b/scripts/add_license.sh index 1d916f42796b53d11e8c9b0575d39ac5915bd9e6..2b283590b0bb7a8413f4862bf63b0a155cc7342b 100755 --- a/scripts/add_license.sh +++ b/scripts/add_license.sh @@ -1,6 +1,20 @@ -#!/bin/sh +#!/usr/bin/env sh -for f in $(find . -name '*.rs'); do - cat license_header $f > $f.new - mv $f.new $f +PAT_GPL="^// Copyright.*If not, see \.$" +PAT_OTHER="^// Copyright" + +for f in $(find . -type f | egrep '\.(c|cpp|rs)$'); do + HEADER=$(head -16 $f) + if [[ $HEADER =~ $PAT_GPL ]]; then + BODY=$(tail -n +17 $f) + cat license_header > temp + echo "$BODY" >> temp + mv temp $f + elif [[ $HEADER =~ $PAT_OTHER ]]; then + echo "Other license was found do nothing" + else + echo "$f was missing header" + cat license_header $f > temp + mv temp $f + fi done diff --git a/scripts/aura-test.sh b/scripts/aura-test.sh index 1cd6bf53687a3bc32873d249ba1b25a707127d06..0c39e12f4d12c28e7bd4c86b1813cede1ee2d3fe 100755 --- a/scripts/aura-test.sh +++ b/scripts/aura-test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e # fail on any error set -u # treat unset variables as error diff --git a/scripts/cov.sh b/scripts/cov.sh index b199da31aa33c6247b425fab6d12e1b6068e2315..b6d25c6921cb5661caaaf58eaca4beb64df3fab0 100755 --- a/scripts/cov.sh +++ b/scripts/cov.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Installing KCOV under ubuntu # https://users.rust-lang.org/t/tutorial-how-to-collect-test-coverages-for-rust-project/650# ### Install deps @@ -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/scripts/doc.sh b/scripts/doc.sh index f0022610a54f78f8df3d02ae19c0d1c6f3b41ef4..44e544c993e4ea9918e0cd5cfa8dc089ef8691f8 100755 --- a/scripts/doc.sh +++ b/scripts/doc.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env sh # generate documentation only for partiy and ethcore libraries cargo doc --no-deps --verbose --all --exclude parity-ipfs-api && diff --git a/scripts/docker-build.sh b/scripts/docker-build.sh new file mode 100755 index 0000000000000000000000000000000000000000..b880d33b71a4e699937dae9140cf0c1eeb14647e --- /dev/null +++ b/scripts/docker-build.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +cd docker/hub +DOCKER_BUILD_TAG=$1 +echo "Docker build tag: " $DOCKER_BUILD_TAG +if [[ "$DOCKER_BUILD_TAG" = "latest" ]]; then + docker build --build-arg BUILD_TAG="master" --no-cache=true --tag parity/parity:$DOCKER_BUILD_TAG . +else + docker build --build-arg BUILD_TAG=$DOCKER_BUILD_TAG --no-cache=true --tag parity/parity:$DOCKER_BUILD_TAG . +fi +docker run -it parity/parity:$DOCKER_BUILD_TAG -v +docker push parity/parity:$DOCKER_BUILD_TAG diff --git a/scripts/evm_jsontests_bench.sh b/scripts/evm_jsontests_bench.sh new file mode 100755 index 0000000000000000000000000000000000000000..acec902196dbe42eb0e1a6bf8006660b47e14e29 --- /dev/null +++ b/scripts/evm_jsontests_bench.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +cargo build --release -p evmbin + +./target/release/parity-evm stats-jsontests-vm ./ethcore/res/ethereum/tests/VMTests/vmArithmeticTest +./target/release/parity-evm stats-jsontests-vm ./ethcore/res/ethereum/tests/VMTests/vmBitwiseLogicOperation +./target/release/parity-evm stats-jsontests-vm ./ethcore/res/ethereum/tests/VMTests/vmBlockInfoTest +./target/release/parity-evm stats-jsontests-vm ./ethcore/res/ethereum/tests/VMTests/vmEnvironmentalInfo +./target/release/parity-evm stats-jsontests-vm ./ethcore/res/ethereum/tests/VMTests/vmIOandFlowOperations +./target/release/parity-evm stats-jsontests-vm ./ethcore/res/ethereum/tests/VMTests/vmLogTest +./target/release/parity-evm stats-jsontests-vm ./ethcore/res/ethereum/tests/VMTests/vmPerformance +./target/release/parity-evm stats-jsontests-vm ./ethcore/res/ethereum/tests/VMTests/vmPushDupSwapTest +./target/release/parity-evm stats-jsontests-vm ./ethcore/res/ethereum/tests/VMTests/vmRandomTest +./target/release/parity-evm stats-jsontests-vm ./ethcore/res/ethereum/tests/VMTests/vmSha3Test +./target/release/parity-evm stats-jsontests-vm ./ethcore/res/ethereum/tests/VMTests/vmSystemOperations +./target/release/parity-evm stats-jsontests-vm ./ethcore/res/ethereum/tests/VMTests/vmTests diff --git a/evmbin/bench.sh b/scripts/evm_uint_bench.sh similarity index 54% rename from evmbin/bench.sh rename to scripts/evm_uint_bench.sh index 9d19729a6811cabd793f290b64dc6631d522001c..b0ca1c4f7bc39d7b9f12c7da93a04b2cc6daa10a 100755 --- a/evmbin/bench.sh +++ b/scripts/evm_uint_bench.sh @@ -1,23 +1,25 @@ -#!/bin/bash +#!/usr/bin/env bash -set -e - -cargo build --release +cargo build --release -p evmbin # LOOP TEST CODE1=606060405260005b620f42408112156019575b6001016007565b600081905550600680602b6000396000f3606060405200 -ethvm --code $CODE1 -echo "^^^^ ethvm" -./target/release/evm stats --code $CODE1 --gas 4402000 +if [ -x "$(command -v ethvm)" ]; then + ethvm --code $CODE1 + echo "^^^^ ethvm" +fi +./target/release/parity-evm stats --code $CODE1 --gas 4402000 echo "^^^^ usize" -./target/release/evm stats --code $CODE1 +./target/release/parity-evm stats --code $CODE1 echo "^^^^ U256" # RNG TEST CODE2=6060604052600360056007600b60005b620f4240811215607f5767ffe7649d5eca84179490940267f47ed85c4b9a6379019367f8e5dd9a5c994bba9390930267f91d87e4b8b74e55019267ff97f6f3b29cda529290920267f393ada8dd75c938019167fe8d437c45bb3735830267f47d9a7b5428ffec019150600101600f565b838518831882186000555050505050600680609a6000396000f3606060405200 -ethvm --code $CODE2 -echo "^^^^ ethvm" -./target/release/evm stats --code $CODE2 --gas 143020115 +if [ -x "$(command -v ethvm)" ]; then + ethvm --code $CODE2 + echo "^^^^ ethvm" +fi +./target/release/parity-evm stats --code $CODE2 --gas 143020115 echo "^^^^ usize" -./target/release/evm stats --code $CODE2 +./target/release/parity-evm stats --code $CODE2 echo "^^^^ U256" diff --git a/scripts/gitlab-test.sh b/scripts/gitlab-test.sh new file mode 100755 index 0000000000000000000000000000000000000000..fbd93167a338297eb687edab81efc16f4f9b9002 --- /dev/null +++ b/scripts/gitlab-test.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +#ARGUMENT test for RUST and COVERAGE +set -e # fail on any error +set -u # treat unset variables as error +if [[ "$CI_COMMIT_REF_NAME" = "master" || "$CI_COMMIT_REF_NAME" = "beta" || "$CI_COMMIT_REF_NAME" = "stable" ]]; then + export GIT_COMPARE=$CI_COMMIT_REF_NAME~; +else + export GIT_COMPARE=master; +fi +git fetch -a +export RUST_FILES_MODIFIED="$(git --no-pager diff --name-only $GIT_COMPARE...$CI_COMMIT_SHA | grep -v -e ^\\. -e ^LICENSE -e ^README.md -e ^test.sh -e ^windows/ -e ^scripts/ -e ^mac/ -e ^nsis/ -e ^docs/ | wc -l)" +echo "RUST_FILES_MODIFIED: $RUST_FILES_MODIFIED" +TEST_SWITCH=$1 +rust_test () { + git submodule update --init --recursive + rustup show + if [[ "${RUST_FILES_MODIFIED}" == "0" ]]; + then echo "Skipping Rust tests since no Rust files modified."; + else ./test.sh || exit $?; + fi + # if [[ "$CI_COMMIT_REF_NAME" == "nightly" ]]; + # ### @TODO re-enable fail after https://github.com/paritytech/parity-import-tests/issues/3 + # then sh scripts/aura-test.sh; # || exit $?; + # fi +} +coverage_test () { + git submodule update --init --recursive + rm -rf target/* + scripts/cov.sh +} +case $TEST_SWITCH in + stable ) + rustup default stable + rust_test + ;; + beta) + rustup default beta + rust_test + ;; + nightly) + rustup default nightly + rust_test + ;; + test-coverage) + coverage_test + ;; +esac diff --git a/scripts/gitlab/build.sh b/scripts/gitlab/build.sh index 5721a8d164d8a0648767ace4d2a49695332c6570..bd2000576dc1c94f9440aeea96dd17c9df6597b4 100755 --- a/scripts/gitlab/build.sh +++ b/scripts/gitlab/build.sh @@ -1,4 +1,5 @@ -#!/bin/bash +#!/usr/bin/env bash + set -e # fail on any error #ARGUMENTS: 1. BUILD_PLATFORM (target for binaries) 2. PLATFORM (target for cargo) 3. ARC (architecture) 4. & 5. CC & CXX flags 6. binary identifier BUILD_PLATFORM=$1 @@ -15,15 +16,13 @@ echo "Build identifier: " $IDENT echo "Cargo target: " $PLATFORM echo "CC&CXX flags: " $CC ", " $CXX echo "Architecture: " $ARC -echo "Libssl version: " $LIBSSL echo "Parity version: " $VER echo "Branch: " $CI_BUILD_REF_NAME echo "Protect? " $protect echo "--------------------" -# NOTE for md5 and sha256 we want to display filename as well +# NOTE for sha256 we want to display filename as well # hence we use --* instead of -p * -MD5_BIN="rhash --md5" SHA256_BIN="rhash --sha256" set_env () { @@ -43,7 +42,6 @@ set_env_win () { set RUST_BACKTRACE=1 #export RUSTFLAGS=$RUSTFLAGS rustup default stable-x86_64-pc-windows-msvc - echo "MsBuild.exe windows\ptray\ptray.vcxproj /p:Platform=x64 /p:Configuration=Release" > msbuild.cmd echo "@ signtool sign /f "\%"1 /p "\%"2 /tr http://timestamp.comodoca.com /du https://parity.io "\%"3" > sign.cmd } build () { @@ -66,90 +64,22 @@ strip_binaries () { calculate_checksums () { echo "__________Checksum calculation__________" rhash --version - rm -rf *.md5 + rm -rf *.sha256 BIN="target/$PLATFORM/release/parity$S3WIN" export SHA3="$($BIN tools hash $BIN)" - echo "__________Parity file SHA3__________" - echo $SHA3 - $MD5_BIN target/$PLATFORM/release/parity$S3WIN > parity$S3WIN.md5 + + echo "Parity file SHA3: $SHA3" $SHA256_BIN target/$PLATFORM/release/parity$S3WIN > parity$S3WIN.sha256 - $MD5_BIN target/$PLATFORM/release/parity-evm$S3WIN > parity-evm$S3WIN.md5 $SHA256_BIN target/$PLATFORM/release/parity-evm$S3WIN > parity-evm$S3WIN.sha256 - $MD5_BIN target/$PLATFORM/release/ethstore$S3WIN > ethstore$S3WIN.md5 $SHA256_BIN target/$PLATFORM/release/ethstore$S3WIN > ethstore$S3WIN.sha256 - $MD5_BIN target/$PLATFORM/release/ethkey$S3WIN > ethkey$S3WIN.md5 $SHA256_BIN target/$PLATFORM/release/ethkey$S3WIN > ethkey$S3WIN.sha256 -} -make_deb () { - rm -rf deb - echo "__________Create DEBIAN files__________" - mkdir -p deb/usr/bin/ - mkdir -p deb/DEBIAN - echo "create copyright, docs, compat" - cp LICENSE deb/DEBIAN/copyright - echo "https://github.com/paritytech/parity/wiki" >> deb/DEBIAN/docs - echo "8" >> deb/DEBIAN/compat - echo "create control file" - control=deb/DEBIAN/control - echo "Package: parity" >> $control - echo "Version: $VER" >> $control - echo "Source: parity" >> $control - echo "Section: science" >> $control - echo "Priority: extra" >> $control - echo "Maintainer: Parity Technologies " >> $control - echo "Build-Depends: debhelper (>=9)" >> $control - echo "Standards-Version: 3.9.5" >> $control - echo "Homepage: https://parity.io" >> $control - echo "Vcs-Git: git://github.com/paritytech/parity.git" >> $control - echo "Vcs-Browser: https://github.com/paritytech/parity" >> $control - echo "Architecture: $ARC" >> $control - echo "Depends: $LIBSSL" >> $control - echo "Description: Ethereum network client by Parity Technologies" >> $control - size=`du deb/|awk 'END {print $1}'` - echo "Installed-Size: $size" >> $control - echo "__________Build .deb package__________" - cp target/$PLATFORM/release/parity deb/usr/bin/parity - cp target/$PLATFORM/release/parity-evm deb/usr/bin/parity-evm - cp target/$PLATFORM/release/ethstore deb/usr/bin/ethstore - cp target/$PLATFORM/release/ethkey deb/usr/bin/ethkey - dpkg-deb -b deb "parity_"$VER"_"$IDENT"_"$ARC".deb" - $MD5_BIN "parity_"$VER"_"$IDENT"_"$ARC".deb" > "parity_"$VER"_"$IDENT"_"$ARC".deb.md5" - $SHA256_BIN "parity_"$VER"_"$IDENT"_"$ARC".deb" > "parity_"$VER"_"$IDENT"_"$ARC".deb.sha256" -} -make_rpm () { - rm -rf /install - echo "__________Create RPM package__________" - mkdir -p /install/usr/bin - cp target/$PLATFORM/release/parity /install/usr/bin - cp target/$PLATFORM/release/parity-evm /install/usr/bin/parity-evm - cp target/$PLATFORM/release/ethstore /install/usr/bin/ethstore - cp target/$PLATFORM/release/ethkey /install/usr/bin/ethkey - - rm -rf "parity-"$VER"-1."$ARC".rpm" || true - fpm -s dir -t rpm -n parity -v $VER --epoch 1 --license GPLv3 -d openssl --provides parity --url https://parity.io --vendor "Parity Technologies" -a x86_64 -m "" --description "Ethereum network client by Parity Technologies" -C /install/ - cp "parity-"$VER"-1."$ARC".rpm" "parity_"$VER"_"$IDENT"_"$ARC".rpm" - $MD5_BIN "parity_"$VER"_"$IDENT"_"$ARC".rpm" > "parity_"$VER"_"$IDENT"_"$ARC".rpm.md5" - $SHA256_BIN "parity_"$VER"_"$IDENT"_"$ARC".rpm" > "parity_"$VER"_"$IDENT"_"$ARC".rpm.sha256" -} -make_pkg () { - echo "__________Make OSX PKG__________" - cp target/$PLATFORM/release/parity target/release/parity - cp target/$PLATFORM/release/parity-evm target/release/parity-evm - cp target/$PLATFORM/release/ethstore target/release/ethstore - cp target/$PLATFORM/release/ethkey target/release/ethkey - cd mac - xcodebuild -configuration Release - cd .. - packagesbuild -v mac/Parity.pkgproj - productsign --sign 'Developer ID Installer: PARITY TECHNOLOGIES LIMITED (P2PX3JU8FT)' target/release/Parity\ Ethereum.pkg target/release/Parity\ Ethereum-signed.pkg - mv target/release/Parity\ Ethereum-signed.pkg "parity_"$VER"_"$IDENT"_"$ARC".pkg" - $MD5_BIN "parity_"$VER"_"$IDENT"_"$ARC"."$EXT >> "parity_"$VER"_"$IDENT"_"$ARC".pkg.md5" - $SHA256_BIN "parity_"$VER"_"$IDENT"_"$ARC"."$EXT >> "parity_"$VER"_"$IDENT"_"$ARC".pkg.sha256" + $SHA256_BIN target/$PLATFORM/release/whisper$S3WIN > whisper$S3WIN.sha256 } sign_exe () { if [[ -z "$protect" ]]; then echo "__________Skipping sign binaries__________"&&return; fi ./sign.cmd $keyfile $certpass "target/$PLATFORM/release/parity.exe" +<<<<<<< HEAD:scripts/gitlab/build.sh ./sign.cmd $keyfile $certpass windows/ptray/x64/release/ptray.exe } make_exe () { @@ -164,6 +94,12 @@ make_exe () { ./sign.cmd $keyfile $certpass "parity_"$VER"_"$IDENT"_"$ARC"."$EXT $MD5_BIN "parity_"$VER"_"$IDENT"_"$ARC"."$EXT -p %h > "parity_"$VER"_"$IDENT"_"$ARC"."$EXT".md5" $SHA256_BIN "parity_"$VER"_"$IDENT"_"$ARC"."$EXT -p %h > "parity_"$VER"_"$IDENT"_"$ARC"."$EXT".sha256" +======= + ./sign.cmd $keyfile $certpass "target/$PLATFORM/release/parity-evm.exe" + ./sign.cmd $keyfile $certpass "target/$PLATFORM/release/ethstore.exe" + ./sign.cmd $keyfile $certpass "target/$PLATFORM/release/ethkey.exe" + ./sign.cmd $keyfile $certpass "target/$PLATFORM/release/whisper.exe" +>>>>>>> master:scripts/gitlab-build.sh } push_snap () { if [[ -z "$protect" ]]; then echo "__________Skipping push and release snap__________"&&return; fi @@ -232,7 +168,7 @@ push_binaries () { echo "__________Push binaries to AWS S3__________" aws configure set aws_access_key_id $s3_key aws configure set aws_secret_access_key $s3_secret - if [[ "$CI_BUILD_REF_NAME" = "master" || "$CI_BUILD_REF_NAME" = "beta" || "$CI_BUILD_REF_NAME" = "stable" || "$CI_BUILD_REF_NAME" = "nightly" ]]; + if [[ "$CI_BUILD_REF_NAME" = "beta" || "$CI_BUILD_REF_NAME" = "stable" || "$CI_BUILD_REF_NAME" = "nightly" ]]; then export S3_BUCKET=builds-parity-published; else @@ -240,35 +176,21 @@ push_binaries () { fi aws s3 rm --recursive s3://$S3_BUCKET/$CI_BUILD_REF_NAME/$BUILD_PLATFORM aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/parity$S3WIN --body target/$PLATFORM/release/parity$S3WIN - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/parity$S3WIN.md5 --body parity$S3WIN.md5 aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/parity$S3WIN.sha256 --body parity$S3WIN.sha256 aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/parity-evm$S3WIN --body target/$PLATFORM/release/parity-evm$S3WIN - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/parity-evm$S3WIN.md5 --body parity-evm$S3WIN.md5 aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/parity-evm$S3WIN.sha256 --body parity-evm$S3WIN.sha256 aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/ethstore$S3WIN --body target/$PLATFORM/release/ethstore$S3WIN - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/ethstore$S3WIN.md5 --body ethstore$S3WIN.md5 aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/ethstore$S3WIN.sha256 --body ethstore$S3WIN.sha256 aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/ethkey$S3WIN --body target/$PLATFORM/release/ethkey$S3WIN - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/ethkey$S3WIN.md5 --body ethkey$S3WIN.md5 aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/ethkey$S3WIN.sha256 --body ethkey$S3WIN.sha256 - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/"parity_"$VER"_"$IDENT"_"$ARC"."$EXT --body "parity_"$VER"_"$IDENT"_"$ARC"."$EXT - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/"parity_"$VER"_"$IDENT"_"$ARC"."$EXT".md5" --body "parity_"$VER"_"$IDENT"_"$ARC"."$EXT".md5" - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/"parity_"$VER"_"$IDENT"_"$ARC"."$EXT".sha256" --body "parity_"$VER"_"$IDENT"_"$ARC"."$EXT".sha256" + aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/whisper$S3WIN --body target/$PLATFORM/release/whisper$S3WIN + aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/whisper$S3WIN.sha256 --body whisper$S3WIN.sha256 } -prepare_artifacts () { - echo "__________Copy all artifacts to one place__________" - rm -rf artifacts - mkdir -p artifacts - cp target/$PLATFORM/release/parity$S3WIN artifacts - cp target/$PLATFORM/release/parity-evm$S3WIN artifacts - cp target/$PLATFORM/release/ethstore$S3WIN artifacts - cp target/$PLATFORM/release/ethkey$S3WIN parity$S3WIN.md5 artifacts - cp parity-evm$S3WIN.md5 ethstore$S3WIN.md5 artifacts - cp ethkey$S3WIN.md5 artifacts - cp parity$S3WIN.sha256 artifacts - cp parity-evm$S3WIN.sha256 artifacts - cp ethstore$S3WIN.sha256 artifacts - cp ethkey$S3WIN.sha256 artifacts + +make_archive () { + echo "add artifacts to archive" + rm -rf parity.zip + zip -r parity.zip target/$PLATFORM/release/parity$S3WIN target/$PLATFORM/release/parity-evm$S3WIN target/$PLATFORM/release/ethstore$S3WIN target/$PLATFORM/release/ethkey$S3WIN target/$PLATFORM/release/whisper$S3WIN parity$S3WIN.sha256 parity-evm$S3WIN.sha256 ethstore$S3WIN.sha256 ethkey$S3WIN.sha256 whisper$S3WIN.sha256 } updater_push_release () { echo "__________Build comlete__________" @@ -294,75 +216,93 @@ case $BUILD_PLATFORM in #set strip bin STRIP_BIN="strip" #package extention - EXT="deb" - build_and_push - ;; - x86_64-unknown-debian-gnu) - STRIP_BIN="strip" - EXT="deb" - LIBSSL="libssl1.1 (>=1.1.0)" - echo "__________Use libssl1.1 (>=1.1.0) for Debian builds__________" - build_and_push - ;; - x86_64-unknown-centos-gnu) - STRIP_BIN="strip" - EXT="rpm" build strip_binaries calculate_checksums - make_rpm - prepare_artifacts + make_archive push_binaries updater_push_release ;; i686-unknown-linux-gnu) STRIP_BIN="strip" - EXT="deb" set_env +<<<<<<< HEAD:scripts/gitlab/build.sh build_and_push +======= + build + strip_binaries + calculate_checksums + make_archive + push_binaries +>>>>>>> master:scripts/gitlab-build.sh ;; armv7-unknown-linux-gnueabihf) STRIP_BIN="arm-linux-gnueabihf-strip" - EXT="deb" set_env - build_and_push + build + strip_binaries + calculate_checksums + make_archive + push_binaries ;; arm-unknown-linux-gnueabihf) STRIP_BIN="arm-linux-gnueabihf-strip" - EXT="deb" set_env - build_and_push + build + strip_binaries + calculate_checksums + make_archive + push_binaries ;; aarch64-unknown-linux-gnu) STRIP_BIN="aarch64-linux-gnu-strip" - EXT="deb" set_env - build_and_push + build + strip_binaries + calculate_checksums + make_archive + push_binaries ;; x86_64-apple-darwin) STRIP_BIN="strip" PLATFORM="x86_64-apple-darwin" - EXT="pkg" build strip_binaries calculate_checksums - make_pkg - prepare_artifacts + make_archive push_binaries updater_push_release ;; x86_64-unknown-snap-gnu) - make_snap - ;; - i686-unknown-snap-gnu) - set_env - make_snap - ;; - arm64-unknown-snap-gnu) - make_snap - ;; - armhf-unknown-snap-gnu) - make_snap + ARC="amd64" + EXT="snap" + apt update + apt install -y expect zip rhash + snapcraft clean + echo "Prepare snapcraft.yaml for build on Gitlab CI in Docker image" + sed -i 's/git/'"$VER"'/g' snap/snapcraft.yaml + if [[ "$CI_BUILD_REF_NAME" = "stable" || "$CI_BUILD_REF_NAME" = "beta" || "$VER" == *1.11* || "$VER" == *2.0* ]]; + then + sed -i -e 's/grade: devel/grade: stable/' snap/snapcraft.yaml; + fi + mv -f snap/snapcraft.yaml snapcraft.yaml + snapcraft -d + snapcraft_login=$(expect -c " + spawn snapcraft login + expect \"Email:\" + send \"$SNAP_EMAIL\n\" + expect \"Password:\" + send \"$SNAP_PASS\n\" + expect \"\$\" + ") + echo "$snapcraft_login" + snapcraft push "parity_"$VER"_amd64.snap" + snapcraft status parity + snapcraft logout + $SHA256_BIN "parity_"$VER"_amd64.snap" > "parity_"$VER"_amd64.snap.sha256" + echo "add artifacts to archive" + rm -rf parity.zip + zip -r parity.zip "parity_"$VER"_amd64.snap" "parity_"$VER"_amd64.snap.sha256" ;; x86_64-pc-windows-msvc) set_env_win @@ -371,8 +311,7 @@ case $BUILD_PLATFORM in build sign_exe calculate_checksums - make_exe - prepare_artifacts + make_archive push_binaries updater_push_release esac diff --git a/scripts/gitlab/push-release.sh b/scripts/gitlab/push-release.sh index 275576b91ecd1c0a8eaeb253b34f412ca535a564..207d66c11cb409346b2740c56db0ab475a31ab02 100755 --- a/scripts/gitlab/push-release.sh +++ b/scripts/gitlab/push-release.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e # fail on any error set -u # treat unset variables as error diff --git a/scripts/hook.sh b/scripts/hook.sh index 2d64d5782f215cf9289390eb4ac4b653e438d7ac..ed7e173c5056944c6de1168eef224ed5794a27f8 100755 --- a/scripts/hook.sh +++ b/scripts/hook.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env sh FILE=./.git/hooks/pre-push echo "#!/bin/sh\n" > $FILE diff --git a/scripts/remove_duplicate_empty_lines.sh b/scripts/remove_duplicate_empty_lines.sh new file mode 100755 index 0000000000000000000000000000000000000000..0df265ab9f601064dcd15ec7cc6e25c602080e54 --- /dev/null +++ b/scripts/remove_duplicate_empty_lines.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env sh + +for f in $(find . -name '*.rs'); do + cat -s $f > $f.temp + mv $f.temp $f +done diff --git a/scripts/safe_curl.sh b/scripts/safe_curl.sh index 5990d1e24b358577b29908669b5d5b8aafe815be..f5bb2ee4ef57bc6f8607c3916a369b21ce87dec6 100755 --- a/scripts/safe_curl.sh +++ b/scripts/safe_curl.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -eu @@ -17,4 +17,3 @@ else echo 'Unable to push info to updater service.'; exit 2 fi - diff --git a/scripts/validate_chainspecs.sh b/scripts/validate_chainspecs.sh index a0e2d9b173986b9646e8db853c1dabf33444c568..c350445dd9b713b13fd11e611ff58883f0ac29e9 100755 --- a/scripts/validate_chainspecs.sh +++ b/scripts/validate_chainspecs.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env sh ERR=0 cargo build --release -p chainspec @@ -12,4 +12,3 @@ for spec in ethcore/res/ethereum/*.json; do done exit $ERR - diff --git a/secret_store/Cargo.toml b/secret_store/Cargo.toml index 261658903cc8f39c8ad2e3d284490b170809cef4..85eda93e3ce32c9c99cf075e6b540e23abfa0649 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" @@ -24,14 +24,14 @@ tokio-service = "0.1" tokio-proto = "0.1" url = "1.0" ethcore = { path = "../ethcore" } -ethcore-bytes = { path = "../util/bytes" } -ethcore-crypto = { path = "../ethcore/crypto" } +parity-bytes = { git = "https://github.com/paritytech/parity-common" } +parity-crypto = { git = "https://github.com/paritytech/parity-common" } ethcore-logger = { path = "../logger" } ethcore-sync = { path = "../ethcore/sync" } ethcore-transaction = { path = "../ethcore/transaction" } ethereum-types = "0.3" -kvdb = { path = "../util/kvdb" } -keccak-hash = { path = "../util/hash" } +kvdb = { git = "https://github.com/paritytech/parity-common" } +keccak-hash = { git = "https://github.com/paritytech/parity-common" } ethkey = { path = "../ethkey" } lazy_static = "1.0" ethabi = "5.1" @@ -39,5 +39,6 @@ ethabi-derive = "5.0" ethabi-contract = "5.0" [dev-dependencies] +ethcore = { path = "../ethcore", features = ["test-helpers"] } tempdir = "0.3" -kvdb-rocksdb = { path = "../util/kvdb-rocksdb" } +kvdb-rocksdb = { git = "https://github.com/paritytech/parity-common" } diff --git a/secret_store/src/acl_storage.rs b/secret_store/src/acl_storage.rs index bc75cfec44c47abbf91e788dfa3167fac064aad5..efc01f0307166fdc44caa6fe75b06d83cadf4935 100644 --- a/secret_store/src/acl_storage.rs +++ b/secret_store/src/acl_storage.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -18,11 +18,11 @@ use std::sync::Arc; use std::collections::{HashMap, HashSet}; use std::time::Duration; use parking_lot::{Mutex, RwLock}; -use ethcore::client::{BlockId, ChainNotify, ChainRoute, CallContract, RegistryInfo}; +use ethcore::client::{BlockId, ChainNotify, ChainRoute, CallContract}; use ethereum_types::{H256, Address}; use bytes::Bytes; use trusted_client::TrustedClient; -use types::{Error, ServerKeyId}; +use types::{Error, ServerKeyId, ContractAddress}; use_contract!(acl_storage, "AclStorage", "res/acl_storage.json"); @@ -44,8 +44,10 @@ pub struct OnChainAclStorage { struct CachedContract { /// Blockchain client. client: TrustedClient, - /// Contract address. - contract_addr: Option
, + /// Contract address source. + address_source: ContractAddress, + /// Current contract address. + contract_address: Option
, /// Contract at given address. contract: acl_storage::AclStorage, } @@ -57,10 +59,10 @@ pub struct DummyAclStorage { } impl OnChainAclStorage { - pub fn new(trusted_client: TrustedClient) -> Result, Error> { + pub fn new(trusted_client: TrustedClient, address_source: ContractAddress) -> Result, Error> { let client = trusted_client.get_untrusted(); let acl_storage = Arc::new(OnChainAclStorage { - contract: Mutex::new(CachedContract::new(trusted_client)), + contract: Mutex::new(CachedContract::new(trusted_client, address_source)), }); client .ok_or_else(|| Error::Internal("Constructing OnChainAclStorage without active Client".into()))? @@ -78,36 +80,37 @@ impl AclStorage for OnChainAclStorage { impl ChainNotify for OnChainAclStorage { fn new_blocks(&self, _imported: Vec, _invalid: Vec, route: ChainRoute, _sealed: Vec, _proposed: Vec, _duration: Duration) { if !route.enacted().is_empty() || !route.retracted().is_empty() { - self.contract.lock().update() + self.contract.lock().update_contract_address() } } } impl CachedContract { - pub fn new(client: TrustedClient) -> Self { - CachedContract { + pub fn new(client: TrustedClient, address_source: ContractAddress) -> Self { + let mut contract = CachedContract { client, - contract_addr: None, + address_source, + contract_address: None, contract: acl_storage::AclStorage::default(), - } + }; + contract.update_contract_address(); + contract } - pub fn update(&mut self) { - if let Some(client) = self.client.get() { - match client.registry_address(ACL_CHECKER_CONTRACT_REGISTRY_NAME.to_owned(), BlockId::Latest) { - Some(new_contract_addr) if Some(new_contract_addr).as_ref() != self.contract_addr.as_ref() => { - trace!(target: "secretstore", "Configuring for ACL checker contract from {}", new_contract_addr); - self.contract_addr = Some(new_contract_addr); - }, - Some(_) | None => () - } + pub fn update_contract_address(&mut self) { + let contract_address = self.client.read_contract_address(ACL_CHECKER_CONTRACT_REGISTRY_NAME.into(), &self.address_source); + if contract_address != self.contract_address { + trace!(target: "secretstore", "Configuring for ACL checker contract from address {:?}", + contract_address); + + self.contract_address = contract_address; } } pub fn check(&mut self, requester: Address, document: &ServerKeyId) -> Result { if let Some(client) = self.client.get() { - // call contract to check access - match self.contract_addr { + // call contract to check accesss + match self.contract_address { Some(contract_address) => { let do_call = |data| client.call_contract(BlockId::Latest, contract_address, data); self.contract.functions() diff --git a/secret_store/src/key_server.rs b/secret_store/src/key_server.rs index b06be2422e214381ef3c8adddf46d8c83800d813..3b24199776323649974afe5e56fc4312478f56c5 100644 --- a/secret_store/src/key_server.rs +++ b/secret_store/src/key_server.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -303,6 +303,7 @@ pub mod tests { address: "127.0.0.1".into(), port: start_port + (j as u16), })).collect(), + key_server_set_contract_address: None, allow_connecting_to_higher_nodes: false, admin_public: None, auto_migrate_enabled: false, @@ -312,7 +313,7 @@ pub mod tests { .collect(); let key_storages = (0..num_nodes).map(|_| Arc::new(DummyKeyStorage::default())).collect::>(); let key_servers: Vec<_> = configs.into_iter().enumerate().map(|(i, cfg)| - KeyServerImpl::new(&cfg, Arc::new(MapKeyServerSet::new(key_servers_set.clone())), + KeyServerImpl::new(&cfg, Arc::new(MapKeyServerSet::new(false, key_servers_set.clone())), Arc::new(PlainNodeKeyPair::new(key_pairs[i].clone())), Arc::new(DummyAclStorage::default()), key_storages[i].clone()).unwrap() diff --git a/secret_store/src/key_server_cluster/admin_sessions/key_version_negotiation_session.rs b/secret_store/src/key_server_cluster/admin_sessions/key_version_negotiation_session.rs index 6c39fd8e7ed6c97e6d409c1a64070591a6397a26..4839ac41e8081b3de386058fefab0c92d4235c8b 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/key_version_negotiation_session.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/key_version_negotiation_session.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -25,7 +25,8 @@ use key_server_cluster::cluster_sessions::{SessionIdWithSubSession, ClusterSessi use key_server_cluster::decryption_session::SessionImpl as DecryptionSession; use key_server_cluster::signing_session_ecdsa::SessionImpl as EcdsaSigningSession; use key_server_cluster::signing_session_schnorr::SessionImpl as SchnorrSigningSession; -use key_server_cluster::message::{Message, KeyVersionNegotiationMessage, RequestKeyVersions, KeyVersions}; +use key_server_cluster::message::{Message, KeyVersionNegotiationMessage, RequestKeyVersions, + KeyVersions, KeyVersionsError, FailedKeyVersionContinueAction}; use key_server_cluster::admin_sessions::ShareChangeSessionMeta; // TODO [Opt]: change sessions so that versions are sent by chunks. @@ -34,6 +35,8 @@ const VERSIONS_PER_MESSAGE: usize = 32; /// Key version negotiation transport. pub trait SessionTransport { + /// Broadcast message to all nodes. + fn broadcast(&self, message: KeyVersionNegotiationMessage) -> Result<(), Error>; /// Send message to given node. fn send(&self, node: &NodeId, message: KeyVersionNegotiationMessage) -> Result<(), Error>; } @@ -63,6 +66,13 @@ pub enum ContinueAction { EcdsaSign(Arc, H256), } +/// Failed action after key version is negotiated. +#[derive(Clone, Debug, PartialEq)] +pub enum FailedContinueAction { + /// Decryption origin + requester. + Decrypt(Option
, Address), +} + /// Immutable session data. struct SessionCore { /// Session meta. @@ -92,9 +102,11 @@ struct SessionData { /// { Version => Nodes } pub versions: Option>>, /// Session result. - pub result: Option>, + pub result: Option, Error>>, /// Continue action. pub continue_with: Option, + /// Failed continue action (reported in error message by master node). + pub failed_continue_with: Option, } /// SessionImpl creation parameters @@ -155,6 +167,7 @@ pub struct LargestSupportResultComputer; impl SessionImpl where T: SessionTransport { /// Create new session. pub fn new(params: SessionParams) -> Self { + let threshold = params.key_share.as_ref().map(|key_share| key_share.threshold); SessionImpl { core: SessionCore { meta: params.meta, @@ -168,10 +181,11 @@ impl SessionImpl where T: SessionTransport { data: Mutex::new(SessionData { state: SessionState::WaitingForInitialization, confirmations: None, - threshold: None, + threshold: threshold, versions: None, result: None, continue_with: None, + failed_continue_with: None, }) } } @@ -183,7 +197,8 @@ impl SessionImpl where T: SessionTransport { /// Return key threshold. pub fn key_threshold(&self) -> Result { - Ok(self.data.lock().threshold.clone().ok_or(Error::InvalidStateForRequest)?) + self.data.lock().threshold.clone() + .ok_or(Error::InvalidStateForRequest) } /// Return result computer reference. @@ -203,8 +218,13 @@ impl SessionImpl where T: SessionTransport { self.data.lock().continue_with.take() } + /// Take failed continue action. + pub fn take_failed_continue_action(&self) -> Option { + self.data.lock().failed_continue_with.take() + } + /// Wait for session completion. - pub fn wait(&self) -> Result<(H256, NodeId), Error> { + pub fn wait(&self) -> Result, Error> { Self::wait_session(&self.core.completed, &self.data, None, |data| data.result.clone()) .expect("wait_session returns Some if called without timeout; qed") } @@ -270,6 +290,12 @@ impl SessionImpl where T: SessionTransport { &KeyVersionNegotiationMessage::KeyVersions(ref message) => self.on_key_versions(sender, message), &KeyVersionNegotiationMessage::KeyVersionsError(ref message) => { + // remember failed continue action + if let Some(FailedKeyVersionContinueAction::Decrypt(Some(ref origin), ref requester)) = message.continue_with { + self.data.lock().failed_continue_with = + Some(FailedContinueAction::Decrypt(Some(origin.clone().into()), requester.clone().into())); + } + self.on_session_error(sender, message.error.clone()); Ok(()) }, @@ -309,6 +335,8 @@ impl SessionImpl where T: SessionTransport { // update state data.state = SessionState::Finished; + data.result = Some(Ok(None)); + self.core.completed.notify_all(); Ok(()) } @@ -361,8 +389,47 @@ impl SessionImpl where T: SessionTransport { let confirmations = data.confirmations.as_ref().expect(reason); let versions = data.versions.as_ref().expect(reason); if let Some(result) = core.result_computer.compute_result(data.threshold.clone(), confirmations, versions) { + // when the master node processing decryption service request, it starts with a key version negotiation session + // if the negotiation fails, only master node knows about it + // => if the error is fatal, only the master will know about it and report it to the contract && the request will never be rejected + // => let's broadcast fatal error so that every other node know about it, and, if it trusts to master node + // will report error to the contract + if let (Some(continue_with), Err(error)) = (data.continue_with.as_ref(), result.as_ref()) { + let origin = match *continue_with { + ContinueAction::Decrypt(_, origin, _, _) => origin.clone(), + _ => None, + }; + + let requester = match *continue_with { + ContinueAction::Decrypt(ref session, _, _, _) => session.requester().and_then(|r| r.address(&core.meta.id).ok()), + _ => None, + }; + + if origin.is_some() && requester.is_some() && !error.is_non_fatal() { + let requester = requester.expect("checked in above condition; qed"); + data.failed_continue_with = + Some(FailedContinueAction::Decrypt(origin.clone(), requester.clone())); + + let send_result = core.transport.broadcast(KeyVersionNegotiationMessage::KeyVersionsError(KeyVersionsError { + session: core.meta.id.clone().into(), + sub_session: core.sub_session.clone().into(), + session_nonce: core.nonce, + error: error.clone(), + continue_with: Some(FailedKeyVersionContinueAction::Decrypt( + origin.map(Into::into), + requester.into(), + )), + })); + + if let Err(send_error) = send_result { + warn!(target: "secretstore_net", "{}: failed to broadcast key version negotiation error {}: {}", + core.meta.self_node_id, error, send_error); + } + } + } + data.state = SessionState::Finished; - data.result = Some(result); + data.result = Some(result.map(Some)); core.completed.notify_all(); } } @@ -390,7 +457,7 @@ impl ClusterSession for SessionImpl where T: SessionTransport { data.confirmations.as_mut().expect("checked a line above; qed").clear(); Self::try_complete(&self.core, &mut *data); if data.state != SessionState::Finished { - warn!("{}: key version negotiation session failed with timeout", self.core.meta.self_node_id); + warn!(target: "secretstore_net", "{}: key version negotiation session failed with timeout", self.core.meta.self_node_id); data.result = Some(Err(Error::ConsensusTemporaryUnreachable)); self.core.completed.notify_all(); @@ -407,17 +474,22 @@ impl ClusterSession for SessionImpl where T: SessionTransport { if data.confirmations.is_some() { let is_waiting_for_confirmation = data.confirmations.as_mut().expect("checked a line above; qed").remove(node); - if is_waiting_for_confirmation { - Self::try_complete(&self.core, &mut *data); - if data.state != SessionState::Finished { - warn!("{}: key version negotiation session failed because {} connection has timeouted", self.core.meta.self_node_id, node); - - data.state = SessionState::Finished; - data.result = Some(Err(error)); - self.core.completed.notify_all(); - } + if !is_waiting_for_confirmation { + return; + } + + Self::try_complete(&self.core, &mut *data); + if data.state == SessionState::Finished { + return; } } + + warn!(target: "secretstore_net", "{}: key version negotiation session failed because of {} from {}", + self.core.meta.self_node_id, error, node); + + data.state = SessionState::Finished; + data.result = Some(Err(error)); + self.core.completed.notify_all(); } fn on_message(&self, sender: &NodeId, message: &Message) -> Result<(), Error> { @@ -429,6 +501,10 @@ impl ClusterSession for SessionImpl where T: SessionTransport { } impl SessionTransport for IsolatedSessionTransport { + fn broadcast(&self, message: KeyVersionNegotiationMessage) -> Result<(), Error> { + self.cluster.broadcast(Message::KeyVersionNegotiation(message)) + } + fn send(&self, node: &NodeId, message: KeyVersionNegotiationMessage) -> Result<(), Error> { self.cluster.send(node, Message::KeyVersionNegotiation(message)) } @@ -514,20 +590,28 @@ impl SessionResultComputer for LargestSupportResultComputer { mod tests { use std::sync::Arc; use std::collections::{VecDeque, BTreeMap, BTreeSet}; - use key_server_cluster::{NodeId, SessionId, Error, KeyStorage, DummyKeyStorage, DocumentKeyShare, DocumentKeyShareVersion}; + use ethkey::public_to_address; + use key_server_cluster::{NodeId, SessionId, Error, KeyStorage, DummyKeyStorage, + DocumentKeyShare, DocumentKeyShareVersion}; use key_server_cluster::math; use key_server_cluster::cluster::Cluster; use key_server_cluster::cluster::tests::DummyCluster; + use key_server_cluster::cluster_sessions::ClusterSession; use key_server_cluster::admin_sessions::ShareChangeSessionMeta; + use key_server_cluster::decryption_session::create_default_decryption_session; use key_server_cluster::message::{Message, KeyVersionNegotiationMessage, RequestKeyVersions, KeyVersions}; use super::{SessionImpl, SessionTransport, SessionParams, FastestResultComputer, LargestSupportResultComputer, - SessionResultComputer, SessionState}; + SessionResultComputer, SessionState, ContinueAction, FailedContinueAction}; struct DummyTransport { cluster: Arc, } impl SessionTransport for DummyTransport { + fn broadcast(&self, message: KeyVersionNegotiationMessage) -> Result<(), Error> { + self.cluster.broadcast(Message::KeyVersionNegotiation(message)) + } + fn send(&self, node: &NodeId, message: KeyVersionNegotiationMessage) -> Result<(), Error> { self.cluster.send(node, Message::KeyVersionNegotiation(message)) } @@ -600,6 +684,27 @@ mod tests { pub fn session(&self, idx: usize) -> &SessionImpl { &self.nodes.values().nth(idx).unwrap().session } + + pub fn take_message(&mut self) -> Option<(NodeId, NodeId, Message)> { + self.nodes.values() + .filter_map(|n| n.cluster.take_message().map(|m| (n.session.meta().self_node_id.clone(), m.0, m.1))) + .nth(0) + .or_else(|| self.queue.pop_front()) + } + + pub fn process_message(&mut self, msg: (NodeId, NodeId, Message)) -> Result<(), Error> { + match msg.2 { + Message::KeyVersionNegotiation(message) => + self.nodes[&msg.1].session.process_message(&msg.0, &message), + _ => panic!("unexpected"), + } + } + + pub fn run(&mut self) { + while let Some((from, to, message)) = self.take_message() { + self.process_message((from, to, message)).unwrap(); + } + } } #[test] @@ -739,6 +844,9 @@ mod tests { ml.session(0).initialize(ml.nodes.keys().cloned().collect()).unwrap(); // we can't be sure that node has given key version because previous ShareAdd session could fail assert!(ml.session(0).data.lock().state != SessionState::Finished); + + // check that upon completion, threshold is known + assert_eq!(ml.session(0).key_threshold(), Ok(1)); } #[test] @@ -757,4 +865,30 @@ mod tests { let computer = LargestSupportResultComputer; assert_eq!(computer.compute_result(Some(10), &Default::default(), &Default::default()), Some(Err(Error::ServerKeyIsNotFound))); } + + #[test] + fn fatal_error_is_not_broadcasted_if_started_without_origin() { + let mut ml = MessageLoop::empty(3); + ml.session(0).set_continue_action(ContinueAction::Decrypt(create_default_decryption_session(), None, false, false)); + ml.session(0).initialize(ml.nodes.keys().cloned().collect()).unwrap(); + ml.run(); + + assert!(ml.nodes.values().all(|n| n.session.is_finished() && + n.session.take_failed_continue_action().is_none())); + } + + #[test] + fn fatal_error_is_broadcasted_if_started_with_origin() { + let mut ml = MessageLoop::empty(3); + ml.session(0).set_continue_action(ContinueAction::Decrypt(create_default_decryption_session(), Some(1.into()), true, true)); + ml.session(0).initialize(ml.nodes.keys().cloned().collect()).unwrap(); + ml.run(); + + // on all nodes session is completed + assert!(ml.nodes.values().all(|n| n.session.is_finished())); + + // slave nodes have non-empty failed continue action + assert!(ml.nodes.values().skip(1).all(|n| n.session.take_failed_continue_action() + == Some(FailedContinueAction::Decrypt(Some(1.into()), public_to_address(&2.into()))))); + } } diff --git a/secret_store/src/key_server_cluster/admin_sessions/mod.rs b/secret_store/src/key_server_cluster/admin_sessions/mod.rs index 11c01cac53ea08043d7ae24be93da255b9b44ddd..1fedc1db40433d3ca73a9370ae7f49b045f26250 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/mod.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs b/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs index 698872aadc2df39be39a1b7ac073f8bb16a03c14..af612c3d9aa48ddaf26bf77f500ad87f7bbb6a0d 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -249,10 +249,16 @@ impl SessionImpl { })?; consensus_session.initialize(self.core.all_nodes_set.clone())?; - debug_assert!(consensus_session.state() != ConsensusSessionState::ConsensusEstablished); + + let is_finished = consensus_session.state() == ConsensusSessionState::ConsensusEstablished; data.consensus_session = Some(consensus_session); data.new_nodes_set = Some(new_nodes_set); + // this is the case when all other nodes are isolated + if is_finished { + Self::complete_session(&self.core, &mut *data)?; + } + Ok(()) } @@ -483,6 +489,7 @@ impl SessionImpl { false => { let master_plan = ShareChangeSessionPlan { key_version: message.version.clone().into(), + version_holders: message.version_holders.iter().cloned().map(Into::into).collect(), consensus_group: message.consensus_group.iter().cloned().map(Into::into).collect(), new_nodes_map: message.new_nodes_map.iter().map(|(k, v)| (k.clone().into(), v.clone().map(Into::into))).collect(), }; @@ -496,22 +503,20 @@ impl SessionImpl { let master_node_id = message.master_node_id.clone().into(); if let Some(key_share) = self.core.key_storage.get(&key_id)? { let version = message.version.clone().into(); - if let Ok(key_version) = key_share.version(&version) { - let key_share_owners = key_version.id_numbers.keys().cloned().collect(); - let new_nodes_set = data.new_nodes_set.as_ref() - .expect("new_nodes_set is filled during consensus establishing; change sessions are running after this; qed"); - let local_plan = prepare_share_change_session_plan( - &self.core.all_nodes_set, - key_share.threshold, - &key_id, - version, - &master_node_id, - &key_share_owners, - new_nodes_set)?; - - if local_plan.new_nodes_map.keys().collect::>() != master_plan.new_nodes_map.keys().collect::>() { - return Err(Error::InvalidMessage); - } + let key_share_owners = message.version_holders.iter().cloned().map(Into::into).collect(); + let new_nodes_set = data.new_nodes_set.as_ref() + .expect("new_nodes_set is filled during consensus establishing; change sessions are running after this; qed"); + let local_plan = prepare_share_change_session_plan( + &self.core.all_nodes_set, + key_share.threshold, + &key_id, + version, + &master_node_id, + &key_share_owners, + new_nodes_set)?; + + if local_plan.new_nodes_map.keys().collect::>() != master_plan.new_nodes_map.keys().collect::>() { + return Err(Error::InvalidMessage); } } @@ -791,7 +796,9 @@ impl SessionImpl { // get selected version && old nodes set from key negotiation session let negotiation_session = data.negotiation_sessions.remove(&key_id) .expect("share change session is only initialized when negotiation is completed; qed"); - let (selected_version, selected_master) = negotiation_session.wait()?; + let (selected_version, selected_master) = negotiation_session + .wait()? + .expect("initialize_share_change_session is only called on share change master; negotiation session completes with some on master; qed"); let selected_version_holders = negotiation_session.version_holders(&selected_version)?; let selected_version_threshold = negotiation_session.key_threshold()?; @@ -818,6 +825,7 @@ impl SessionImpl { session_nonce: core.nonce, key_id: key_id.clone().into(), version: selected_version.into(), + version_holders: old_nodes_set.iter().cloned().map(Into::into).collect(), master_node_id: selected_master.clone().into(), consensus_group: session_plan.consensus_group.iter().cloned().map(Into::into).collect(), new_nodes_map: session_plan.new_nodes_map.iter() @@ -942,7 +950,8 @@ impl ClusterSession for SessionImpl { let mut data = self.data.lock(); - warn!("{}: servers set change session failed: {} on {}", self.core.meta.self_node_id, error, node); + warn!(target: "secretstore_net", "{}: servers set change session failed: {} on {}", + self.core.meta.self_node_id, error, node); data.state = SessionState::Finished; data.result = Some(Err(error)); @@ -1007,6 +1016,14 @@ impl JobTransport for UnknownSessionsJobTransport { } impl KeyVersionNegotiationTransport for ServersSetChangeKeyVersionNegotiationTransport { + fn broadcast(&self, message: KeyVersionNegotiationMessage) -> Result<(), Error> { + self.cluster.broadcast(Message::ServersSetChange(ServersSetChangeMessage::ShareChangeKeyVersionNegotiation(ShareChangeKeyVersionNegotiation { + session: self.id.clone().into(), + session_nonce: self.nonce, + message: message, + }))) + } + fn send(&self, node: &NodeId, message: KeyVersionNegotiationMessage) -> Result<(), Error> { self.cluster.send(node, Message::ServersSetChange(ServersSetChangeMessage::ShareChangeKeyVersionNegotiation(ShareChangeKeyVersionNegotiation { session: self.id.clone().into(), @@ -1343,4 +1360,48 @@ pub mod tests { // check that all sessions have finished assert!(ml.nodes.iter().filter(|&(k, _)| !nodes_to_remove.contains(k)).all(|(_, n)| n.session.is_finished())); } + + #[test] + fn removing_node_from_cluster_of_2_works() { + // initial 2-of-2 session + let gml = generate_key(1, generate_nodes_ids(2)); + let master_node_id = gml.nodes.keys().cloned().nth(0).unwrap(); + + // make 2nd node isolated so that key becomes irrecoverable (make sure the session is completed, even though key is irrecoverable) + let nodes_to_isolate: BTreeSet<_> = gml.nodes.keys().cloned().skip(1).take(1).collect(); + let new_nodes_set: BTreeSet<_> = gml.nodes.keys().cloned().filter(|n| !nodes_to_isolate.contains(&n)).collect(); + let mut ml = MessageLoop::new(&gml, master_node_id, None, BTreeSet::new(), BTreeSet::new(), nodes_to_isolate.clone()); + ml.nodes[&master_node_id].session.initialize(new_nodes_set, ml.all_set_signature.clone(), ml.new_set_signature.clone()).unwrap(); + ml.run(); + + // check that session on master node has completed (session on 2nd node is not even started in network mode) + assert!(ml.nodes.values().take(1).all(|n| n.session.is_finished())); + } + + #[test] + fn adding_node_that_has_lost_its_database_works() { + // initial 2-of-2 session + let gml = generate_key(1, generate_nodes_ids(2)); + let master_node_id = gml.nodes.keys().cloned().nth(0).unwrap(); + + // insert 1 node so that it becames 2-of-3 session + let nodes_to_add: BTreeSet<_> = (0..1).map(|_| Random.generate().unwrap().public().clone()).collect(); + let mut ml = MessageLoop::new(&gml, master_node_id, None, nodes_to_add.clone(), BTreeSet::new(), BTreeSet::new()); + ml.nodes[&master_node_id].session.initialize(ml.nodes.keys().cloned().collect(), ml.all_set_signature.clone(), ml.new_set_signature.clone()).unwrap(); + ml.run(); + + // now let's say new node has lost its db and we're trying to join it again + ml.nodes[nodes_to_add.iter().nth(0).unwrap()].key_storage.clear().unwrap(); + + // this time old nodes have version, where new node is mentioned, but it doesn't report it when negotiating + let mut ml = MessageLoop::new(&gml, master_node_id, None, nodes_to_add, BTreeSet::new(), BTreeSet::new()); + ml.nodes[&master_node_id].session.initialize(ml.nodes.keys().cloned().collect(), ml.all_set_signature.clone(), ml.new_set_signature.clone()).unwrap(); + ml.run(); + + // try to recover secret for every possible combination of nodes && check that secret is the same + check_secret_is_preserved(ml.original_key_pair.clone(), ml.nodes.iter().map(|(k, v)| (k.clone(), v.key_storage.clone())).collect()); + + // check that all sessions have finished + assert!(ml.nodes.values().all(|n| n.session.is_finished())); + } } diff --git a/secret_store/src/key_server_cluster/admin_sessions/sessions_queue.rs b/secret_store/src/key_server_cluster/admin_sessions/sessions_queue.rs index 35adaab68cdafb49e038810453262836fa2b8fce..7657dfc82638901d17de66abcde1263745ef817f 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/sessions_queue.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/sessions_queue.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/admin_sessions/share_add_session.rs b/secret_store/src/key_server_cluster/admin_sessions/share_add_session.rs index abe34edeab22fbe437175fb9a81d97ed797afa10..51a027dca3865935e03f55f612df7554fc3641f5 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/share_add_session.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/share_add_session.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -39,7 +39,7 @@ pub trait SessionTransport: Clone + JobTransport Result<(), Error>; /// Set data for master node (sent to slave nodes in consensus session initialization message). - fn set_master_data(&mut self, consensus_group: BTreeSet, id_numbers: BTreeMap>); + fn set_master_data(&mut self, consensus_group: BTreeSet, version_holders: BTreeSet, id_numbers: BTreeMap>); } /// Share addition session. @@ -86,6 +86,8 @@ struct SessionData { pub version: Option, /// Consensus session. pub consensus_session: Option>, + /// Holders of key version. + pub version_holders: Option>, /// NewKeyShare (for nodes being added). pub new_key_share: Option, /// Nodes id numbers. @@ -144,6 +146,8 @@ pub struct IsolatedSessionTransport { version: Option, /// Session-level nonce. nonce: u64, + /// Holders of key version. + version_holders: Option>, /// Consensus group. consensus_group: Option>, /// Id numbers of all new nodes. @@ -171,6 +175,7 @@ impl SessionImpl where T: SessionTransport { state: SessionState::ConsensusEstablishing, version: None, consensus_session: None, + version_holders: None, new_key_share: None, id_numbers: None, secret_subshares: None, @@ -180,7 +185,7 @@ impl SessionImpl where T: SessionTransport { } /// Set pre-established consensus data. - pub fn set_consensus_output(&self, version: &H256, consensus_group: BTreeSet, mut new_nodes_map: BTreeMap>) -> Result<(), Error> { + pub fn set_consensus_output(&self, version: &H256, consensus_group: BTreeSet, version_holders: BTreeSet, mut new_nodes_map: BTreeMap>) -> Result<(), Error> { let mut data = self.data.lock(); // check state @@ -191,18 +196,30 @@ impl SessionImpl where T: SessionTransport { // key share version is required on ShareAdd master node if let Some(key_share) = self.core.key_share.as_ref() { if let Ok(key_version) = key_share.version(version) { + let non_isolated_nodes = self.core.transport.nodes(); for (node, id_number) in &key_version.id_numbers { { let external_id_number = new_nodes_map.get(node); match external_id_number { Some(&Some(ref external_id_number)) => { + if !version_holders.contains(node) { + // possible when joining version holder, that has lost its database + // and haven't reported version ownership + continue; + } if external_id_number == id_number { continue; } + return Err(Error::ConsensusUnreachable); }, Some(&None) => (), - None => return Err(Error::ConsensusUnreachable), + None => { + if non_isolated_nodes.contains(node) { + return Err(Error::ConsensusUnreachable) + } + continue; + }, } } @@ -217,7 +234,7 @@ impl SessionImpl where T: SessionTransport { } // check passed consensus data - Self::check_nodes_map(&self.core, version, &consensus_group, &new_nodes_map)?; + Self::check_nodes_map(&self.core, version, &consensus_group, &version_holders, &new_nodes_map)?; // update data data.version = Some(version.clone()); @@ -225,6 +242,7 @@ impl SessionImpl where T: SessionTransport { data.secret_subshares = Some(consensus_group.into_iter() .map(|n| (n, None)) .collect()); + data.version_holders = Some(version_holders); Ok(()) } @@ -281,13 +299,14 @@ impl SessionImpl where T: SessionTransport { .take(key_share.threshold) .cloned()) .collect(); + let version_holders = &old_nodes_set; // now check nodes map - Self::check_nodes_map(&self.core, &version, &consensus_group, &new_nodes_map)?; + Self::check_nodes_map(&self.core, &version, &consensus_group, version_holders, &new_nodes_map)?; // prepare consensus session transport let mut consensus_transport = self.core.transport.clone(); - consensus_transport.set_master_data(consensus_group.clone(), new_nodes_map.clone()); + consensus_transport.set_master_data(consensus_group.clone(), version_holders.clone(), new_nodes_map.clone()); // create && initialize consensus session let mut consensus_session = ConsensusSession::new(ConsensusSessionParams { @@ -306,6 +325,7 @@ impl SessionImpl where T: SessionTransport { data.consensus_session = Some(consensus_session); data.id_numbers = Some(new_nodes_map); data.secret_subshares = Some(consensus_group.into_iter().map(|n| (n, None)).collect()); + data.version_holders = Some(version_holders.clone()); Ok(()) } @@ -351,16 +371,17 @@ impl SessionImpl where T: SessionTransport { }; // process consensus message - let (is_establishing_consensus, is_consensus_established, version, new_nodes_map, consensus_group) = { + let (is_establishing_consensus, is_consensus_established, version, new_nodes_map, consensus_group, version_holders) = { let consensus_session = data.consensus_session.as_mut().ok_or(Error::InvalidMessage)?; let is_establishing_consensus = consensus_session.state() == ConsensusSessionState::EstablishingConsensus; - let (version, new_nodes_map, consensus_group) = match &message.message { + let (version, new_nodes_map, consensus_group, version_holders) = match &message.message { &ConsensusMessageOfShareAdd::InitializeConsensusSession(ref message) => { consensus_session.on_consensus_partial_request(sender, ServersSetChangeAccessRequest::from(message))?; let version = message.version.clone().into(); let consensus_group = message.consensus_group.iter().cloned().map(Into::into).collect(); + let version_holders = message.version_holders.iter().cloned().map(Into::into).collect(); let new_nodes_map: BTreeMap<_, _> = message.new_nodes_map.iter() .map(|(n, nn)| (n.clone().into(), Some(nn.clone().into()))) .collect(); @@ -371,13 +392,13 @@ impl SessionImpl where T: SessionTransport { } // check old set of nodes - Self::check_nodes_map(&self.core, &version, &consensus_group, &new_nodes_map)?; + Self::check_nodes_map(&self.core, &version, &consensus_group, &version_holders, &new_nodes_map)?; - (Some(version), Some(new_nodes_map), Some(consensus_group)) + (Some(version), Some(new_nodes_map), Some(consensus_group), Some(version_holders)) }, &ConsensusMessageOfShareAdd::ConfirmConsensusInitialization(ref message) => { consensus_session.on_consensus_partial_response(sender, message.is_confirmed)?; - (None, None, None) + (None, None, None, None) }, }; @@ -387,6 +408,7 @@ impl SessionImpl where T: SessionTransport { version, new_nodes_map, consensus_group, + version_holders, ) }; @@ -400,6 +422,9 @@ impl SessionImpl where T: SessionTransport { if let Some(consensus_group) = consensus_group { data.secret_subshares = Some(consensus_group.into_iter().map(|n| (n, None)).collect()); } + if let Some(version_holders) = version_holders { + data.version_holders = Some(version_holders); + } // if consensus is stablished, proceed if !is_establishing_consensus || !is_consensus_established || self.core.meta.self_node_id != self.core.meta.master_node_id { @@ -451,7 +476,7 @@ impl SessionImpl where T: SessionTransport { }); let id_numbers = data.id_numbers.as_mut() - .expect("common key share data is expected after initialization; id_numers are filled during initialization; qed"); + .expect("common key share data is expected after initialization; id_numbers are filled during initialization; qed"); for (node, id_number) in &message.id_numbers { let id_number: Secret = id_number.clone().into(); { @@ -519,7 +544,7 @@ impl SessionImpl where T: SessionTransport { } /// Check nodes map. - fn check_nodes_map(core: &SessionCore, version: &H256, consensus_group: &BTreeSet, new_nodes_map: &BTreeMap>) -> Result<(), Error> { + fn check_nodes_map(core: &SessionCore, version: &H256, consensus_group: &BTreeSet, version_holders: &BTreeSet, new_nodes_map: &BTreeMap>) -> Result<(), Error> { // check if this node has given version let has_this_version = match core.key_share.as_ref() { Some(key_share) => key_share.version(version).is_ok(), @@ -546,7 +571,7 @@ impl SessionImpl where T: SessionTransport { } // there must be at least one new node in new_nodes_map - if key_version.id_numbers.len() >= new_nodes_map.len() { + if key_version.id_numbers.keys().filter(|n| non_isolated_nodes.contains(n) && version_holders.contains(n)).count() >= new_nodes_map.len() { return Err(Error::ConsensusUnreachable); } }, @@ -607,6 +632,8 @@ impl SessionImpl where T: SessionTransport { let explanation = "disseminate_common_share_data is only called on master node; master node has specified version of the key; qed"; let old_key_share = core.key_share.as_ref().expect(explanation); let old_key_version = old_key_share.version(data.version.as_ref().expect(explanation)).expect(explanation); + let version_holders = data.version_holders.as_ref() + .expect("disseminate_common_share_data is only called on master node; version holders is created during initialization on master node; qed"); let consensus_group = data.secret_subshares.as_ref() .expect("disseminate_common_share_data is only called on master node; consensus group is created during initialization on master node; qed"); let nodes = data.id_numbers.as_ref() @@ -622,7 +649,9 @@ impl SessionImpl where T: SessionTransport { joint_public: old_key_share.public.clone().into(), common_point: old_key_share.common_point.clone().map(Into::into), encrypted_point: old_key_share.encrypted_point.clone().map(Into::into), - id_numbers: old_key_version.id_numbers.iter().map(|(k, v)| (k.clone().into(), v.clone().into())).collect(), + id_numbers: old_key_version.id_numbers.iter() + .filter(|&(k, _)| version_holders.contains(k)) + .map(|(k, v)| (k.clone().into(), v.clone().into())).collect(), }))?; } @@ -765,7 +794,8 @@ impl ClusterSession for SessionImpl where T: SessionTransport { let mut data = self.data.lock(); - warn!("{}: share add session failed: {} on {}", self.core.meta.self_node_id, error, node); + warn!(target: "secretstore_net", "{}: share add session failed: {} on {}", + self.core.meta.self_node_id, error, node); data.state = SessionState::Finished; data.result = Some(Err(error)); @@ -788,6 +818,7 @@ impl IsolatedSessionTransport { nonce: nonce, cluster: cluster, id_numbers: None, + version_holders: None, consensus_group: None, } } @@ -806,6 +837,7 @@ impl JobTransport for IsolatedSessionTransport { session_nonce: self.nonce, message: ConsensusMessageOfShareAdd::InitializeConsensusSession(InitializeConsensusSessionOfShareAdd { version: self.version.clone().expect(explanation).into(), + version_holders: self.version_holders.as_ref().expect(explanation).iter().cloned().map(Into::into).collect(), consensus_group: self.consensus_group.as_ref().expect(explanation).iter().cloned().map(Into::into).collect(), old_nodes_set: request.old_servers_set.into_iter().map(Into::into).collect(), new_nodes_map: request.new_servers_set.into_iter() @@ -836,7 +868,8 @@ impl SessionTransport for IsolatedSessionTransport { self.cluster.nodes() } - fn set_master_data(&mut self, consensus_group: BTreeSet, id_numbers: BTreeMap>) { + fn set_master_data(&mut self, consensus_group: BTreeSet, version_holders: BTreeSet, id_numbers: BTreeMap>) { + self.version_holders = Some(version_holders); self.consensus_group = Some(consensus_group); self.id_numbers = Some(id_numbers); } diff --git a/secret_store/src/key_server_cluster/admin_sessions/share_change_session.rs b/secret_store/src/key_server_cluster/admin_sessions/share_change_session.rs index 1e408ee52e7ab8db803779dd65c5878ac92611e6..48cb81c137a006c0ff98e9f7edbae8abbef09f77 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/share_change_session.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/share_change_session.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -48,6 +48,8 @@ pub struct ShareChangeSession { key_storage: Arc, /// Key version. key_version: H256, + /// Nodes that have reported version ownership. + version_holders: Option>, /// Consensus group to use in ShareAdd session. consensus_group: Option>, /// Nodes to add shares for. @@ -63,6 +65,8 @@ pub struct ShareChangeSession { pub struct ShareChangeSessionPlan { /// Key version that plan is valid for. pub key_version: H256, + /// Nodes that have reported version ownership. + pub version_holders: BTreeSet, /// Consensus group to use in ShareAdd session. pub consensus_group: BTreeSet, /// Nodes to add shares for. @@ -102,6 +106,7 @@ impl ShareChangeSession { // we can't create sessions right now, because key share is read when session is created, but it can change in previous session let key_version = params.plan.key_version; let consensus_group = if !params.plan.consensus_group.is_empty() { Some(params.plan.consensus_group) } else { None }; + let version_holders = if !params.plan.version_holders.is_empty() { Some(params.plan.version_holders) } else { None }; let new_nodes_map = if !params.plan.new_nodes_map.is_empty() { Some(params.plan.new_nodes_map) } else { None }; debug_assert!(new_nodes_map.is_some()); @@ -113,6 +118,7 @@ impl ShareChangeSession { cluster: params.cluster, key_storage: params.key_storage, key_version: key_version, + version_holders: version_holders, consensus_group: consensus_group, new_nodes_map: new_nodes_map, share_add_session: None, @@ -158,6 +164,7 @@ impl ShareChangeSession { /// Create new share add session. fn create_share_add_session(&mut self) -> Result<(), Error> { let consensus_group = self.consensus_group.take().ok_or(Error::InvalidStateForRequest)?; + let version_holders = self.version_holders.take().ok_or(Error::InvalidStateForRequest)?; let new_nodes_map = self.new_nodes_map.take().ok_or(Error::InvalidStateForRequest)?; let share_add_session = ShareAddSessionImpl::new(ShareAddSessionParams { meta: self.meta.clone(), @@ -166,7 +173,7 @@ impl ShareChangeSession { key_storage: self.key_storage.clone(), admin_public: None, })?; - share_add_session.set_consensus_output(&self.key_version, consensus_group, new_nodes_map)?; + share_add_session.set_consensus_output(&self.key_version, consensus_group, version_holders, new_nodes_map)?; self.share_add_session = Some(share_add_session); Ok(()) } @@ -221,7 +228,7 @@ impl ShareAddSessionTransport for ShareChangeTransport { self.cluster.nodes() } - fn set_master_data(&mut self, _consensus_group: BTreeSet, _id_numbers: BTreeMap>) { + fn set_master_data(&mut self, _consensus_group: BTreeSet, _version_holders: BTreeSet, _id_numbers: BTreeMap>) { unreachable!("only called when establishing consensus; this transport is never used for establishing consensus; qed") } @@ -242,6 +249,7 @@ pub fn prepare_share_change_session_plan(cluster_nodes: &BTreeSet, thres key_id, threshold, old_key_version_owners.len()); return Ok(ShareChangeSessionPlan { key_version: key_version, + version_holders: Default::default(), consensus_group: Default::default(), new_nodes_map: Default::default(), }); @@ -279,6 +287,7 @@ pub fn prepare_share_change_session_plan(cluster_nodes: &BTreeSet, thres Ok(ShareChangeSessionPlan { key_version: key_version, + version_holders: old_key_version_owners.clone(), consensus_group: consensus_group, new_nodes_map: new_nodes_map, }) diff --git a/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs b/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs index f852451b43347452e5a9cde0f319225b5175ec28..9172a03b1a86d81565e18d2d30ead9fe0447c030 100644 --- a/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs +++ b/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -812,6 +812,28 @@ impl JobTransport for DecryptionJobTransport { } } +#[cfg(test)] +pub fn create_default_decryption_session() -> Arc { + use acl_storage::DummyAclStorage; + use key_server_cluster::cluster::tests::DummyCluster; + + Arc::new(SessionImpl::new(SessionParams { + meta: SessionMeta { + id: Default::default(), + self_node_id: Default::default(), + master_node_id: Default::default(), + threshold: 0, + configured_nodes_count: 0, + connected_nodes_count: 0, + }, + access_key: Secret::zero(), + key_share: Default::default(), + acl_storage: Arc::new(DummyAclStorage::default()), + cluster: Arc::new(DummyCluster::new(Default::default())), + nonce: 0, + }, Some(Requester::Public(2.into()))).unwrap()) +} + #[cfg(test)] mod tests { use std::sync::Arc; diff --git a/secret_store/src/key_server_cluster/client_sessions/encryption_session.rs b/secret_store/src/key_server_cluster/client_sessions/encryption_session.rs index 3c863d1cb932183d309f72aca43b65b2a24a9ade..70532b69052171aa061b4ba0f672e7390801fdb4 100644 --- a/secret_store/src/key_server_cluster/client_sessions/encryption_session.rs +++ b/secret_store/src/key_server_cluster/client_sessions/encryption_session.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/client_sessions/generation_session.rs b/secret_store/src/key_server_cluster/client_sessions/generation_session.rs index c2effe6c26d717b2612e27821e4c5686bb0acbc1..7001ccf69ec49a721d01d3a3cc4b3de3e52fa2ab 100644 --- a/secret_store/src/key_server_cluster/client_sessions/generation_session.rs +++ b/secret_store/src/key_server_cluster/client_sessions/generation_session.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -1299,7 +1299,6 @@ pub mod tests { }).unwrap_err(), Error::InvalidMessage); } - #[test] fn encryption_fails_on_session_timeout() { let (_, _, _, l) = make_simple_cluster(0, 2).unwrap(); diff --git a/secret_store/src/key_server_cluster/client_sessions/mod.rs b/secret_store/src/key_server_cluster/client_sessions/mod.rs index ba2fbd5350084773a6db13832805c4a3eda74d54..133edcffbb233a0a9027a765d7404f8bf012a1cc 100644 --- a/secret_store/src/key_server_cluster/client_sessions/mod.rs +++ b/secret_store/src/key_server_cluster/client_sessions/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/client_sessions/signing_session_ecdsa.rs b/secret_store/src/key_server_cluster/client_sessions/signing_session_ecdsa.rs index b0d465343bd178b0729d698465dda9d5df8a1d06..670fa138f2cd5b44f37c03557511958ec4a0d5e2 100644 --- a/secret_store/src/key_server_cluster/client_sessions/signing_session_ecdsa.rs +++ b/secret_store/src/key_server_cluster/client_sessions/signing_session_ecdsa.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -644,7 +644,6 @@ impl SessionImpl { Self::compute_inversed_nonce_coeff(&self.core, &*data)? }; - let version = data.version.as_ref().ok_or(Error::InvalidMessage)?.clone(); let message_hash = data.message_hash .expect("we are on master node; on master node message_hash is filled in initialize(); on_generation_message follows initialize; qed"); diff --git a/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs b/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs index 013748827c0c85374b08d27ab57bac9b7de5aef8..376eab26b4f66997a2e6983fa8aae834cbad0272 100644 --- a/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs +++ b/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -1289,4 +1289,4 @@ mod tests { _ => unreachable!(), } } -} \ No newline at end of file +} diff --git a/secret_store/src/key_server_cluster/cluster.rs b/secret_store/src/key_server_cluster/cluster.rs index d782ccd035f25431dd89d6008a371de7e9dd8d1b..b48290a4fc33673ebf39920d56e3a87aa9e2dfca 100644 --- a/secret_store/src/key_server_cluster/cluster.rs +++ b/secret_store/src/key_server_cluster/cluster.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -84,6 +84,8 @@ pub trait ClusterClient: Send + Sync { fn add_generation_listener(&self, listener: Arc>); /// Listen for new decryption sessions. fn add_decryption_listener(&self, listener: Arc>); + /// Listen for new key version negotiation sessions. + fn add_key_version_negotiation_listener(&self, listener: Arc>>); /// Ask node to make 'faulty' generation sessions. #[cfg(test)] @@ -198,9 +200,10 @@ pub struct ClusterConnections { pub data: RwLock, } -#[derive(Default)] /// Cluster connections data. pub struct ClusterConnectionsData { + /// Is this node isolated from cluster? + pub is_isolated: bool, /// Active key servers set. pub nodes: BTreeMap, /// Active connections to key servers. @@ -384,6 +387,9 @@ impl ClusterCore { for connection in data.connections.active_connections() { let last_message_diff = Instant::now() - connection.last_message_time(); if last_message_diff > KEEP_ALIVE_DISCONNECT_INTERVAL { + warn!(target: "secretstore_net", "{}: keep alive timeout for node {}", + data.self_key_pair.public(), connection.node_id()); + data.connections.remove(data.clone(), connection.node_id(), connection.is_inbound()); data.sessions.on_connection_timeout(connection.node_id()); } @@ -484,7 +490,7 @@ impl ClusterCore { if is_master_node && session.is_finished() { data.sessions.negotiation_sessions.remove(&session.id()); match session.wait() { - Ok((version, master)) => match session.take_continue_action() { + Ok(Some((version, master))) => match session.take_continue_action() { Some(ContinueAction::Decrypt(session, origin, is_shadow_decryption, is_broadcast_decryption)) => { let initialization_error = if data.self_key_pair.public() == &master { session.initialize(origin, version, is_shadow_decryption, is_broadcast_decryption) @@ -523,18 +529,19 @@ impl ClusterCore { }, None => (), }, + Ok(None) => unreachable!("is_master_node; session is finished; negotiation version always finished with result on master; qed"), Err(error) => match session.take_continue_action() { Some(ContinueAction::Decrypt(session, _, _, _)) => { - data.sessions.decryption_sessions.remove(&session.id()); session.on_session_error(&meta.self_node_id, error); + data.sessions.decryption_sessions.remove(&session.id()); }, Some(ContinueAction::SchnorrSign(session, _)) => { - data.sessions.schnorr_signing_sessions.remove(&session.id()); session.on_session_error(&meta.self_node_id, error); + data.sessions.schnorr_signing_sessions.remove(&session.id()); }, Some(ContinueAction::EcdsaSign(session, _)) => { - data.sessions.ecdsa_signing_sessions.remove(&session.id()); session.on_session_error(&meta.self_node_id, error); + data.sessions.ecdsa_signing_sessions.remove(&session.id()); }, None => (), }, @@ -653,7 +660,7 @@ impl ClusterCore { impl ClusterConnections { pub fn new(config: &ClusterConfiguration) -> Result { let mut nodes = config.key_server_set.snapshot().current_set; - nodes.remove(config.self_key_pair.public()); + let is_isolated = nodes.remove(config.self_key_pair.public()).is_none(); let trigger: Box = match config.auto_migrate_enabled { false => Box::new(SimpleConnectionTrigger::new(config.key_server_set.clone(), config.self_key_pair.clone(), config.admin_public.clone())), @@ -668,6 +675,7 @@ impl ClusterConnections { trigger: Mutex::new(trigger), connector: connector, data: RwLock::new(ClusterConnectionsData { + is_isolated: is_isolated, nodes: nodes, connections: BTreeMap::new(), }), @@ -734,8 +742,13 @@ impl ClusterConnections { self.maintain_connection_trigger(maintain_action, data); } - pub fn connected_nodes(&self) -> BTreeSet { - self.data.read().connections.keys().cloned().collect() + pub fn connected_nodes(&self) -> Result, Error> { + let data = self.data.read(); + if data.is_isolated { + return Err(Error::NodeDisconnected); + } + + Ok(data.connections.keys().cloned().collect()) } pub fn active_connections(&self)-> Vec> { @@ -897,7 +910,7 @@ impl ClusterClientImpl { } fn create_key_version_negotiation_session(&self, session_id: SessionId) -> Result>, Error> { - let mut connected_nodes = self.data.connections.connected_nodes(); + let mut connected_nodes = self.data.connections.connected_nodes()?; connected_nodes.insert(self.data.self_key_pair.public().clone()); let access_key = Random.generate()?.secret().clone(); @@ -934,7 +947,7 @@ impl ClusterClient for ClusterClientImpl { } fn new_generation_session(&self, session_id: SessionId, origin: Option
, author: Address, threshold: usize) -> Result, Error> { - let mut connected_nodes = self.data.connections.connected_nodes(); + let mut connected_nodes = self.data.connections.connected_nodes()?; connected_nodes.insert(self.data.self_key_pair.public().clone()); let cluster = create_cluster_view(&self.data, true)?; @@ -945,7 +958,7 @@ impl ClusterClient for ClusterClientImpl { } fn new_encryption_session(&self, session_id: SessionId, requester: Requester, common_point: Public, encrypted_point: Public) -> Result, Error> { - let mut connected_nodes = self.data.connections.connected_nodes(); + let mut connected_nodes = self.data.connections.connected_nodes()?; connected_nodes.insert(self.data.self_key_pair.public().clone()); let cluster = create_cluster_view(&self.data, true)?; @@ -956,7 +969,7 @@ impl ClusterClient for ClusterClientImpl { } fn new_decryption_session(&self, session_id: SessionId, origin: Option
, requester: Requester, version: Option, is_shadow_decryption: bool, is_broadcast_decryption: bool) -> Result, Error> { - let mut connected_nodes = self.data.connections.connected_nodes(); + let mut connected_nodes = self.data.connections.connected_nodes()?; connected_nodes.insert(self.data.self_key_pair.public().clone()); let access_key = Random.generate()?.secret().clone(); @@ -982,7 +995,7 @@ impl ClusterClient for ClusterClientImpl { } fn new_schnorr_signing_session(&self, session_id: SessionId, requester: Requester, version: Option, message_hash: H256) -> Result, Error> { - let mut connected_nodes = self.data.connections.connected_nodes(); + let mut connected_nodes = self.data.connections.connected_nodes()?; connected_nodes.insert(self.data.self_key_pair.public().clone()); let access_key = Random.generate()?.secret().clone(); @@ -1007,7 +1020,7 @@ impl ClusterClient for ClusterClientImpl { } fn new_ecdsa_signing_session(&self, session_id: SessionId, requester: Requester, version: Option, message_hash: H256) -> Result, Error> { - let mut connected_nodes = self.data.connections.connected_nodes(); + let mut connected_nodes = self.data.connections.connected_nodes()?; connected_nodes.insert(self.data.self_key_pair.public().clone()); let access_key = Random.generate()?.secret().clone(); @@ -1037,7 +1050,7 @@ impl ClusterClient for ClusterClientImpl { } fn new_servers_set_change_session(&self, session_id: Option, migration_id: Option, new_nodes_set: BTreeSet, old_set_signature: Signature, new_set_signature: Signature) -> Result, Error> { - let mut connected_nodes = self.data.connections.connected_nodes(); + let mut connected_nodes = self.data.connections.connected_nodes()?; connected_nodes.insert(self.data.self_key_pair.public().clone()); let session_id = match session_id { @@ -1069,6 +1082,10 @@ impl ClusterClient for ClusterClientImpl { self.data.sessions.decryption_sessions.add_listener(listener); } + fn add_key_version_negotiation_listener(&self, listener: Arc>>) { + self.data.sessions.negotiation_sessions.add_listener(listener); + } + #[cfg(test)] fn connect(&self) { ClusterCore::connect_disconnected_nodes(self.data.clone()); @@ -1153,6 +1170,7 @@ pub mod tests { fn add_generation_listener(&self, _listener: Arc>) {} fn add_decryption_listener(&self, _listener: Arc>) {} + fn add_key_version_negotiation_listener(&self, _listener: Arc>>) {} fn make_faulty_generation_sessions(&self) { unimplemented!("test-only") } fn generation_session(&self, _session_id: &SessionId) -> Option> { unimplemented!("test-only") } @@ -1249,7 +1267,7 @@ pub mod tests { threads: 1, self_key_pair: Arc::new(PlainNodeKeyPair::new(key_pairs[i].clone())), listen_address: ("127.0.0.1".to_owned(), ports_begin + i as u16), - key_server_set: Arc::new(MapKeyServerSet::new(key_pairs.iter().enumerate() + key_server_set: Arc::new(MapKeyServerSet::new(false, key_pairs.iter().enumerate() .map(|(j, kp)| (kp.public().clone(), format!("127.0.0.1:{}", ports_begin + j as u16).parse().unwrap())) .collect())), allow_connecting_to_higher_nodes: false, diff --git a/secret_store/src/key_server_cluster/cluster_sessions.rs b/secret_store/src/key_server_cluster/cluster_sessions.rs index 780c947fc3774e669fcecfce96ba19850f810f15..b34485638e6de3f43df973e386ba33114b4982ef 100644 --- a/secret_store/src/key_server_cluster/cluster_sessions.rs +++ b/secret_store/src/key_server_cluster/cluster_sessions.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -330,10 +330,7 @@ impl ClusterSessionsContainer where S: ClusterSession, SC: C } pub fn remove(&self, session_id: &S::Id) { - if let Some(session) = self.sessions.write().remove(session_id) { - self.container_state.lock().on_session_completed(); - self.notify_listeners(|l| l.on_session_removed(session.session.clone())); - } + self.do_remove(session_id, &mut *self.sessions.write()); } pub fn enqueue_message(&self, session_id: &S::Id, sender: NodeId, message: Message, is_queued_message: bool) { @@ -361,7 +358,7 @@ impl ClusterSessionsContainer where S: ClusterSession, SC: C }; if remove_session { - sessions.remove(&sid); + self.do_remove(&sid, &mut *sessions); } } } @@ -374,12 +371,20 @@ impl ClusterSessionsContainer where S: ClusterSession, SC: C session.session.on_node_timeout(node_id); session.session.is_finished() }; + if remove_session { - sessions.remove(&sid); + self.do_remove(&sid, &mut *sessions); } } } + fn do_remove(&self, session_id: &S::Id, sessions: &mut BTreeMap>) { + if let Some(session) = sessions.remove(session_id) { + self.container_state.lock().on_session_completed(); + self.notify_listeners(|l| l.on_session_removed(session.session.clone())); + } + } + fn notify_listeners) -> ()>(&self, callback: F) { let mut listeners = self.listeners.lock(); let mut listener_index = 0; @@ -554,7 +559,7 @@ pub fn create_cluster_view(data: &Arc, requires_all_connections: bo } } - let mut connected_nodes = data.connections.connected_nodes(); + let mut connected_nodes = data.connections.connected_nodes()?; connected_nodes.insert(data.self_key_pair.public().clone()); let connected_nodes_count = connected_nodes.len(); @@ -571,7 +576,8 @@ mod tests { use key_server_cluster::connection_trigger::SimpleServersSetChangeSessionCreatorConnector; use key_server_cluster::cluster::tests::DummyCluster; use key_server_cluster::generation_session::{SessionImpl as GenerationSession}; - use super::{ClusterSessions, AdminSessionCreationData, ClusterSessionsListener}; + use super::{ClusterSessions, AdminSessionCreationData, ClusterSessionsListener, + ClusterSessionsContainerState, SESSION_TIMEOUT_INTERVAL}; pub fn make_cluster_sessions() -> ClusterSessions { let key_pair = Random.generate().unwrap(); @@ -579,7 +585,7 @@ mod tests { threads: 1, self_key_pair: Arc::new(PlainNodeKeyPair::new(key_pair.clone())), listen_address: ("127.0.0.1".to_owned(), 100_u16), - key_server_set: Arc::new(MapKeyServerSet::new(vec![(key_pair.public().clone(), format!("127.0.0.1:{}", 100).parse().unwrap())].into_iter().collect())), + key_server_set: Arc::new(MapKeyServerSet::new(false, vec![(key_pair.public().clone(), format!("127.0.0.1:{}", 100).parse().unwrap())].into_iter().collect())), allow_connecting_to_higher_nodes: false, key_storage: Arc::new(DummyKeyStorage::default()), acl_storage: Arc::new(DummyAclStorage::default()), @@ -644,4 +650,41 @@ mod tests { assert_eq!(listener.inserted.load(Ordering::Relaxed), 1); assert_eq!(listener.removed.load(Ordering::Relaxed), 1); } + + #[test] + fn last_session_removal_sets_container_state_to_idle() { + let sessions = make_cluster_sessions(); + + sessions.generation_sessions.insert(Arc::new(DummyCluster::new(Default::default())), Default::default(), Default::default(), None, false, None).unwrap(); + assert_eq!(*sessions.generation_sessions.container_state.lock(), ClusterSessionsContainerState::Active(1)); + + sessions.generation_sessions.remove(&Default::default()); + assert_eq!(*sessions.generation_sessions.container_state.lock(), ClusterSessionsContainerState::Idle); + } + + #[test] + fn last_session_removal_by_timeout_sets_container_state_to_idle() { + let sessions = make_cluster_sessions(); + + sessions.generation_sessions.insert(Arc::new(DummyCluster::new(Default::default())), Default::default(), Default::default(), None, false, None).unwrap(); + assert_eq!(*sessions.generation_sessions.container_state.lock(), ClusterSessionsContainerState::Active(1)); + + sessions.generation_sessions.sessions.write().get_mut(&Default::default()).unwrap().last_message_time -= SESSION_TIMEOUT_INTERVAL * 2; + + sessions.generation_sessions.stop_stalled_sessions(); + assert_eq!(sessions.generation_sessions.sessions.read().len(), 0); + assert_eq!(*sessions.generation_sessions.container_state.lock(), ClusterSessionsContainerState::Idle); + } + + #[test] + fn last_session_removal_by_node_timeout_sets_container_state_to_idle() { + let sessions = make_cluster_sessions(); + + sessions.generation_sessions.insert(Arc::new(DummyCluster::new(Default::default())), Default::default(), Default::default(), None, false, None).unwrap(); + assert_eq!(*sessions.generation_sessions.container_state.lock(), ClusterSessionsContainerState::Active(1)); + + sessions.generation_sessions.on_connection_timeout(&Default::default()); + assert_eq!(sessions.generation_sessions.sessions.read().len(), 0); + assert_eq!(*sessions.generation_sessions.container_state.lock(), ClusterSessionsContainerState::Idle); + } } diff --git a/secret_store/src/key_server_cluster/cluster_sessions_creator.rs b/secret_store/src/key_server_cluster/cluster_sessions_creator.rs index a56f51f8fbc3d787725b6d26299c021d65a509f7..15192542b5cdccddd30af1fd866cda3db22cc3ae 100644 --- a/secret_store/src/key_server_cluster/cluster_sessions_creator.rs +++ b/secret_store/src/key_server_cluster/cluster_sessions_creator.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -353,6 +353,9 @@ impl ClusterSessionCreator) { if !required_set.contains_key(self_node_id) { - trace!(target: "secretstore_net", "{}: isolated from cluser", self_node_id); + if !data.is_isolated { + trace!(target: "secretstore_net", "{}: isolated from cluser", self_node_id); + } + + data.is_isolated = true; data.connections.clear(); data.nodes.clear(); return; } + data.is_isolated = false; for node_to_disconnect in select_nodes_to_disconnect(&data.nodes, required_set) { if let Entry::Occupied(entry) = data.connections.entry(node_to_disconnect.clone()) { - trace!(target: "secretstore_net", "{}: removing connection to {} at {}", + trace!(target: "secretstore_net", "{}: adjusting connections - removing connection to {} at {}", self_node_id, entry.get().node_id(), entry.get().node_address()); entry.remove(); } @@ -204,6 +209,14 @@ mod tests { use super::{Maintain, TriggerConnections, ConnectionsAction, ConnectionTrigger, SimpleConnectionTrigger, select_nodes_to_disconnect, adjust_connections}; + fn default_connection_data() -> ClusterConnectionsData { + ClusterConnectionsData { + is_isolated: false, + nodes: Default::default(), + connections: Default::default(), + } + } + fn create_connections() -> TriggerConnections { TriggerConnections { self_key_pair: Arc::new(PlainNodeKeyPair::new(Random.generate().unwrap())), @@ -252,59 +265,64 @@ mod tests { fn adjust_connections_disconnects_from_all_nodes_if_not_a_part_of_key_server() { let self_node_id = Random.generate().unwrap().public().clone(); let other_node_id = Random.generate().unwrap().public().clone(); - let mut connection_data: ClusterConnectionsData = Default::default(); + let mut connection_data = default_connection_data(); connection_data.nodes.insert(other_node_id.clone(), "127.0.0.1:8081".parse().unwrap()); let required_set = connection_data.nodes.clone(); adjust_connections(&self_node_id, &mut connection_data, &required_set); assert!(connection_data.nodes.is_empty()); + assert!(connection_data.is_isolated); } #[test] fn adjust_connections_connects_to_new_nodes() { let self_node_id = Random.generate().unwrap().public().clone(); let other_node_id = Random.generate().unwrap().public().clone(); - let mut connection_data: ClusterConnectionsData = Default::default(); + let mut connection_data = default_connection_data(); let required_set = vec![(self_node_id.clone(), "127.0.0.1:8081".parse().unwrap()), (other_node_id.clone(), "127.0.0.1:8082".parse().unwrap())].into_iter().collect(); adjust_connections(&self_node_id, &mut connection_data, &required_set); assert!(connection_data.nodes.contains_key(&other_node_id)); + assert!(!connection_data.is_isolated); } #[test] fn adjust_connections_reconnects_from_changed_nodes() { let self_node_id = Random.generate().unwrap().public().clone(); let other_node_id = Random.generate().unwrap().public().clone(); - let mut connection_data: ClusterConnectionsData = Default::default(); + let mut connection_data = default_connection_data(); connection_data.nodes.insert(other_node_id.clone(), "127.0.0.1:8082".parse().unwrap()); let required_set = vec![(self_node_id.clone(), "127.0.0.1:8081".parse().unwrap()), (other_node_id.clone(), "127.0.0.1:8083".parse().unwrap())].into_iter().collect(); adjust_connections(&self_node_id, &mut connection_data, &required_set); assert_eq!(connection_data.nodes.get(&other_node_id), Some(&"127.0.0.1:8083".parse().unwrap())); + assert!(!connection_data.is_isolated); } #[test] fn adjust_connections_disconnects_from_removed_nodes() { let self_node_id = Random.generate().unwrap().public().clone(); let other_node_id = Random.generate().unwrap().public().clone(); - let mut connection_data: ClusterConnectionsData = Default::default(); + let mut connection_data = default_connection_data(); connection_data.nodes.insert(other_node_id.clone(), "127.0.0.1:8082".parse().unwrap()); let required_set = vec![(self_node_id.clone(), "127.0.0.1:8081".parse().unwrap())].into_iter().collect(); adjust_connections(&self_node_id, &mut connection_data, &required_set); assert!(connection_data.nodes.is_empty()); + assert!(!connection_data.is_isolated); } #[test] fn adjust_connections_does_not_connects_to_self() { let self_node_id = Random.generate().unwrap().public().clone(); - let mut connection_data: ClusterConnectionsData = Default::default(); + let mut connection_data = default_connection_data(); let required_set = vec![(self_node_id.clone(), "127.0.0.1:8081".parse().unwrap())].into_iter().collect(); adjust_connections(&self_node_id, &mut connection_data, &required_set); assert!(connection_data.nodes.is_empty()); + assert!(!connection_data.is_isolated); } #[test] @@ -315,7 +333,7 @@ mod tests { let migration_node_id = Random.generate().unwrap().public().clone(); let new_node_id = Random.generate().unwrap().public().clone(); - let mut connections_data: ClusterConnectionsData = Default::default(); + let mut connections_data = default_connection_data(); connections.maintain(ConnectionsAction::ConnectToCurrentSet, &mut connections_data, &KeyServerSetSnapshot { current_set: vec![(self_node_id.clone(), "127.0.0.1:8081".parse().unwrap()), (current_node_id.clone(), "127.0.0.1:8082".parse().unwrap())].into_iter().collect(), @@ -337,7 +355,7 @@ mod tests { let migration_node_id = Random.generate().unwrap().public().clone(); let new_node_id = Random.generate().unwrap().public().clone(); - let mut connections_data: ClusterConnectionsData = Default::default(); + let mut connections_data = default_connection_data(); connections.maintain(ConnectionsAction::ConnectToMigrationSet, &mut connections_data, &KeyServerSetSnapshot { current_set: vec![(current_node_id.clone(), "127.0.0.1:8082".parse().unwrap())].into_iter().collect(), new_set: vec![(new_node_id.clone(), "127.0.0.1:8083".parse().unwrap())].into_iter().collect(), @@ -354,7 +372,7 @@ mod tests { #[test] fn simple_connections_trigger_only_maintains_connections() { - let key_server_set = Arc::new(MapKeyServerSet::new(Default::default())); + let key_server_set = Arc::new(MapKeyServerSet::new(false, Default::default())); let self_key_pair = Arc::new(PlainNodeKeyPair::new(Random.generate().unwrap())); let mut trigger = SimpleConnectionTrigger::new(key_server_set, self_key_pair, None); assert_eq!(trigger.on_maintain(), Some(Maintain::Connections)); diff --git a/secret_store/src/key_server_cluster/connection_trigger_with_migration.rs b/secret_store/src/key_server_cluster/connection_trigger_with_migration.rs index 40a4b5028eb7dee1ac525923d1ed189cd3bf96c9..cc8db3e6652bf1fd057e71082da75d1b6f2e7d6b 100644 --- a/secret_store/src/key_server_cluster/connection_trigger_with_migration.rs +++ b/secret_store/src/key_server_cluster/connection_trigger_with_migration.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/io/deadline.rs b/secret_store/src/key_server_cluster/io/deadline.rs index 1088f4f33722004ce774e6b649a9509e7046dbc9..94a189522799f30a5926effefe8551eabe912b33 100644 --- a/secret_store/src/key_server_cluster/io/deadline.rs +++ b/secret_store/src/key_server_cluster/io/deadline.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/io/handshake.rs b/secret_store/src/key_server_cluster/io/handshake.rs index af642956322cfc6b544b451317442de8d68e4a87..5081004d0b3118075e31cd1a066227213018e4f2 100644 --- a/secret_store/src/key_server_cluster/io/handshake.rs +++ b/secret_store/src/key_server_cluster/io/handshake.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/io/message.rs b/secret_store/src/key_server_cluster/io/message.rs index 9925b789d24c76a32e560218cd4be4cc37baba2d..e8e01a91f52a16a83b217d4ff2e601600a521a6e 100644 --- a/secret_store/src/key_server_cluster/io/message.rs +++ b/secret_store/src/key_server_cluster/io/message.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/io/mod.rs b/secret_store/src/key_server_cluster/io/mod.rs index dfea336830fd487e2781047a0da0d0fdbf73abaf..02adb72ad77f152a62d5e122e81c0beb6b39419b 100644 --- a/secret_store/src/key_server_cluster/io/mod.rs +++ b/secret_store/src/key_server_cluster/io/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/io/read_header.rs b/secret_store/src/key_server_cluster/io/read_header.rs index 2fd8960e30fdf7be9c4cfda9c6cfb025c1a814a6..803e01b95b4ae972f9896b7988b05633c3cd749c 100644 --- a/secret_store/src/key_server_cluster/io/read_header.rs +++ b/secret_store/src/key_server_cluster/io/read_header.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/io/read_message.rs b/secret_store/src/key_server_cluster/io/read_message.rs index 1ffb98792a50d7e88c276226e19e157c3d0cabc7..b1d0395d57acce4e9d34039e6b86e3663134c2ba 100644 --- a/secret_store/src/key_server_cluster/io/read_message.rs +++ b/secret_store/src/key_server_cluster/io/read_message.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/io/read_payload.rs b/secret_store/src/key_server_cluster/io/read_payload.rs index 1246092e90a1db0b6090eb24ed3b56c503a8e5e8..da4f4d3c019997f11850edea0c51d459545f2a27 100644 --- a/secret_store/src/key_server_cluster/io/read_payload.rs +++ b/secret_store/src/key_server_cluster/io/read_payload.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/io/shared_tcp_stream.rs b/secret_store/src/key_server_cluster/io/shared_tcp_stream.rs index a847b14280ce7c8a692d75d02fdf4e7606359041..64afbbe82f37b29918af1e9e1beb4b5413b6d71b 100644 --- a/secret_store/src/key_server_cluster/io/shared_tcp_stream.rs +++ b/secret_store/src/key_server_cluster/io/shared_tcp_stream.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/io/write_message.rs b/secret_store/src/key_server_cluster/io/write_message.rs index 8a89cf4552a4e2fa547cc3164e6fca894bff3530..d337a3705a01a76376f35ef5a5b06379da8eb86d 100644 --- a/secret_store/src/key_server_cluster/io/write_message.rs +++ b/secret_store/src/key_server_cluster/io/write_message.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/jobs/consensus_session.rs b/secret_store/src/key_server_cluster/jobs/consensus_session.rs index 5d780a48ebf91f70c567a02c2218772cab032cab..6d2866750ee1d5e03ec2400ae91612bbc06dcb0a 100644 --- a/secret_store/src/key_server_cluster/jobs/consensus_session.rs +++ b/secret_store/src/key_server_cluster/jobs/consensus_session.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/jobs/decryption_job.rs b/secret_store/src/key_server_cluster/jobs/decryption_job.rs index 2c11fe0ab365889d16edb4b5dee6e4b791405f9f..debffa25e0a4b4f075541e4da22ab798b8136446 100644 --- a/secret_store/src/key_server_cluster/jobs/decryption_job.rs +++ b/secret_store/src/key_server_cluster/jobs/decryption_job.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/jobs/dummy_job.rs b/secret_store/src/key_server_cluster/jobs/dummy_job.rs index 3e84c0d49d2f9f3bb5464a8188a4f6d09f74ae48..f7e771d1558ea7ad8f5bfa58f0fbe9d0a4aee608 100644 --- a/secret_store/src/key_server_cluster/jobs/dummy_job.rs +++ b/secret_store/src/key_server_cluster/jobs/dummy_job.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/jobs/job_session.rs b/secret_store/src/key_server_cluster/jobs/job_session.rs index d3a765bf5bc15761a6ce6677c965d22386663b97..ab0300db3618613e36b1ff9af8e7d2db3b3130fb 100644 --- a/secret_store/src/key_server_cluster/jobs/job_session.rs +++ b/secret_store/src/key_server_cluster/jobs/job_session.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/jobs/key_access_job.rs b/secret_store/src/key_server_cluster/jobs/key_access_job.rs index a47385b5aeff6b16823c706024526af1c89c466e..7ded90afabb3b10b255a43c8f50aa9e6f435d1d0 100644 --- a/secret_store/src/key_server_cluster/jobs/key_access_job.rs +++ b/secret_store/src/key_server_cluster/jobs/key_access_job.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -79,7 +79,6 @@ impl JobExecutor for KeyAccessJob { self.requester = Some(partial_request.clone()); self.acl_storage.check(partial_request.address(&self.id).map_err(Error::InsufficientRequesterData)?, &self.id) - .map_err(|_| Error::AccessDenied) .map(|is_confirmed| if is_confirmed { JobPartialRequestAction::Respond(true) } else { JobPartialRequestAction::Reject(false) }) } diff --git a/secret_store/src/key_server_cluster/jobs/mod.rs b/secret_store/src/key_server_cluster/jobs/mod.rs index 817f09b71dde2bd413d79f3cc8a768ecd04e6fd0..75d07e313b790c6198ef489bcc60515fbd5f43d4 100644 --- a/secret_store/src/key_server_cluster/jobs/mod.rs +++ b/secret_store/src/key_server_cluster/jobs/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/jobs/servers_set_change_access_job.rs b/secret_store/src/key_server_cluster/jobs/servers_set_change_access_job.rs index 1d1628692695130fa63567c2096645e5b8065669..6c142d2a2f84f7e3e2627d48607113b0d371d99a 100644 --- a/secret_store/src/key_server_cluster/jobs/servers_set_change_access_job.rs +++ b/secret_store/src/key_server_cluster/jobs/servers_set_change_access_job.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/jobs/signing_job_ecdsa.rs b/secret_store/src/key_server_cluster/jobs/signing_job_ecdsa.rs index 8f4ab1d68eb001be2772d8695de18c232bf205bf..6349c2e7db493a238c9d12bccc3518331e2bb4db 100644 --- a/secret_store/src/key_server_cluster/jobs/signing_job_ecdsa.rs +++ b/secret_store/src/key_server_cluster/jobs/signing_job_ecdsa.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/jobs/signing_job_schnorr.rs b/secret_store/src/key_server_cluster/jobs/signing_job_schnorr.rs index 54225a6cf574528b5328b57379c2f7385653f1e5..4d1a0e7d9092e12c289b60db44d2e0b8202ad6fa 100644 --- a/secret_store/src/key_server_cluster/jobs/signing_job_schnorr.rs +++ b/secret_store/src/key_server_cluster/jobs/signing_job_schnorr.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -148,4 +148,4 @@ impl JobExecutor for SchnorrSigningJob { Ok((signature_c, signature_s)) } -} \ No newline at end of file +} diff --git a/secret_store/src/key_server_cluster/jobs/unknown_sessions_job.rs b/secret_store/src/key_server_cluster/jobs/unknown_sessions_job.rs index 13f2f8b8bb46ee2ae698154a984a28e6f40d77ce..908afa1ecc6ec1bfd11b66e2bfba15a84d577569 100644 --- a/secret_store/src/key_server_cluster/jobs/unknown_sessions_job.rs +++ b/secret_store/src/key_server_cluster/jobs/unknown_sessions_job.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/math.rs b/secret_store/src/key_server_cluster/math.rs index ef6d88f67ce8737062bd03985645d9f3d8456b12..7fbe48574b18d43c139f5a57118fdc161ad1ede8 100644 --- a/secret_store/src/key_server_cluster/math.rs +++ b/secret_store/src/key_server_cluster/math.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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/secret_store/src/key_server_cluster/message.rs b/secret_store/src/key_server_cluster/message.rs index cc49e56fdb54bb06a951a183efa182e3b7b3f894..1bc487eb78f2090b943cf1255e353261c493d367 100644 --- a/secret_store/src/key_server_cluster/message.rs +++ b/secret_store/src/key_server_cluster/message.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -429,6 +429,8 @@ pub struct InitializeConsensusSessionWithServersSet { pub struct InitializeConsensusSessionOfShareAdd { /// Key version. pub version: SerializableH256, + /// Nodes that have reported version ownership. + pub version_holders: BTreeSet, /// threshold+1 nodes from old_nodes_set selected for shares redistribution. pub consensus_group: BTreeSet, /// Old nodes set: all non-isolated owners of selected key share version. @@ -876,6 +878,8 @@ pub struct InitializeShareChangeSession { pub key_id: MessageSessionId, /// Key vesion to use in ShareAdd session. pub version: SerializableH256, + /// Nodes that have confirmed version ownership. + pub version_holders: BTreeSet, /// Master node. pub master_node_id: MessageNodeId, /// Consensus group to use in ShareAdd session. @@ -1039,6 +1043,16 @@ pub struct KeyVersionsError { pub session_nonce: u64, /// Error message. pub error: Error, + /// Continue action from failed node (if any). This field is oly filled + /// when error has occured when trying to compute result on master node. + pub continue_with: Option, +} + +/// Key version continue action from failed node. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum FailedKeyVersionContinueAction { + /// Decryption session: origin + requester. + Decrypt(Option, SerializableAddress), } impl Message { @@ -1059,6 +1073,7 @@ impl Message { _ => false }, Message::KeyVersionNegotiation(KeyVersionNegotiationMessage::RequestKeyVersions(_)) => true, + Message::KeyVersionNegotiation(KeyVersionNegotiationMessage::KeyVersionsError(ref msg)) if msg.continue_with.is_some() => true, Message::ShareAdd(ShareAddMessage::ShareAddConsensusMessage(ref msg)) => match msg.message { ConsensusMessageOfShareAdd::InitializeConsensusSession(_) => true, _ => false diff --git a/secret_store/src/key_server_cluster/mod.rs b/secret_store/src/key_server_cluster/mod.rs index d5ac85b3dea6d313f305f66b0422403083a8f680..018d70d305feb04d67a9c7c2518baa8381b65546 100644 --- a/secret_store/src/key_server_cluster/mod.rs +++ b/secret_store/src/key_server_cluster/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/net/accept_connection.rs b/secret_store/src/key_server_cluster/net/accept_connection.rs index d85e492dd7b9f0a608f795b40efc56d690fa838c..3565ea3d0fd81bbab49833ccbb3dc63c09e1ece7 100644 --- a/secret_store/src/key_server_cluster/net/accept_connection.rs +++ b/secret_store/src/key_server_cluster/net/accept_connection.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/net/connect.rs b/secret_store/src/key_server_cluster/net/connect.rs index 7515494e44992bf151ba9090aeadfdf901463c7c..8b93479f97d81ac65fb5d84ddaed2b06f9986018 100644 --- a/secret_store/src/key_server_cluster/net/connect.rs +++ b/secret_store/src/key_server_cluster/net/connect.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/net/connection.rs b/secret_store/src/key_server_cluster/net/connection.rs index 577f5828f659205e213c793229ee250f5d7822d6..7776e97a74e9d9f1383ac845d339966e388e17ce 100644 --- a/secret_store/src/key_server_cluster/net/connection.rs +++ b/secret_store/src/key_server_cluster/net/connection.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/net/mod.rs b/secret_store/src/key_server_cluster/net/mod.rs index 6abf83ceb8e1a4323588e224cac539af7539cfdd..e76f4f476c698427445a589a017360eb51306e0e 100644 --- a/secret_store/src/key_server_cluster/net/mod.rs +++ b/secret_store/src/key_server_cluster/net/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_set.rs b/secret_store/src/key_server_set.rs index 8a0d786af988172988e6c23c70b318571960388f..7bae27017a399c7172c7086652e7596c7b2fa4a3 100644 --- a/secret_store/src/key_server_set.rs +++ b/secret_store/src/key_server_set.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -19,16 +19,13 @@ use std::net::SocketAddr; use std::collections::{BTreeMap, HashSet}; use std::time::Duration; use parking_lot::Mutex; -use ethcore::client::{Client, BlockChainClient, BlockId, ChainNotify, ChainRoute, CallContract, RegistryInfo}; -use ethcore::filter::Filter; +use ethcore::client::{Client, BlockChainClient, BlockId, ChainNotify, ChainRoute, CallContract}; use ethkey::public_to_address; -use hash::keccak; use ethereum_types::{H256, Address}; use bytes::Bytes; use types::{Error, Public, NodeAddress, NodeId}; use trusted_client::TrustedClient; -use helpers::{get_confirmed_block_hash, REQUEST_CONFIRMATIONS_REQUIRED}; -use {NodeKeyPair}; +use {NodeKeyPair, ContractAddress}; use_contract!(key_server, "KeyServerSet", "res/key_server_set.json"); @@ -39,22 +36,6 @@ const MIGRATION_CONFIRMATIONS_REQUIRED: u64 = 5; /// Number of blocks before the same-migration transaction (be it start or confirmation) will be retried. const TRANSACTION_RETRY_INTERVAL_BLOCKS: u64 = 30; -/// Key server has been added to the set. -const ADDED_EVENT_NAME: &'static [u8] = &*b"KeyServerAdded(address)"; -/// Key server has been removed from the set. -const REMOVED_EVENT_NAME: &'static [u8] = &*b"KeyServerRemoved(address)"; -/// Migration has started. -const MIGRATION_STARTED_EVENT_NAME: &'static [u8] = &*b"MigrationStarted()"; -/// Migration has completed. -const MIGRATION_COMPLETED_EVENT_NAME: &'static [u8] = &*b"MigrationCompleted()"; - -lazy_static! { - static ref ADDED_EVENT_NAME_HASH: H256 = keccak(ADDED_EVENT_NAME); - static ref REMOVED_EVENT_NAME_HASH: H256 = keccak(REMOVED_EVENT_NAME); - static ref MIGRATION_STARTED_EVENT_NAME_HASH: H256 = keccak(MIGRATION_STARTED_EVENT_NAME); - static ref MIGRATION_COMPLETED_EVENT_NAME_HASH: H256 = keccak(MIGRATION_COMPLETED_EVENT_NAME); -} - #[derive(Default, Debug, Clone, PartialEq)] /// Key Server Set state. pub struct KeyServerSetSnapshot { @@ -81,6 +62,8 @@ pub struct KeyServerSetMigration { /// Key Server Set pub trait KeyServerSet: Send + Sync { + /// Is this node currently isolated from the set? + fn is_isolated(&self) -> bool; /// Get server set state. fn snapshot(&self) -> KeyServerSetSnapshot; /// Start migration. @@ -117,7 +100,9 @@ struct PreviousMigrationTransaction { struct CachedContract { /// Blockchain client. client: TrustedClient, - /// Contract address. + /// Contract address source. + contract_address_source: Option, + /// Current contract address. contract_address: Option
, /// Contract interface. contract: key_server::KeyServerSet, @@ -136,10 +121,10 @@ struct CachedContract { } impl OnChainKeyServerSet { - pub fn new(trusted_client: TrustedClient, self_key_pair: Arc, auto_migrate_enabled: bool, key_servers: BTreeMap) -> Result, Error> { + pub fn new(trusted_client: TrustedClient, contract_address_source: Option, self_key_pair: Arc, auto_migrate_enabled: bool, key_servers: BTreeMap) -> Result, Error> { let client = trusted_client.get_untrusted(); let key_server_set = Arc::new(OnChainKeyServerSet { - contract: Mutex::new(CachedContract::new(trusted_client, self_key_pair, auto_migrate_enabled, key_servers)?), + contract: Mutex::new(CachedContract::new(trusted_client, contract_address_source, self_key_pair, auto_migrate_enabled, key_servers)?), }); client .ok_or_else(|| Error::Internal("Constructing OnChainKeyServerSet without active Client".into()))? @@ -149,6 +134,10 @@ impl OnChainKeyServerSet { } impl KeyServerSet for OnChainKeyServerSet { + fn is_isolated(&self) -> bool { + self.contract.lock().is_isolated() + } + fn snapshot(&self) -> KeyServerSetSnapshot { self.contract.lock().snapshot() } @@ -244,16 +233,21 @@ impl ) -> Result, String>> KeyServerSubset for NewKeySe } impl CachedContract { - pub fn new(client: TrustedClient, self_key_pair: Arc, auto_migrate_enabled: bool, key_servers: BTreeMap) -> Result { - let server_set = key_servers.into_iter() - .map(|(p, addr)| { - let addr = format!("{}:{}", addr.address, addr.port).parse() - .map_err(|err| Error::Internal(format!("error parsing node address: {}", err)))?; - Ok((p, addr)) - }) - .collect::, Error>>()?; - Ok(CachedContract { + pub fn new(client: TrustedClient, contract_address_source: Option, self_key_pair: Arc, auto_migrate_enabled: bool, key_servers: BTreeMap) -> Result { + let server_set = match contract_address_source.is_none() { + true => key_servers.into_iter() + .map(|(p, addr)| { + let addr = format!("{}:{}", addr.address, addr.port).parse() + .map_err(|err| Error::Internal(format!("error parsing node address: {}", err)))?; + Ok((p, addr)) + }) + .collect::, Error>>()?, + false => Default::default(), + }; + + let mut contract = CachedContract { client: client, + contract_address_source: contract_address_source, contract_address: None, contract: key_server::KeyServerSet::default(), auto_migrate_enabled: auto_migrate_enabled, @@ -266,19 +260,46 @@ impl CachedContract { ..Default::default() }, self_key_pair: self_key_pair, - }) + }; + contract.update_contract_address(); + + Ok(contract) + } + + pub fn update_contract_address(&mut self) { + if let Some(ref contract_address_source) = self.contract_address_source { + let contract_address = self.client.read_contract_address(KEY_SERVER_SET_CONTRACT_REGISTRY_NAME.into(), contract_address_source); + if contract_address != self.contract_address { + trace!(target: "secretstore", "{}: Configuring for key server set contract from address {:?}", + self.self_key_pair.public(), contract_address); + + self.contract_address = contract_address; + } + } } pub fn update(&mut self, enacted: Vec, retracted: Vec) { + // no need to update when servers set is hardcoded + if self.contract_address_source.is_none() { + return; + } + if let Some(client) = self.client.get() { - // read new snapshot from registry (if something has changed) - self.read_from_registry_if_required(&*client, enacted, retracted); + // read new snapshot from reqistry (if something has chnaged) + if !enacted.is_empty() || !retracted.is_empty() { + self.update_contract_address(); + self.read_from_registry(&*client); + } // update number of confirmations (if there's future new set) self.update_number_of_confirmations_if_required(&*client); } } + fn is_isolated(&self) -> bool { + !self.snapshot.current_set.contains_key(self.self_key_pair.public()) + } + fn snapshot(&self) -> KeyServerSetSnapshot { self.snapshot.clone() } @@ -295,12 +316,11 @@ impl CachedContract { let transaction_data = self.contract.functions().start_migration().input(migration_id); // send transaction - if let Err(error) = self.client.transact_contract(*contract_address, transaction_data) { - warn!(target: "secretstore_net", "{}: failed to submit auto-migration start transaction: {}", - self.self_key_pair.public(), error); - } else { - trace!(target: "secretstore_net", "{}: sent auto-migration start transaction", - self.self_key_pair.public()); + match self.client.transact_contract(*contract_address, transaction_data) { + Ok(_) => trace!(target: "secretstore_net", "{}: sent auto-migration start transaction", + self.self_key_pair.public()), + Err(error) => warn!(target: "secretstore_net", "{}: failed to submit auto-migration start transaction: {}", + self.self_key_pair.public(), error), } } } @@ -317,55 +337,16 @@ impl CachedContract { let transaction_data = self.contract.functions().confirm_migration().input(migration_id); // send transaction - if let Err(error) = self.client.transact_contract(contract_address, transaction_data) { - warn!(target: "secretstore_net", "{}: failed to submit auto-migration confirmation transaction: {}", - self.self_key_pair.public(), error); - } else { - trace!(target: "secretstore_net", "{}: sent auto-migration confirm transaction", - self.self_key_pair.public()); + match self.client.transact_contract(contract_address, transaction_data) { + Ok(_) => trace!(target: "secretstore_net", "{}: sent auto-migration confirm transaction", + self.self_key_pair.public()), + Err(error) => warn!(target: "secretstore_net", "{}: failed to submit auto-migration confirmation transaction: {}", + self.self_key_pair.public(), error), } } } - fn read_from_registry_if_required(&mut self, client: &Client, enacted: Vec, retracted: Vec) { - // read new contract from registry - let new_contract_addr = get_confirmed_block_hash(&*client, REQUEST_CONFIRMATIONS_REQUIRED).and_then(|block_hash| client.registry_address(KEY_SERVER_SET_CONTRACT_REGISTRY_NAME.to_owned(), BlockId::Hash(block_hash))); - - // new contract installed => read nodes set from the contract - if self.contract_address.as_ref() != new_contract_addr.as_ref() { - self.read_from_registry(&*client, new_contract_addr); - return; - } - - // check for contract events - let is_set_changed = self.contract_address.is_some() && enacted.iter() - .chain(retracted.iter()) - .any(|block_hash| !client.logs(Filter { - from_block: BlockId::Hash(block_hash.clone()), - to_block: BlockId::Hash(block_hash.clone()), - address: self.contract_address.map(|address| vec![address]), - topics: vec![ - Some(vec![*ADDED_EVENT_NAME_HASH, *REMOVED_EVENT_NAME_HASH, - *MIGRATION_STARTED_EVENT_NAME_HASH, *MIGRATION_COMPLETED_EVENT_NAME_HASH]), - None, - None, - None, - ], - limit: Some(1), - }).is_empty()); - - // to simplify processing - just re-read the whole nodes set from the contract - if is_set_changed { - self.read_from_registry(&*client, new_contract_addr); - } - } - - fn read_from_registry(&mut self, client: &Client, new_contract_address: Option
) { - if let Some(ref contract_addr) = new_contract_address { - trace!(target: "secretstore", "Configuring for key server set contract from {}", contract_addr); - } - self.contract_address = new_contract_address; - + fn read_from_registry(&mut self, client: &Client) { let contract_address = match self.contract_address { Some(contract_address) => contract_address, None => { @@ -505,7 +486,7 @@ fn update_future_set(future_new_set: &mut Option, new_snapshot: &m return; } - // new no migration is required => no need to delay visibility + // no migration is required => no need to delay visibility if !is_migration_required(&new_snapshot.current_set, &new_snapshot.new_set) { *future_new_set = None; return; @@ -602,18 +583,24 @@ pub mod tests { #[derive(Default)] pub struct MapKeyServerSet { + is_isolated: bool, nodes: BTreeMap, } impl MapKeyServerSet { - pub fn new(nodes: BTreeMap) -> Self { + pub fn new(is_isolated: bool, nodes: BTreeMap) -> Self { MapKeyServerSet { + is_isolated: is_isolated, nodes: nodes, } } } impl KeyServerSet for MapKeyServerSet { + fn is_isolated(&self) -> bool { + self.is_isolated + } + fn snapshot(&self) -> KeyServerSetSnapshot { KeyServerSetSnapshot { current_set: self.nodes.clone(), diff --git a/secret_store/src/key_storage.rs b/secret_store/src/key_storage.rs index 848e6bf2a522f74844458704698cbd9780db664b..f19630c5c6ef2a4506d6addf2707110fff12211f 100644 --- a/secret_store/src/key_storage.rs +++ b/secret_store/src/key_storage.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -348,7 +348,6 @@ impl DocumentKeyShareVersion { } } - /// Calculate hash of given version data. pub fn data_hash<'a, I>(id_numbers: I) -> H256 where I: Iterator { let mut nodes_keccak = Keccak::new_keccak256(); @@ -467,7 +466,6 @@ pub mod tests { #[test] fn persistent_key_storage() { let tempdir = TempDir::new("").unwrap(); - let key1 = ServerKeyId::from(1); let value1 = DocumentKeyShare { author: Default::default(), diff --git a/secret_store/src/lib.rs b/secret_store/src/lib.rs index 80b15318a9f4d166fe96c911db0e0306cdf4cbad..b58534b3e5990de5ad0539e9e104c51c1fbf4f69 100644 --- a/secret_store/src/lib.rs +++ b/secret_store/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -17,8 +17,8 @@ extern crate byteorder; extern crate ethabi; extern crate ethcore; -extern crate ethcore_bytes as bytes; -extern crate ethcore_crypto as crypto; +extern crate parity_bytes as bytes; +extern crate parity_crypto as crypto; extern crate ethcore_logger as logger; extern crate ethcore_sync as sync; extern crate ethcore_transaction as transaction; @@ -82,16 +82,15 @@ pub use traits::{NodeKeyPair, KeyServer}; pub use self::node_key_pair::{PlainNodeKeyPair, KeyStoreNodeKeyPair}; /// Start new key server instance -pub fn start(client: Arc, sync: Arc, miner: Arc, self_key_pair: Arc, config: ServiceConfiguration, db: Arc) -> Result, Error> { +pub fn start(client: Arc, sync: Arc, miner: Arc, self_key_pair: Arc, mut config: ServiceConfiguration, db: Arc) -> Result, Error> { let trusted_client = trusted_client::TrustedClient::new(self_key_pair.clone(), client.clone(), sync, miner); - let acl_storage: Arc = if config.acl_check_enabled { - acl_storage::OnChainAclStorage::new(trusted_client.clone())? - } else { - Arc::new(acl_storage::DummyAclStorage::default()) - }; - - let key_server_set = key_server_set::OnChainKeyServerSet::new(trusted_client.clone(), self_key_pair.clone(), - config.cluster_config.auto_migrate_enabled, config.cluster_config.nodes.clone())?; + let acl_storage: Arc = match config.acl_check_contract_address.take() { + Some(acl_check_contract_address) => acl_storage::OnChainAclStorage::new(trusted_client.clone(), acl_check_contract_address)?, + None => Arc::new(acl_storage::DummyAclStorage::default()), + }; + + let key_server_set = key_server_set::OnChainKeyServerSet::new(trusted_client.clone(), config.cluster_config.key_server_set_contract_address.take(), + self_key_pair.clone(), config.cluster_config.auto_migrate_enabled, config.cluster_config.nodes.clone())?; let key_storage = Arc::new(key_storage::PersistentKeyStorage::new(db)?); let key_server = Arc::new(key_server::KeyServerImpl::new(&config.cluster_config, key_server_set.clone(), self_key_pair.clone(), acl_storage.clone(), key_storage.clone())?); let cluster = key_server.cluster(); diff --git a/secret_store/src/listener/http_listener.rs b/secret_store/src/listener/http_listener.rs index 074052fae476b3355681b8ee0825d63ffb709a88..5aa82a1cbda014b31a64e676823db655cee1dcca 100644 --- a/secret_store/src/listener/http_listener.rs +++ b/secret_store/src/listener/http_listener.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/listener/mod.rs b/secret_store/src/listener/mod.rs index 0d1f3f2675332b170620de8132707dd9cec88b38..8837e7ffd634c172179bead900593f59b8e4c9ff 100644 --- a/secret_store/src/listener/mod.rs +++ b/secret_store/src/listener/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/listener/service_contract.rs b/secret_store/src/listener/service_contract.rs index eac3cfa9dad944d857dfd1c33493a5e76c89a83d..daf70cd6488365bdaf2ea7d75c5f253d9ed289c9 100644 --- a/secret_store/src/listener/service_contract.rs +++ b/secret_store/src/listener/service_contract.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -18,7 +18,7 @@ use std::sync::Arc; use parking_lot::RwLock; use ethabi::RawLog; use ethcore::filter::Filter; -use ethcore::client::{Client, BlockChainClient, BlockId, RegistryInfo, CallContract}; +use ethcore::client::{Client, BlockChainClient, BlockId, CallContract}; use ethkey::{Public, public_to_address}; use hash::keccak; use bytes::Bytes; @@ -99,8 +99,8 @@ pub struct OnChainServiceContract { self_key_pair: Arc, /// Contract registry name (if any). name: String, - /// Contract address. - address: ContractAddress, + /// Contract address source. + address_source: ContractAddress, /// Contract. contract: service::Service, /// Contract. @@ -109,8 +109,8 @@ pub struct OnChainServiceContract { /// On-chain service contract data. struct ServiceData { - /// Actual contract address. - pub contract_address: Address, + /// Current contract address. + pub contract_address: Option
, /// Last block we have read logs from. pub last_log_block: Option, } @@ -136,38 +136,26 @@ struct DocumentKeyShadowRetrievalService; impl OnChainServiceContract { /// Create new on-chain service contract. - pub fn new(mask: ApiMask, client: TrustedClient, name: String, address: ContractAddress, self_key_pair: Arc) -> Self { - let contract_addr = match address { - ContractAddress::Registry => client.get().and_then(|c| c.registry_address(name.clone(), BlockId::Latest) - .map(|address| { - trace!(target: "secretstore", "{}: installing {} service contract from address {}", - self_key_pair.public(), name, address); - address - })) - .unwrap_or_default(), - ContractAddress::Address(ref address) => { - trace!(target: "secretstore", "{}: installing service contract from address {}", - self_key_pair.public(), address); - address.clone() - }, - }; - - OnChainServiceContract { + pub fn new(mask: ApiMask, client: TrustedClient, name: String, address_source: ContractAddress, self_key_pair: Arc) -> Self { + let contract = OnChainServiceContract { mask: mask, client: client, self_key_pair: self_key_pair, name: name, - address: address, + address_source: address_source, contract: service::Service::default(), data: RwLock::new(ServiceData { - contract_address: contract_addr, + contract_address: None, last_log_block: None, }), - } + }; + + contract.update_contract_address(); + contract } /// Send transaction to the service contract. - fn send_contract_transaction(&self, origin: &Address, server_key_id: &ServerKeyId, is_response_required: C, prepare_tx: P) -> Result<(), String> + fn send_contract_transaction(&self, tx_name: &str, origin: &Address, server_key_id: &ServerKeyId, is_response_required: C, prepare_tx: P) -> Result<(), String> where C: FnOnce(&Client, &Address, &service::Service, &ServerKeyId, &Address) -> bool, P: FnOnce(&Client, &Address, &service::Service) -> Result { // only publish if contract address is set && client is online @@ -193,6 +181,9 @@ impl OnChainServiceContract { transaction_data ).map_err(|e| format!("{}", e))?; + trace!(target: "secretstore", "{}: transaction {} sent to service contract", + self.self_key_pair.public(), tx_name); + Ok(()) } @@ -228,26 +219,25 @@ impl OnChainServiceContract { .ok() .unwrap_or_else(|| Box::new(::std::iter::empty())) } + + /// Update service contract address. + fn update_contract_address(&self) -> bool { + let contract_address = self.client.read_contract_address(self.name.clone(), &self.address_source); + let mut data = self.data.write(); + if contract_address != data.contract_address { + trace!(target: "secretstore", "{}: installing {} service contract from address {:?}", + self.self_key_pair.public(), self.name, contract_address); + + data.contract_address = contract_address; + } + + data.contract_address.is_some() + } } impl ServiceContract for OnChainServiceContract { fn update(&self) -> bool { - if let &ContractAddress::Registry = &self.address { - if let Some(client) = self.client.get() { - if let Some(block_hash) = get_confirmed_block_hash(&*client, REQUEST_CONFIRMATIONS_REQUIRED) { - // update contract address from registry - let service_contract_addr = client.registry_address(self.name.clone(), BlockId::Hash(block_hash)).unwrap_or_default(); - if self.data.read().contract_address != service_contract_addr { - trace!(target: "secretstore", "{}: installing {} service contract from address {}", - self.self_key_pair.public(), self.name, service_contract_addr); - self.data.write().contract_address = service_contract_addr; - } - } - } - } - - self.data.read().contract_address != Default::default() - && self.client.get().is_some() + self.update_contract_address() && self.client.get().is_some() } fn read_logs(&self) -> Box> { @@ -263,7 +253,10 @@ impl ServiceContract for OnChainServiceContract { // prepare range of blocks to read logs from let (address, first_block, last_block) = { let mut data = self.data.write(); - let address = data.contract_address; + let address = match data.contract_address { + Some(address) => address, + None => return Box::new(::std::iter::empty()), // no contract installed + }; let confirmed_block = match get_confirmed_block_hash(&*client, REQUEST_CONFIRMATIONS_REQUIRED) { Some(confirmed_block) => confirmed_block, None => return Box::new(::std::iter::empty()), // no block with enough confirmations @@ -326,31 +319,31 @@ impl ServiceContract for OnChainServiceContract { // we only need requests that are here for more than REQUEST_CONFIRMATIONS_REQUIRED blocks // => we're reading from Latest - (REQUEST_CONFIRMATIONS_REQUIRED + 1) block let data = self.data.read(); - match data.contract_address == Default::default() { - true => Box::new(::std::iter::empty()), - false => get_confirmed_block_hash(&*client, REQUEST_CONFIRMATIONS_REQUIRED + 1) + match data.contract_address { + None => Box::new(::std::iter::empty()), + Some(contract_address) => get_confirmed_block_hash(&*client, REQUEST_CONFIRMATIONS_REQUIRED + 1) .map(|b| { let block = BlockId::Hash(b); let iter = match self.mask.server_key_generation_requests { - true => Box::new(self.create_pending_requests_iterator(client.clone(), &data.contract_address, &block, + true => Box::new(self.create_pending_requests_iterator(client.clone(), &contract_address, &block, &ServerKeyGenerationService::read_pending_requests_count, &ServerKeyGenerationService::read_pending_request)) as Box>, false => Box::new(::std::iter::empty()), }; let iter = match self.mask.server_key_retrieval_requests { - true => Box::new(iter.chain(self.create_pending_requests_iterator(client.clone(), &data.contract_address, &block, + true => Box::new(iter.chain(self.create_pending_requests_iterator(client.clone(), &contract_address, &block, &ServerKeyRetrievalService::read_pending_requests_count, &ServerKeyRetrievalService::read_pending_request))), false => iter, }; let iter = match self.mask.document_key_store_requests { - true => Box::new(iter.chain(self.create_pending_requests_iterator(client.clone(), &data.contract_address, &block, + true => Box::new(iter.chain(self.create_pending_requests_iterator(client.clone(), &contract_address, &block, &DocumentKeyStoreService::read_pending_requests_count, &DocumentKeyStoreService::read_pending_request))), false => iter, }; let iter = match self.mask.document_key_shadow_retrieval_requests { - true => Box::new(iter.chain(self.create_pending_requests_iterator(client, &data.contract_address, &block, + true => Box::new(iter.chain(self.create_pending_requests_iterator(client, &contract_address, &block, &DocumentKeyShadowRetrievalService::read_pending_requests_count, &DocumentKeyShadowRetrievalService::read_pending_request))), false => iter @@ -363,63 +356,59 @@ impl ServiceContract for OnChainServiceContract { } fn publish_generated_server_key(&self, origin: &Address, server_key_id: &ServerKeyId, server_key: Public) -> Result<(), String> { - self.send_contract_transaction(origin, server_key_id, ServerKeyGenerationService::is_response_required, |_, _, service| - Ok(ServerKeyGenerationService::prepare_pubish_tx_data(service, server_key_id, &server_key)) - ) + self.send_contract_transaction("publish_generated_server_key", origin, server_key_id, ServerKeyGenerationService::is_response_required, + |_, _, service| Ok(ServerKeyGenerationService::prepare_pubish_tx_data(service, server_key_id, &server_key))) } fn publish_server_key_generation_error(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { - self.send_contract_transaction(origin, server_key_id, ServerKeyGenerationService::is_response_required, |_, _, service| - Ok(ServerKeyGenerationService::prepare_error_tx_data(service, server_key_id)) - ) + self.send_contract_transaction("publish_server_key_generation_error", origin, server_key_id, ServerKeyGenerationService::is_response_required, + |_, _, service| Ok(ServerKeyGenerationService::prepare_error_tx_data(service, server_key_id))) } fn publish_retrieved_server_key(&self, origin: &Address, server_key_id: &ServerKeyId, server_key: Public, threshold: usize) -> Result<(), String> { let threshold = serialize_threshold(threshold)?; - self.send_contract_transaction(origin, server_key_id, ServerKeyRetrievalService::is_response_required, |_, _, service| - Ok(ServerKeyRetrievalService::prepare_pubish_tx_data(service, server_key_id, server_key, threshold)) - ) + self.send_contract_transaction("publish_retrieved_server_key", origin, server_key_id, ServerKeyRetrievalService::is_response_required, + |_, _, service| Ok(ServerKeyRetrievalService::prepare_pubish_tx_data(service, server_key_id, server_key, threshold))) } fn publish_server_key_retrieval_error(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { - self.send_contract_transaction(origin, server_key_id, ServerKeyRetrievalService::is_response_required, |_, _, service| - Ok(ServerKeyRetrievalService::prepare_error_tx_data(service, server_key_id)) - ) + self.send_contract_transaction("publish_server_key_retrieval_error", origin, server_key_id, ServerKeyRetrievalService::is_response_required, + |_, _, service| Ok(ServerKeyRetrievalService::prepare_error_tx_data(service, server_key_id))) } fn publish_stored_document_key(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { - self.send_contract_transaction(origin, server_key_id, DocumentKeyStoreService::is_response_required, |_, _, service| - Ok(DocumentKeyStoreService::prepare_pubish_tx_data(service, server_key_id)) - ) + self.send_contract_transaction("publish_stored_document_key", origin, server_key_id, DocumentKeyStoreService::is_response_required, + |_, _, service| Ok(DocumentKeyStoreService::prepare_pubish_tx_data(service, server_key_id))) } fn publish_document_key_store_error(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { - self.send_contract_transaction(origin, server_key_id, DocumentKeyStoreService::is_response_required, |_, _, service| - Ok(DocumentKeyStoreService::prepare_error_tx_data(service, server_key_id)) - ) + self.send_contract_transaction("publish_document_key_store_error", origin, server_key_id, DocumentKeyStoreService::is_response_required, + |_, _, service| Ok(DocumentKeyStoreService::prepare_error_tx_data(service, server_key_id))) } fn publish_retrieved_document_key_common(&self, origin: &Address, server_key_id: &ServerKeyId, requester: &Address, common_point: Public, threshold: usize) -> Result<(), String> { let threshold = serialize_threshold(threshold)?; - self.send_contract_transaction(origin, server_key_id, |client, contract_address, contract, server_key_id, key_server| - DocumentKeyShadowRetrievalService::is_response_required(client, contract_address, contract, server_key_id, requester, key_server), - |_, _, service| - Ok(DocumentKeyShadowRetrievalService::prepare_pubish_common_tx_data(service, server_key_id, requester, common_point, threshold)) + self.send_contract_transaction("publish_retrieved_document_key_common", origin, server_key_id, + |client, contract_address, contract, server_key_id, key_server| + DocumentKeyShadowRetrievalService::is_response_required(client, contract_address, contract, server_key_id, requester, key_server), + |_, _, service| + Ok(DocumentKeyShadowRetrievalService::prepare_pubish_common_tx_data(service, server_key_id, requester, common_point, threshold)) ) } fn publish_retrieved_document_key_personal(&self, origin: &Address, server_key_id: &ServerKeyId, requester: &Address, participants: &[Address], decrypted_secret: Public, shadow: Bytes) -> Result<(), String> { - self.send_contract_transaction(origin, server_key_id, |_, _, _, _, _| true, + self.send_contract_transaction("publish_retrieved_document_key_personal", origin, server_key_id, |_, _, _, _, _| true, move |client, address, service| DocumentKeyShadowRetrievalService::prepare_pubish_personal_tx_data(client, address, service, server_key_id, requester, participants, decrypted_secret, shadow) ) } fn publish_document_key_retrieval_error(&self, origin: &Address, server_key_id: &ServerKeyId, requester: &Address) -> Result<(), String> { - self.send_contract_transaction(origin, server_key_id, |client, contract_address, contract, server_key_id, key_server| - DocumentKeyShadowRetrievalService::is_response_required(client, contract_address, contract, server_key_id, requester, key_server), - |_, _, service| - Ok(DocumentKeyShadowRetrievalService::prepare_error_tx_data(service, server_key_id, requester)) + self.send_contract_transaction("publish_document_key_retrieval_error", origin, server_key_id, + |client, contract_address, contract, server_key_id, key_server| + DocumentKeyShadowRetrievalService::is_response_required(client, contract_address, contract, server_key_id, requester, key_server), + |_, _, service| + Ok(DocumentKeyShadowRetrievalService::prepare_error_tx_data(service, server_key_id, requester)) ) } } @@ -742,16 +731,16 @@ impl DocumentKeyShadowRetrievalService { .map(|not_confirmed| ( not_confirmed, match is_common_retrieval_completed { - true => ServiceTask::RetrieveShadowDocumentKeyCommon( + true => ServiceTask::RetrieveShadowDocumentKeyPersonal( contract_address.clone(), server_key_id, - public_to_address(&requester), + requester, ), - false => ServiceTask::RetrieveShadowDocumentKeyPersonal( + false => ServiceTask::RetrieveShadowDocumentKeyCommon( contract_address.clone(), server_key_id, - requester, - ) + public_to_address(&requester), + ), }, )) .map_err(|error| format!("{}", error)) diff --git a/secret_store/src/listener/service_contract_aggregate.rs b/secret_store/src/listener/service_contract_aggregate.rs index 9ec467fea40259999a306a8fc8e4c8342c15f1d0..cc2e97b8d424c67ed33e6ec4fff64fa32e59e1ff 100644 --- a/secret_store/src/listener/service_contract_aggregate.rs +++ b/secret_store/src/listener/service_contract_aggregate.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/listener/service_contract_listener.rs b/secret_store/src/listener/service_contract_listener.rs index 214235210fa2625fe6273f57bc1781a45485ccdf..8dc549a729fafcb4f92ced5412081b2f363d6c26 100644 --- a/secret_store/src/listener/service_contract_listener.rs +++ b/secret_store/src/listener/service_contract_listener.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -25,11 +25,13 @@ use ethkey::{Public, public_to_address}; use bytes::Bytes; use ethereum_types::{H256, U256, Address}; use key_server_set::KeyServerSet; -use key_server_cluster::{ClusterClient, ClusterSessionsListener, ClusterSession}; +use key_server_cluster::{NodeId, ClusterClient, ClusterSessionsListener, ClusterSession}; use key_server_cluster::math; use key_server_cluster::generation_session::SessionImpl as GenerationSession; use key_server_cluster::encryption_session::{check_encrypted_data, update_encrypted_data}; use key_server_cluster::decryption_session::SessionImpl as DecryptionSession; +use key_server_cluster::key_version_negotiation_session::{SessionImpl as KeyVersionNegotiationSession, + IsolatedSessionTransport as KeyVersionNegotiationTransport, FailedContinueAction}; use key_storage::KeyStorage; use acl_storage::AclStorage; use listener::service_contract::ServiceContract; @@ -138,7 +140,6 @@ impl ServiceContractListener { key_server_set: params.key_server_set, key_storage: params.key_storage, }); - data.tasks_queue.push(ServiceTask::Retry); // we are not starting thread when in test mode let service_handle = if cfg!(test) { @@ -154,11 +155,17 @@ impl ServiceContractListener { }); contract.data.cluster.add_generation_listener(contract.clone()); contract.data.cluster.add_decryption_listener(contract.clone()); + contract.data.cluster.add_key_version_negotiation_listener(contract.clone()); Ok(contract) } /// Process incoming events of service contract. fn process_service_contract_events(&self) { + // shortcut: do not process events if we're isolated from the cluster + if self.data.key_server_set.is_isolated() { + return; + } + self.data.tasks_queue.push_many(self.data.contract.read_logs() .filter_map(|task| Self::filter_task(&self.data, task))); } @@ -168,7 +175,7 @@ impl ServiceContractListener { match task { // when this node should be master of this server key generation session ServiceTask::GenerateServerKey(origin, server_key_id, author, threshold) if is_processed_by_this_key_server( - &*data.key_server_set, &*data.self_key_pair, &server_key_id) => + &*data.key_server_set, data.self_key_pair.public(), &server_key_id) => Some(ServiceTask::GenerateServerKey(origin, server_key_id, author, threshold)), // when server key is not yet generated and generation must be initiated by other node ServiceTask::GenerateServerKey(_, _, _, _) => None, @@ -187,7 +194,7 @@ impl ServiceContractListener { // when this node should be master of this document key decryption session ServiceTask::RetrieveShadowDocumentKeyPersonal(origin, server_key_id, requester) if is_processed_by_this_key_server( - &*data.key_server_set, &*data.self_key_pair, &server_key_id) => + &*data.key_server_set, data.self_key_pair.public(), &server_key_id) => Some(ServiceTask::RetrieveShadowDocumentKeyPersonal(origin, server_key_id, requester)), // when server key is not yet generated and generation must be initiated by other node ServiceTask::RetrieveShadowDocumentKeyPersonal(_, _, _) => None, @@ -211,7 +218,7 @@ impl ServiceContractListener { }; } - trace!(target: "secretstore_net", "{}: ServiceContractListener thread stopped", data.self_key_pair.public()); + trace!(target: "secretstore", "{}: ServiceContractListener thread stopped", data.self_key_pair.public()); } /// Process single service task. @@ -430,7 +437,7 @@ impl Drop for ServiceContractListener { impl ChainNotify for ServiceContractListener { fn new_blocks(&self, _imported: Vec, _invalid: Vec, route: ChainRoute, _sealed: Vec, _proposed: Vec, _duration: Duration) { let enacted_len = route.enacted().len(); - if enacted_len == 0 { + if enacted_len == 0 && route.retracted().is_empty() { return; } @@ -443,8 +450,11 @@ impl ChainNotify for ServiceContractListener { // schedule retry if received enough blocks since last retry // it maybe inaccurate when switching syncing/synced states, but that's ok if self.data.last_retry.fetch_add(enacted_len, Ordering::Relaxed) >= RETRY_INTERVAL_BLOCKS { - self.data.tasks_queue.push(ServiceTask::Retry); - self.data.last_retry.store(0, Ordering::Relaxed); + // shortcut: do not retry if we're isolated from the cluster + if !self.data.key_server_set.is_isolated() { + self.data.tasks_queue.push(ServiceTask::Retry); + self.data.last_retry.store(0, Ordering::Relaxed); + } } } } @@ -491,6 +501,35 @@ impl ClusterSessionsListener for ServiceContractListener { } } +impl ClusterSessionsListener> for ServiceContractListener { + fn on_session_removed(&self, session: Arc>) { + // by this time sesion must already be completed - either successfully, or not + assert!(session.is_finished()); + + // we're interested in: + // 1) sessions failed with fatal error + // 2) with decryption continue action + let error = match session.wait() { + Err(ref error) if !error.is_non_fatal() => error.clone(), + _ => return, + }; + + let (origin, requester) = match session.take_failed_continue_action() { + Some(FailedContinueAction::Decrypt(Some(origin), requester)) => (origin, requester), + _ => return, + }; + + // check if master node is responsible for processing key requests + let meta = session.meta(); + if !is_processed_by_this_key_server(&*self.data.key_server_set, &meta.master_node_id, &meta.id) { + return; + } + + // ignore result as we're already processing an error + let _ = Self::process_document_key_retrieval_result(&self.data, origin, &meta.id, &requester, Err(error)); + } +} + impl ::std::fmt::Display for ServiceTask { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { match *self { @@ -520,8 +559,8 @@ fn log_service_task_result(task: &ServiceTask, self_id: &Public, result: Result< result } -/// Returns true when session, related to `server_key_id` must be started on this KeyServer. -fn is_processed_by_this_key_server(key_server_set: &KeyServerSet, self_key_pair: &NodeKeyPair, server_key_id: &H256) -> bool { +/// Returns true when session, related to `server_key_id` must be started on `node`. +fn is_processed_by_this_key_server(key_server_set: &KeyServerSet, node: &NodeId, server_key_id: &H256) -> bool { let servers = key_server_set.snapshot().current_set; let total_servers_count = servers.len(); match total_servers_count { @@ -530,7 +569,7 @@ fn is_processed_by_this_key_server(key_server_set: &KeyServerSet, self_key_pair: _ => (), } - let this_server_index = match servers.keys().enumerate().find(|&(_, s)| s == self_key_pair.public()) { + let this_server_index = match servers.keys().enumerate().find(|&(_, s)| s == node) { Some((index, _)) => index, None => return false, }; @@ -554,8 +593,9 @@ mod tests { use acl_storage::{AclStorage, DummyAclStorage}; use key_storage::{KeyStorage, DocumentKeyShare}; use key_storage::tests::DummyKeyStorage; + use key_server_set::KeyServerSet; use key_server_set::tests::MapKeyServerSet; - use {PlainNodeKeyPair, ServerKeyId}; + use {NodeKeyPair, PlainNodeKeyPair, ServerKeyId}; use super::{ServiceTask, ServiceContractListener, ServiceContractListenerParams, is_processed_by_this_key_server}; fn create_non_empty_key_storage(has_doc_key: bool) -> Arc { @@ -571,19 +611,23 @@ mod tests { key_storage } - fn make_service_contract_listener(contract: Option>, cluster: Option>, key_storage: Option>, acl_storage: Option>) -> Arc { - let contract = contract.unwrap_or_else(|| Arc::new(DummyServiceContract::default())); - let cluster = cluster.unwrap_or_else(|| Arc::new(DummyClusterClient::default())); - let key_storage = key_storage.unwrap_or_else(|| Arc::new(DummyKeyStorage::default())); - let acl_storage = acl_storage.unwrap_or_else(|| Arc::new(DummyAclStorage::default())); - let servers_set = Arc::new(MapKeyServerSet::new(vec![ + fn make_servers_set(is_isolated: bool) -> Arc { + Arc::new(MapKeyServerSet::new(is_isolated, vec![ ("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8".parse().unwrap(), "127.0.0.1:8080".parse().unwrap()), ("c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a".parse().unwrap(), "127.0.0.1:8080".parse().unwrap()), ("f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672".parse().unwrap(), "127.0.0.1:8080".parse().unwrap()), - ].into_iter().collect())); + ].into_iter().collect())) + } + + fn make_service_contract_listener(contract: Option>, cluster: Option>, key_storage: Option>, acl_storage: Option>, servers_set: Option>) -> Arc { + let contract = contract.unwrap_or_else(|| Arc::new(DummyServiceContract::default())); + let cluster = cluster.unwrap_or_else(|| Arc::new(DummyClusterClient::default())); + let key_storage = key_storage.unwrap_or_else(|| Arc::new(DummyKeyStorage::default())); + let acl_storage = acl_storage.unwrap_or_else(|| Arc::new(DummyAclStorage::default())); + let servers_set = servers_set.unwrap_or_else(|| make_servers_set(false)); let self_key_pair = Arc::new(PlainNodeKeyPair::new(KeyPair::from_secret("0000000000000000000000000000000000000000000000000000000000000001".parse().unwrap()).unwrap())); ServiceContractListener::new(ServiceContractListenerParams { contract: contract, @@ -599,7 +643,7 @@ mod tests { fn is_not_processed_by_this_key_server_with_zero_servers() { assert_eq!(is_processed_by_this_key_server( &MapKeyServerSet::default(), - &PlainNodeKeyPair::new(Random.generate().unwrap()), + Random.generate().unwrap().public(), &Default::default()), false); } @@ -607,27 +651,27 @@ mod tests { fn is_processed_by_this_key_server_with_single_server() { let self_key_pair = Random.generate().unwrap(); assert_eq!(is_processed_by_this_key_server( - &MapKeyServerSet::new(vec![ + &MapKeyServerSet::new(false, vec![ (self_key_pair.public().clone(), "127.0.0.1:8080".parse().unwrap()) ].into_iter().collect()), - &PlainNodeKeyPair::new(self_key_pair), + self_key_pair.public(), &Default::default()), true); } #[test] fn is_not_processed_by_this_key_server_when_not_a_part_of_servers_set() { assert!(is_processed_by_this_key_server( - &MapKeyServerSet::new(vec![ + &MapKeyServerSet::new(false, vec![ (Random.generate().unwrap().public().clone(), "127.0.0.1:8080".parse().unwrap()) ].into_iter().collect()), - &PlainNodeKeyPair::new(Random.generate().unwrap()), + Random.generate().unwrap().public(), &Default::default())); } #[test] fn is_processed_by_this_key_server_in_set_of_3() { // servers set is ordered && server range depends on index of this server - let servers_set = MapKeyServerSet::new(vec![ + let servers_set = MapKeyServerSet::new(false, vec![ // secret: 0000000000000000000000000000000000000000000000000000000000000001 ("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8".parse().unwrap(), "127.0.0.1:8080".parse().unwrap()), @@ -642,46 +686,46 @@ mod tests { // 1st server: process hashes [0x0; 0x555...555] let key_pair = PlainNodeKeyPair::new(KeyPair::from_secret( "0000000000000000000000000000000000000000000000000000000000000001".parse().unwrap()).unwrap()); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"0000000000000000000000000000000000000000000000000000000000000000".parse().unwrap()), true); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"3000000000000000000000000000000000000000000000000000000000000000".parse().unwrap()), true); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"5555555555555555555555555555555555555555555555555555555555555555".parse().unwrap()), true); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"5555555555555555555555555555555555555555555555555555555555555556".parse().unwrap()), false); // 2nd server: process hashes from 0x555...556 to 0xaaa...aab let key_pair = PlainNodeKeyPair::new(KeyPair::from_secret( "0000000000000000000000000000000000000000000000000000000000000002".parse().unwrap()).unwrap()); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"5555555555555555555555555555555555555555555555555555555555555555".parse().unwrap()), false); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"5555555555555555555555555555555555555555555555555555555555555556".parse().unwrap()), true); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"7555555555555555555555555555555555555555555555555555555555555555".parse().unwrap()), true); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab".parse().unwrap()), true); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac".parse().unwrap()), false); // 3rd server: process hashes from 0x800...000 to 0xbff...ff let key_pair = PlainNodeKeyPair::new(KeyPair::from_secret( "0000000000000000000000000000000000000000000000000000000000000003".parse().unwrap()).unwrap()); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab".parse().unwrap()), false); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac".parse().unwrap()), true); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"daaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac".parse().unwrap()), true); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse().unwrap()), true); } #[test] fn is_processed_by_this_key_server_in_set_of_4() { // servers set is ordered && server range depends on index of this server - let servers_set = MapKeyServerSet::new(vec![ + let servers_set = MapKeyServerSet::new(false, vec![ // secret: 0000000000000000000000000000000000000000000000000000000000000001 ("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8".parse().unwrap(), "127.0.0.1:8080".parse().unwrap()), @@ -699,62 +743,72 @@ mod tests { // 1st server: process hashes [0x0; 0x3ff...ff] let key_pair = PlainNodeKeyPair::new(KeyPair::from_secret( "0000000000000000000000000000000000000000000000000000000000000001".parse().unwrap()).unwrap()); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"0000000000000000000000000000000000000000000000000000000000000000".parse().unwrap()), true); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"2000000000000000000000000000000000000000000000000000000000000000".parse().unwrap()), true); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse().unwrap()), true); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"4000000000000000000000000000000000000000000000000000000000000000".parse().unwrap()), false); // 2nd server: process hashes from 0x400...000 to 0x7ff...ff let key_pair = PlainNodeKeyPair::new(KeyPair::from_secret( "0000000000000000000000000000000000000000000000000000000000000002".parse().unwrap()).unwrap()); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse().unwrap()), false); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"4000000000000000000000000000000000000000000000000000000000000000".parse().unwrap()), true); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"6000000000000000000000000000000000000000000000000000000000000000".parse().unwrap()), true); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse().unwrap()), true); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"8000000000000000000000000000000000000000000000000000000000000000".parse().unwrap()), false); // 3rd server: process hashes from 0x800...000 to 0xbff...ff let key_pair = PlainNodeKeyPair::new(KeyPair::from_secret( "0000000000000000000000000000000000000000000000000000000000000004".parse().unwrap()).unwrap()); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse().unwrap()), false); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"8000000000000000000000000000000000000000000000000000000000000000".parse().unwrap()), true); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"a000000000000000000000000000000000000000000000000000000000000000".parse().unwrap()), true); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"bfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse().unwrap()), true); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"c000000000000000000000000000000000000000000000000000000000000000".parse().unwrap()), false); // 4th server: process hashes from 0xc00...000 to 0xfff...ff let key_pair = PlainNodeKeyPair::new(KeyPair::from_secret( "0000000000000000000000000000000000000000000000000000000000000003".parse().unwrap()).unwrap()); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"bfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse().unwrap()), false); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"c000000000000000000000000000000000000000000000000000000000000000".parse().unwrap()), true); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"e000000000000000000000000000000000000000000000000000000000000000".parse().unwrap()), true); - assert_eq!(is_processed_by_this_key_server(&servers_set, &key_pair, + assert_eq!(is_processed_by_this_key_server(&servers_set, key_pair.public(), &"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse().unwrap()), true); } #[test] fn no_tasks_scheduled_when_no_contract_events() { - let listener = make_service_contract_listener(None, None, None, None); - assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); + let listener = make_service_contract_listener(None, None, None, None, None); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 0); listener.process_service_contract_events(); - assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 0); + } + + #[test] + fn tasks_are_not_scheduled_on_isolated_node() { + let mut contract = DummyServiceContract::default(); + contract.logs.push(ServiceTask::GenerateServerKey(Default::default(), Default::default(), Default::default(), 0)); + let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None, Some(make_servers_set(true))); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 0); + listener.process_service_contract_events(); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 0); } // server key generation tests @@ -763,10 +817,10 @@ mod tests { fn server_key_generation_is_scheduled_when_requested() { let mut contract = DummyServiceContract::default(); contract.logs.push(ServiceTask::GenerateServerKey(Default::default(), Default::default(), Default::default(), 0)); - let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None); - assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); + let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None, None); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 0); listener.process_service_contract_events(); - assert_eq!(listener.data.tasks_queue.snapshot().len(), 2); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); assert_eq!(listener.data.tasks_queue.snapshot().pop_back(), Some(ServiceTask::GenerateServerKey( Default::default(), Default::default(), Default::default(), 0))); } @@ -776,16 +830,16 @@ mod tests { let server_key_id = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse().unwrap(); let mut contract = DummyServiceContract::default(); contract.logs.push(ServiceTask::GenerateServerKey(Default::default(), server_key_id, Default::default(), 0)); - let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None); - assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); + let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None, None); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 0); listener.process_service_contract_events(); - assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 0); } #[test] fn generation_session_is_created_when_processing_generate_server_key_task() { let cluster = Arc::new(DummyClusterClient::default()); - let listener = make_service_contract_listener(None, Some(cluster.clone()), None, None); + let listener = make_service_contract_listener(None, Some(cluster.clone()), None, None, None); ServiceContractListener::process_service_task(&listener.data, ServiceTask::GenerateServerKey( Default::default(), Default::default(), Default::default(), Default::default())).unwrap_err(); assert_eq!(cluster.generation_requests_count.load(Ordering::Relaxed), 1); @@ -797,7 +851,7 @@ mod tests { contract.pending_requests.push((false, ServiceTask::GenerateServerKey(Default::default(), Default::default(), Default::default(), Default::default()))); let cluster = Arc::new(DummyClusterClient::default()); - let listener = make_service_contract_listener(Some(Arc::new(contract)), Some(cluster.clone()), None, None); + let listener = make_service_contract_listener(Some(Arc::new(contract)), Some(cluster.clone()), None, None, None); listener.data.retry_data.lock().affected_server_keys.insert(Default::default()); ServiceContractListener::retry_pending_requests(&listener.data).unwrap(); assert_eq!(cluster.generation_requests_count.load(Ordering::Relaxed), 0); @@ -809,10 +863,10 @@ mod tests { fn server_key_retrieval_is_scheduled_when_requested() { let mut contract = DummyServiceContract::default(); contract.logs.push(ServiceTask::RetrieveServerKey(Default::default(), Default::default())); - let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None); - assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); + let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None, None); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 0); listener.process_service_contract_events(); - assert_eq!(listener.data.tasks_queue.snapshot().len(), 2); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); assert_eq!(listener.data.tasks_queue.snapshot().pop_back(), Some(ServiceTask::RetrieveServerKey( Default::default(), Default::default()))); } @@ -822,10 +876,10 @@ mod tests { let server_key_id: ServerKeyId = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse().unwrap(); let mut contract = DummyServiceContract::default(); contract.logs.push(ServiceTask::RetrieveServerKey(Default::default(), server_key_id.clone())); - let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None); - assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); + let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None, None); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 0); listener.process_service_contract_events(); - assert_eq!(listener.data.tasks_queue.snapshot().len(), 2); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); assert_eq!(listener.data.tasks_queue.snapshot().pop_back(), Some(ServiceTask::RetrieveServerKey( Default::default(), server_key_id))); } @@ -834,7 +888,7 @@ mod tests { fn server_key_is_retrieved_when_processing_retrieve_server_key_task() { let contract = Arc::new(DummyServiceContract::default()); let key_storage = create_non_empty_key_storage(false); - let listener = make_service_contract_listener(Some(contract.clone()), None, Some(key_storage), None); + let listener = make_service_contract_listener(Some(contract.clone()), None, Some(key_storage), None, None); ServiceContractListener::process_service_task(&listener.data, ServiceTask::RetrieveServerKey( Default::default(), Default::default())).unwrap(); assert_eq!(*contract.retrieved_server_keys.lock(), vec![(Default::default(), @@ -844,7 +898,7 @@ mod tests { #[test] fn server_key_retrieval_failure_is_reported_when_processing_retrieve_server_key_task_and_key_is_unknown() { let contract = Arc::new(DummyServiceContract::default()); - let listener = make_service_contract_listener(Some(contract.clone()), None, None, None); + let listener = make_service_contract_listener(Some(contract.clone()), None, None, None, None); ServiceContractListener::process_service_task(&listener.data, ServiceTask::RetrieveServerKey( Default::default(), Default::default())).unwrap(); assert_eq!(*contract.server_keys_retrieval_failures.lock(), vec![Default::default()]); @@ -855,7 +909,7 @@ mod tests { let mut contract = DummyServiceContract::default(); contract.pending_requests.push((false, ServiceTask::RetrieveServerKey(Default::default(), Default::default()))); let cluster = Arc::new(DummyClusterClient::default()); - let listener = make_service_contract_listener(Some(Arc::new(contract)), Some(cluster.clone()), None, None); + let listener = make_service_contract_listener(Some(Arc::new(contract)), Some(cluster.clone()), None, None, None); listener.data.retry_data.lock().affected_server_keys.insert(Default::default()); ServiceContractListener::retry_pending_requests(&listener.data).unwrap(); assert_eq!(cluster.generation_requests_count.load(Ordering::Relaxed), 0); @@ -868,10 +922,10 @@ mod tests { let mut contract = DummyServiceContract::default(); contract.logs.push(ServiceTask::StoreDocumentKey(Default::default(), Default::default(), Default::default(), Default::default(), Default::default())); - let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None); - assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); + let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None, None); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 0); listener.process_service_contract_events(); - assert_eq!(listener.data.tasks_queue.snapshot().len(), 2); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); assert_eq!(listener.data.tasks_queue.snapshot().pop_back(), Some(ServiceTask::StoreDocumentKey( Default::default(), Default::default(), Default::default(), Default::default(), Default::default()))); } @@ -882,10 +936,10 @@ mod tests { let mut contract = DummyServiceContract::default(); contract.logs.push(ServiceTask::StoreDocumentKey(Default::default(), server_key_id.clone(), Default::default(), Default::default(), Default::default())); - let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None); - assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); + let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None, None); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 0); listener.process_service_contract_events(); - assert_eq!(listener.data.tasks_queue.snapshot().len(), 2); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); assert_eq!(listener.data.tasks_queue.snapshot().pop_back(), Some(ServiceTask::StoreDocumentKey( Default::default(), server_key_id, Default::default(), Default::default(), Default::default()))); } @@ -894,7 +948,7 @@ mod tests { fn document_key_is_stored_when_processing_store_document_key_task() { let contract = Arc::new(DummyServiceContract::default()); let key_storage = create_non_empty_key_storage(false); - let listener = make_service_contract_listener(Some(contract.clone()), None, Some(key_storage.clone()), None); + let listener = make_service_contract_listener(Some(contract.clone()), None, Some(key_storage.clone()), None, None); ServiceContractListener::process_service_task(&listener.data, ServiceTask::StoreDocumentKey( Default::default(), Default::default(), Default::default(), Default::default(), Default::default())).unwrap(); assert_eq!(*contract.stored_document_keys.lock(), vec![Default::default()]); @@ -907,7 +961,7 @@ mod tests { #[test] fn document_key_store_failure_reported_when_no_server_key() { let contract = Arc::new(DummyServiceContract::default()); - let listener = make_service_contract_listener(Some(contract.clone()), None, None, None); + let listener = make_service_contract_listener(Some(contract.clone()), None, None, None, None); ServiceContractListener::process_service_task(&listener.data, ServiceTask::StoreDocumentKey( Default::default(), Default::default(), Default::default(), Default::default(), Default::default())).unwrap_err(); assert_eq!(*contract.document_keys_store_failures.lock(), vec![Default::default()]); @@ -917,7 +971,7 @@ mod tests { fn document_key_store_failure_reported_when_document_key_already_set() { let contract = Arc::new(DummyServiceContract::default()); let key_storage = create_non_empty_key_storage(true); - let listener = make_service_contract_listener(Some(contract.clone()), None, Some(key_storage), None); + let listener = make_service_contract_listener(Some(contract.clone()), None, Some(key_storage), None, None); ServiceContractListener::process_service_task(&listener.data, ServiceTask::StoreDocumentKey( Default::default(), Default::default(), Default::default(), Default::default(), Default::default())).unwrap_err(); assert_eq!(*contract.document_keys_store_failures.lock(), vec![Default::default()]); @@ -927,7 +981,7 @@ mod tests { fn document_key_store_failure_reported_when_author_differs() { let contract = Arc::new(DummyServiceContract::default()); let key_storage = create_non_empty_key_storage(false); - let listener = make_service_contract_listener(Some(contract.clone()), None, Some(key_storage), None); + let listener = make_service_contract_listener(Some(contract.clone()), None, Some(key_storage), None, None); ServiceContractListener::process_service_task(&listener.data, ServiceTask::StoreDocumentKey( Default::default(), Default::default(), 1.into(), Default::default(), Default::default())).unwrap_err(); assert_eq!(*contract.document_keys_store_failures.lock(), vec![Default::default()]); @@ -939,10 +993,10 @@ mod tests { fn document_key_shadow_common_retrieval_is_scheduled_when_requested() { let mut contract = DummyServiceContract::default(); contract.logs.push(ServiceTask::RetrieveShadowDocumentKeyCommon(Default::default(), Default::default(), Default::default())); - let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None); - assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); + let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None, None); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 0); listener.process_service_contract_events(); - assert_eq!(listener.data.tasks_queue.snapshot().len(), 2); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); assert_eq!(listener.data.tasks_queue.snapshot().pop_back(), Some(ServiceTask::RetrieveShadowDocumentKeyCommon( Default::default(), Default::default(), Default::default()))); } @@ -952,10 +1006,10 @@ mod tests { let server_key_id: ServerKeyId = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse().unwrap(); let mut contract = DummyServiceContract::default(); contract.logs.push(ServiceTask::RetrieveShadowDocumentKeyCommon(Default::default(), server_key_id.clone(), Default::default())); - let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None); - assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); + let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None, None); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 0); listener.process_service_contract_events(); - assert_eq!(listener.data.tasks_queue.snapshot().len(), 2); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); assert_eq!(listener.data.tasks_queue.snapshot().pop_back(), Some(ServiceTask::RetrieveShadowDocumentKeyCommon( Default::default(), server_key_id, Default::default()))); } @@ -964,7 +1018,7 @@ mod tests { fn document_key_shadow_common_is_retrieved_when_processing_document_key_shadow_common_retrieval_task() { let contract = Arc::new(DummyServiceContract::default()); let key_storage = create_non_empty_key_storage(true); - let listener = make_service_contract_listener(Some(contract.clone()), None, Some(key_storage.clone()), None); + let listener = make_service_contract_listener(Some(contract.clone()), None, Some(key_storage.clone()), None, None); ServiceContractListener::process_service_task(&listener.data, ServiceTask::RetrieveShadowDocumentKeyCommon( Default::default(), Default::default(), Default::default())).unwrap(); assert_eq!(*contract.common_shadow_retrieved_document_keys.lock(), vec![(Default::default(), Default::default(), @@ -977,7 +1031,7 @@ mod tests { acl_storage.prohibit(Default::default(), Default::default()); let contract = Arc::new(DummyServiceContract::default()); let key_storage = create_non_empty_key_storage(true); - let listener = make_service_contract_listener(Some(contract.clone()), None, Some(key_storage.clone()), Some(Arc::new(acl_storage))); + let listener = make_service_contract_listener(Some(contract.clone()), None, Some(key_storage.clone()), Some(Arc::new(acl_storage)), None); ServiceContractListener::process_service_task(&listener.data, ServiceTask::RetrieveShadowDocumentKeyCommon( Default::default(), Default::default(), Default::default())).unwrap_err(); assert_eq!(*contract.document_keys_shadow_retrieval_failures.lock(), vec![(Default::default(), Default::default())]); @@ -986,7 +1040,7 @@ mod tests { #[test] fn document_key_shadow_common_retrieval_failure_reported_when_no_server_key() { let contract = Arc::new(DummyServiceContract::default()); - let listener = make_service_contract_listener(Some(contract.clone()), None, None, None); + let listener = make_service_contract_listener(Some(contract.clone()), None, None, None, None); ServiceContractListener::process_service_task(&listener.data, ServiceTask::RetrieveShadowDocumentKeyCommon( Default::default(), Default::default(), Default::default())).unwrap_err(); assert_eq!(*contract.document_keys_shadow_retrieval_failures.lock(), vec![(Default::default(), Default::default())]); @@ -996,7 +1050,7 @@ mod tests { fn document_key_shadow_common_retrieval_failure_reported_when_no_document_key() { let contract = Arc::new(DummyServiceContract::default()); let key_storage = create_non_empty_key_storage(false); - let listener = make_service_contract_listener(Some(contract.clone()), None, Some(key_storage.clone()), None); + let listener = make_service_contract_listener(Some(contract.clone()), None, Some(key_storage.clone()), None, None); ServiceContractListener::process_service_task(&listener.data, ServiceTask::RetrieveShadowDocumentKeyCommon( Default::default(), Default::default(), Default::default())).unwrap_err(); assert_eq!(*contract.document_keys_shadow_retrieval_failures.lock(), vec![(Default::default(), Default::default())]); diff --git a/secret_store/src/listener/tasks_queue.rs b/secret_store/src/listener/tasks_queue.rs index e228d12cef81141d289fa7794aeb85ae545e81d8..934459940aeba00c5e07e5d2e0272bfa12871b25 100644 --- a/secret_store/src/listener/tasks_queue.rs +++ b/secret_store/src/listener/tasks_queue.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/node_key_pair.rs b/secret_store/src/node_key_pair.rs index 428dba6c1a706e59080b8a5a4a8a976332a2e1cf..d96d9ff61151286dcb353be290657b3e9be36769 100644 --- a/secret_store/src/node_key_pair.rs +++ b/secret_store/src/node_key_pair.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -20,6 +20,7 @@ use ethkey::{KeyPair, Public, Signature, Error as EthKeyError, sign, public_to_a use ethcore::account_provider::AccountProvider; use ethereum_types::{H256, Address}; use traits::NodeKeyPair; +use ethkey::Password; pub struct PlainNodeKeyPair { key_pair: KeyPair, @@ -29,7 +30,7 @@ pub struct KeyStoreNodeKeyPair { account_provider: Arc, address: Address, public: Public, - password: String, + password: Password, } impl PlainNodeKeyPair { @@ -61,7 +62,7 @@ impl NodeKeyPair for PlainNodeKeyPair { } impl KeyStoreNodeKeyPair { - pub fn new(account_provider: Arc, address: Address, password: String) -> Result { + pub fn new(account_provider: Arc, address: Address, password: Password) -> Result { let public = account_provider.account_public(address.clone(), &password).map_err(|e| EthKeyError::Custom(format!("{}", e)))?; Ok(KeyStoreNodeKeyPair { account_provider: account_provider, diff --git a/secret_store/src/serialization.rs b/secret_store/src/serialization.rs index f3e9aa1d76d979937f38b3545c86b044ca3e1707..7ae5e8f2694a17ed4d7f591c1718ea723fb68132 100644 --- a/secret_store/src/serialization.rs +++ b/secret_store/src/serialization.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/traits.rs b/secret_store/src/traits.rs index 704be1c2545e58fa1240f589052b972b6c0dbfed..d92983fe8da7f48894792c20ec43e44049ced574 100644 --- a/secret_store/src/traits.rs +++ b/secret_store/src/traits.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/trusted_client.rs b/secret_store/src/trusted_client.rs index 94b1c0174de9e2b067eb046eab7995d36f2baa35..24db21460005be01db2aacffaae5b6ff398b2da1 100644 --- a/secret_store/src/trusted_client.rs +++ b/secret_store/src/trusted_client.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -17,11 +17,12 @@ use std::sync::{Arc, Weak}; use bytes::Bytes; use ethereum_types::Address; -use ethcore::client::{Client, BlockChainClient, ChainInfo, Nonce}; +use ethcore::client::{Client, BlockChainClient, ChainInfo, Nonce, BlockId, RegistryInfo}; use ethcore::miner::{Miner, MinerService}; use sync::SyncProvider; use transaction::{Transaction, SignedTransaction, Action}; -use {Error, NodeKeyPair}; +use helpers::{get_confirmed_block_hash, REQUEST_CONFIRMATIONS_REQUIRED}; +use {Error, NodeKeyPair, ContractAddress}; #[derive(Clone)] /// 'Trusted' client weak reference. @@ -84,6 +85,18 @@ impl TrustedClient { let signed = SignedTransaction::new(transaction.with_signature(signature, chain_id))?; miner.import_own_transaction(&*client, signed.into()) .map_err(|e| Error::Internal(format!("failed to import tx: {}", e))) - .map(|_| ()) + } + + /// Read contract address. If address source is registry, address only returned if current client state is + /// trusted. Address from registry is read from registry from block latest block with + /// REQUEST_CONFIRMATIONS_REQUIRED confirmations. + pub fn read_contract_address(&self, registry_name: String, address: &ContractAddress) -> Option
{ + match *address { + ContractAddress::Address(ref address) => Some(address.clone()), + ContractAddress::Registry => self.get().and_then(|client| + get_confirmed_block_hash(&*client, REQUEST_CONFIRMATIONS_REQUIRED) + .and_then(|block| client.registry_address(registry_name, BlockId::Hash(block))) + ), + } } } diff --git a/secret_store/src/types/all.rs b/secret_store/src/types/all.rs index ab0aea1b1333c9e3782975e5d0611557c935d204..feca4141f084b0c79cde7db4d9b620c99737cde5 100644 --- a/secret_store/src/types/all.rs +++ b/secret_store/src/types/all.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -66,8 +66,8 @@ pub struct ServiceConfiguration { pub service_contract_doc_store_address: Option, /// Document key shadow retrieval service contract address. pub service_contract_doc_sretr_address: Option, - /// Is ACL check enabled. If false, everyone has access to all keys. Useful for tests only. - pub acl_check_enabled: bool, + /// ACL check contract address. If None, everyone has access to all keys. Useful for tests only. + pub acl_check_contract_address: Option, /// Cluster configuration. pub cluster_config: ClusterConfiguration, } @@ -81,6 +81,8 @@ pub struct ClusterConfiguration { pub listener_address: NodeAddress, /// All cluster nodes addresses. pub nodes: BTreeMap, + /// Key Server Set contract address. If None, servers from 'nodes' map are used. + pub key_server_set_contract_address: Option, /// Allow outbound connections to 'higher' nodes. /// This is useful for tests, but slower a bit for production. pub allow_connecting_to_higher_nodes: bool, diff --git a/secret_store/src/types/error.rs b/secret_store/src/types/error.rs index eae914ec866cdf954e6b46fe82df6bc79481f1b2..fc670fcc02dec0fd1ae89add38176a7821b0d3e0 100644 --- a/secret_store/src/types/error.rs +++ b/secret_store/src/types/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -18,7 +18,7 @@ use std::fmt; use std::net; use std::io::Error as IoError; -use {ethkey, crypto, kvdb}; +use {ethkey, crypto}; /// Secret store error. #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -174,12 +174,6 @@ impl From for Error { } } -impl From for Error { - fn from(err: kvdb::Error) -> Self { - Error::Database(err.to_string()) - } -} - impl From for Error { fn from(err: crypto::Error) -> Self { Error::EthKey(err.to_string()) diff --git a/secret_store/src/types/mod.rs b/secret_store/src/types/mod.rs index 9da7f6ef9851d10e0a1d619f244d690304d5eefe..443f4acb3a5725c12f2e9d1b7438fa9073d756cc 100644 --- a/secret_store/src/types/mod.rs +++ b/secret_store/src/types/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c7da2396002da968136e39c63579691bfb80469f --- /dev/null +++ b/snap/snapcraft.yaml @@ -0,0 +1,41 @@ +name: parity +version: git +summary: Fast, light, robust Ethereum implementation +description: | + Parity's goal is to be the fastest, lightest, and most secure Ethereum + client. We are developing Parity using the sophisticated and cutting-edge + Rust programming language. Parity is licensed under the GPLv3, and can be + used for all your Ethereum needs. + +grade: devel +confinement: strict + +apps: + parity: + command: parity + plugs: [home, network, network-bind, mount-observe, x11, unity7, desktop, desktop-legacy, wayland] + desktop: usr/share/applications/parity.desktop + +icon: snap/gui/icon.png + +parts: + desktop-icon: + source: ./snap + plugin: nil + prepare: | + mkdir -p $SNAPCRAFT_PART_INSTALL/usr/share/applications + mkdir -p $SNAPCRAFT_PART_INSTALL/usr/share/pixmaps + cp -v gui/parity.desktop $SNAPCRAFT_PART_INSTALL/usr/share/applications/ + cp -v gui/icon.png $SNAPCRAFT_PART_INSTALL/usr/share/pixmaps/ + parity: + source: . + plugin: rust + # rust-channel: stable # @TODO enable after https://bugs.launchpad.net/snapcraft/+bug/1778530 + rust-revision: 1.26.2 # @TODO remove after https://bugs.launchpad.net/snapcraft/+bug/1778530 + build-attributes: [no-system-libraries] + build-packages: [g++, libudev-dev, make, pkg-config, cmake] + stage-packages: [libc6, libudev1, libstdc++6] + df: + plugin: nil + stage-packages: [coreutils] + stage: [bin/df] diff --git a/test.sh b/test.sh index 9bb527b70830377a8e130f68aa4b50cd79616f3e..82e05d954c507c1c8b501d292dd19ae17ec57eba 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,8 +52,9 @@ cd parity-clib-example && \ ./parity-example && \ cd .. && \ rm -rf build && \ - cd .. + cd ../.. # Running tests echo "________Running Parity Full Test Suite________" +git submodule update --init --recursive cargo test -j 8 $OPTIONS --features "$FEATURES" --all $1 diff --git a/transaction-pool/Cargo.toml b/transaction-pool/Cargo.toml index 8965c8cee01543225897d8926e8ab02013a657cc..8af887d3cb968f7c7a02e0978b6a593ed093deed 100644 --- a/transaction-pool/Cargo.toml +++ b/transaction-pool/Cargo.toml @@ -1,12 +1,12 @@ [package] description = "Generic transaction pool." name = "transaction-pool" -version = "1.12.0" +version = "1.12.1" license = "GPL-3.0" authors = ["Parity Technologies "] [dependencies] -error-chain = "0.11" +error-chain = "0.12" log = "0.3" smallvec = "0.4" trace-time = { path = "../util/trace-time", version = "0.1" } diff --git a/transaction-pool/src/error.rs b/transaction-pool/src/error.rs index 4cf221a71e4e717e10ccc435b4c1f7e9dd8463f7..c7666841a2c9c450f834bf833ca15a9bdb65491c 100644 --- a/transaction-pool/src/error.rs +++ b/transaction-pool/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/transaction-pool/src/lib.rs b/transaction-pool/src/lib.rs index 4a1bdcde14234f62b839298512b0e208cf6c618e..ea77debfa2f965d5da16c243b5f76d331e7e2be2 100644 --- a/transaction-pool/src/lib.rs +++ b/transaction-pool/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/transaction-pool/src/listener.rs b/transaction-pool/src/listener.rs index 728a035e314aa2e96a279a217c5cf4770e8b68b4..3339a7730d1d3ac2c2192fedb8ab83a5b9672815 100644 --- a/transaction-pool/src/listener.rs +++ b/transaction-pool/src/listener.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/transaction-pool/src/options.rs b/transaction-pool/src/options.rs index 8ccf8adfd1695281c344b21c1f3ad08a3bae94bb..291001a20270434c7c4f335d19e9e983c537df66 100644 --- a/transaction-pool/src/options.rs +++ b/transaction-pool/src/options.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/transaction-pool/src/pool.rs b/transaction-pool/src/pool.rs index 5cb6e479b8e4920a1bd4eafb25946f3bffbae768..c94b736b8ff4d88dad3e13053b397e18297fdd97 100644 --- a/transaction-pool/src/pool.rs +++ b/transaction-pool/src/pool.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -15,13 +15,14 @@ // along with Parity. If not, see . use std::sync::Arc; -use std::collections::{HashMap, BTreeSet}; +use std::slice; +use std::collections::{hash_map, HashMap, BTreeSet}; 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}; @@ -95,7 +96,6 @@ impl> Pool { } } - const INITIAL_NUMBER_OF_SENDERS: usize = 16; impl Pool where @@ -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`. @@ -390,7 +405,18 @@ impl Pool where /// Returns worst transaction in the queue (if any). pub fn worst_transaction(&self) -> Option> { - self.worst_transactions.iter().next().map(|x| x.transaction.transaction.clone()) + self.worst_transactions.iter().next_back().map(|x| x.transaction.transaction.clone()) + } + + /// Returns true if the pool is at it's capacity. + pub fn is_full(&self) -> bool { + self.by_hash.len() >= self.options.max_count + || 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. @@ -417,7 +443,16 @@ impl Pool where PendingIterator { ready, best_transactions, - pool: self + pool: self, + } + } + + /// Returns unprioritized list of ready transactions. + pub fn unordered_pending>(&self, ready: R) -> UnorderedIterator { + UnorderedIterator { + ready, + senders: self.transactions.iter(), + transactions: None, } } @@ -477,12 +512,61 @@ impl Pool where &self.listener } + /// Borrows scoring instance. + pub fn scoring(&self) -> &S { + &self.scoring + } + /// Borrows listener mutably. pub fn listener_mut(&mut self) -> &mut L { &mut self.listener } } +/// An iterator over all pending (ready) transactions in unoredered fashion. +/// +/// NOTE: Current implementation will iterate over all transactions from particular sender +/// ordered by nonce, but that might change in the future. +/// +/// NOTE: the transactions are not removed from the queue. +/// You might remove them later by calling `cull`. +pub struct UnorderedIterator<'a, T, R, S> where + T: VerifiedTransaction + 'a, + S: Scoring + 'a, +{ + ready: R, + senders: hash_map::Iter<'a, T::Sender, Transactions>, + transactions: Option>>, +} + +impl<'a, T, R, S> Iterator for UnorderedIterator<'a, T, R, S> where + T: VerifiedTransaction, + R: Ready, + S: Scoring, +{ + type Item = Arc; + + fn next(&mut self) -> Option { + loop { + if let Some(transactions) = self.transactions.as_mut() { + if let Some(tx) = transactions.next() { + match self.ready.is_ready(&tx) { + Readiness::Ready => { + return Some(tx.transaction.clone()); + }, + state => trace!("[{:?}] Ignoring {:?} transaction.", tx.hash(), state), + } + } + } + + // otherwise fallback and try next sender + let next_sender = self.senders.next()?; + self.transactions = Some(next_sender.1.iter()); + } + } +} + + /// An iterator over all pending (ready) transactions. /// NOTE: the transactions are not removed from the queue. /// You might remove them later by calling `cull`. @@ -529,3 +613,4 @@ impl<'a, T, R, S, L> Iterator for PendingIterator<'a, T, R, S, L> where None } } + diff --git a/transaction-pool/src/ready.rs b/transaction-pool/src/ready.rs index aa913a9eb58afd79ac90ffa2483f5d1c4cfd52e2..0bee5188df285fb09392bb49215d6a33115197aa 100644 --- a/transaction-pool/src/ready.rs +++ b/transaction-pool/src/ready.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/transaction-pool/src/scoring.rs b/transaction-pool/src/scoring.rs index 2acfb3374856d3dba771fe940feee246ad14036b..25189604cd293a5e796ce6284aab71c5268be4c6 100644 --- a/transaction-pool/src/scoring.rs +++ b/transaction-pool/src/scoring.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -99,7 +99,15 @@ 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; + + /// Decides if the transaction should ignore per-sender limit in the pool. + /// + /// If you return `true` for given transaction it's going to be accepted even though + /// the per-sender limit is exceeded. + fn should_ignore_sender_limit(&self, _new: &T) -> bool { false } } /// A score with a reference to the transaction. diff --git a/transaction-pool/src/status.rs b/transaction-pool/src/status.rs index a03bc6b062a2e639bb0b5b90d74b69f5e71e6362..b9e7656d445a7e7e951e9f4d019dafdfe06c00c6 100644 --- a/transaction-pool/src/status.rs +++ b/transaction-pool/src/status.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/transaction-pool/src/tests/helpers.rs b/transaction-pool/src/tests/helpers.rs index cfc6641b5ebfed568ab79faac65a9da8c61cc424..9918db91b4376a0ba7779b77461481383024fdf8 100644 --- a/transaction-pool/src/tests/helpers.rs +++ b/transaction-pool/src/tests/helpers.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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,18 @@ 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 + } + } + + fn should_ignore_sender_limit(&self, _new: &Transaction) -> bool { + self.always_insert } } diff --git a/transaction-pool/src/tests/mod.rs b/transaction-pool/src/tests/mod.rs index b21ea31807c482bb85325399f2fe04a9a2f93ca9..85260133e3e9dd148665f585667276f9c32ce3c5 100644 --- a/transaction-pool/src/tests/mod.rs +++ b/transaction-pool/src/tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -48,6 +48,15 @@ pub type SharedTransaction = Arc; type TestPool = Pool; +impl TestPool { + pub fn with_limit(max_count: usize) -> Self { + Self::with_options(Options { + max_count, + ..Default::default() + }) + } +} + #[test] fn should_clear_queue() { // given @@ -250,6 +259,66 @@ fn should_construct_pending() { assert_eq!(pending.next(), None); } +#[test] +fn should_return_unordered_iterator() { + // given + let b = TransactionBuilder::default(); + let mut txq = TestPool::default(); + + let tx0 = txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap(); + let tx1 = txq.import(b.tx().nonce(1).gas_price(5).new()).unwrap(); + let tx2 = txq.import(b.tx().nonce(2).new()).unwrap(); + let tx3 = txq.import(b.tx().nonce(3).gas_price(4).new()).unwrap(); + //gap + txq.import(b.tx().nonce(5).new()).unwrap(); + + let tx5 = txq.import(b.tx().sender(1).nonce(0).new()).unwrap(); + let tx6 = txq.import(b.tx().sender(1).nonce(1).new()).unwrap(); + let tx7 = txq.import(b.tx().sender(1).nonce(2).new()).unwrap(); + let tx8 = txq.import(b.tx().sender(1).nonce(3).gas_price(4).new()).unwrap(); + // gap + txq.import(b.tx().sender(1).nonce(5).new()).unwrap(); + + let tx9 = txq.import(b.tx().sender(2).nonce(0).new()).unwrap(); + assert_eq!(txq.light_status().transaction_count, 11); + assert_eq!(txq.status(NonceReady::default()), Status { + stalled: 0, + pending: 9, + future: 2, + }); + assert_eq!(txq.status(NonceReady::new(1)), Status { + stalled: 3, + pending: 6, + future: 2, + }); + + // when + let all: Vec<_> = txq.unordered_pending(NonceReady::default()).collect(); + + let chain1 = vec![tx0, tx1, tx2, tx3]; + let chain2 = vec![tx5, tx6, tx7, tx8]; + let chain3 = vec![tx9]; + + assert_eq!(all.len(), chain1.len() + chain2.len() + chain3.len()); + + let mut options = vec![ + vec![chain1.clone(), chain2.clone(), chain3.clone()], + vec![chain2.clone(), chain1.clone(), chain3.clone()], + vec![chain2.clone(), chain3.clone(), chain1.clone()], + vec![chain3.clone(), chain2.clone(), chain1.clone()], + vec![chain3.clone(), chain1.clone(), chain2.clone()], + vec![chain1.clone(), chain3.clone(), chain2.clone()], + ].into_iter().map(|mut v| { + let mut first = v.pop().unwrap(); + for mut x in v { + first.append(&mut x); + } + first + }); + + assert!(options.any(|opt| all == opt)); +} + #[test] fn should_update_scoring_correctly() { // given @@ -445,9 +514,108 @@ fn should_return_worst_transaction() { // when txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap(); + txq.import(b.tx().sender(1).nonce(0).gas_price(4).new()).unwrap(); + + // then + assert_eq!(txq.worst_transaction().unwrap().gas_price, 4.into()); +} + +#[test] +fn should_return_is_full() { + // given + let b = TransactionBuilder::default(); + let mut txq = TestPool::with_limit(2); + assert!(!txq.is_full()); + + // when + txq.import(b.tx().nonce(0).gas_price(110).new()).unwrap(); + assert!(!txq.is_full()); + + txq.import(b.tx().sender(1).nonce(0).gas_price(100).new()).unwrap(); + + // then + 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!(txq.worst_transaction().is_some()); + 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, + }); +} + +#[test] +fn should_import_even_if_sender_limit_is_reached() { + // given + let b = TransactionBuilder::default(); + let mut txq = TestPool::with_scoring(DummyScoring::always_insert(), Options { + max_count: 1, + max_per_sender: 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, + }); } mod listener { @@ -490,7 +658,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() @@ -528,7 +696,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(); @@ -547,7 +715,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(); @@ -565,7 +733,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(); @@ -578,4 +746,3 @@ mod listener { assert_eq!(*results.borrow(), &["added", "added", "mined", "mined"]); } } - diff --git a/transaction-pool/src/tests/tx_builder.rs b/transaction-pool/src/tests/tx_builder.rs index 88a881aca8a4a4828df49991327d13335df62df7..9478d417a2eb268e29ee3b84d0b17d81e311b9f9 100644 --- a/transaction-pool/src/tests/tx_builder.rs +++ b/transaction-pool/src/tests/tx_builder.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/transaction-pool/src/transactions.rs b/transaction-pool/src/transactions.rs index f1a91ff4f83767bd49018a73af7a5680187ce463..96fe2e91bc9fe4a36907293841f734f2cc931c16 100644 --- a/transaction-pool/src/transactions.rs +++ b/transaction-pool/src/transactions.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -95,7 +95,7 @@ impl> Transactions { fn push_cheapest_transaction(&mut self, tx: Transaction, scoring: &S, max_count: usize) -> AddResult, S::Score> { let index = self.transactions.len(); - if index == max_count { + if index == max_count && !scoring.should_ignore_sender_limit(&tx) { let min_score = self.scores[index - 1].clone(); AddResult::TooCheapToEnter(tx, min_score) } else { diff --git a/transaction-pool/src/verifier.rs b/transaction-pool/src/verifier.rs index e55a17e91198da8befbcd13e45deb2e864e6f08a..312a3eae3cf58cd82c27ffc9384884ac493661d3 100644 --- a/transaction-pool/src/verifier.rs +++ b/transaction-pool/src/verifier.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/updater/Cargo.toml b/updater/Cargo.toml index d76db6ec0ea1cfb0f8875a877902f4b92a2abf1c..b7c1aded9a2c3b2585a22fa356b0c0fa91b30eae 100644 --- a/updater/Cargo.toml +++ b/updater/Cargo.toml @@ -6,7 +6,7 @@ license = "GPL-3.0" authors = ["Parity Technologies "] [dependencies] -keccak-hash = { path = "../util/hash" } +keccak-hash = { git = "https://github.com/paritytech/parity-common" } lazy_static = "1.0" log = "0.3" ethabi = "5.1" @@ -15,15 +15,22 @@ ethabi-contract = "5.0" target_info = "0.1" semver = "0.9" ethcore = { path = "../ethcore" } -ethcore-bytes = { path = "../util/bytes" } +parity-bytes = { git = "https://github.com/paritytech/parity-common" } 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" } +path = { git = "https://github.com/paritytech/parity-common" } rand = "0.4" [dev-dependencies] +ethcore = { path = "../ethcore", features = ["test-helpers"] } tempdir = "0.3" matches = "0.1" + +[features] +# hardcode version number 1.3.7 of parity to force an update +# in order to manually test that parity fall-over to the local version +# in case of invalid or deprecated command line arguments are entered +test-updater = [] diff --git a/updater/src/lib.rs b/updater/src/lib.rs index 67525aa4b27123e23ec8e1bce14629317bf2b85b..c50e0fee6e0da744c80ce002ef393948131799b7 100644 --- a/updater/src/lib.rs +++ b/updater/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -16,9 +16,11 @@ //! Updater for Parity executables +#![warn(missing_docs)] + extern crate ethabi; extern crate ethcore; -extern crate ethcore_bytes as bytes; +extern crate parity_bytes as bytes; extern crate ethcore_sync as sync; extern crate ethereum_types; extern crate keccak_hash as hash; diff --git a/updater/src/service.rs b/updater/src/service.rs index b025eb42eaf455a08caa36f70b3d471e8d3b9b7d..1cf35d4ea67c41e716a3e37ad1a2706b509bdc3c 100644 --- a/updater/src/service.rs +++ b/updater/src/service.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -16,6 +16,7 @@ use types::{CapState, ReleaseInfo, OperationsInfo, VersionInfo}; +/// Parity updater service trait pub trait Service: Send + Sync { /// Is the currently running client capable of supporting the current chain? /// We default to true if there's no clear information. @@ -35,4 +36,3 @@ pub trait Service: Send + Sync { /// Information gathered concerning the release. fn info(&self) -> Option; } - diff --git a/updater/src/types/all.rs b/updater/src/types/all.rs index 7079fb8dedb83dd2b70bd784064428b4a1ac91f1..9dd782683d6dda83dbf9bbd8a8e67ce1c42748c0 100644 --- a/updater/src/types/all.rs +++ b/updater/src/types/all.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/updater/src/types/mod.rs b/updater/src/types/mod.rs index b6d3c6025456940d0c06eb9c0f57a12a14e4e7d8..8fdbcf169df85a9ef8ef38b12060f9c78c107aca 100644 --- a/updater/src/types/mod.rs +++ b/updater/src/types/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -23,4 +23,3 @@ mod version_info; pub use self::all::{ReleaseInfo, OperationsInfo, CapState}; pub use self::release_track::ReleaseTrack; pub use self::version_info::VersionInfo; - diff --git a/updater/src/types/release_track.rs b/updater/src/types/release_track.rs index a1f646805a3ef8b9826b41859d7a8f13bd00bc1e..eefe18d9f20c742e0f181d45f1aba776a45d882e 100644 --- a/updater/src/types/release_track.rs +++ b/updater/src/types/release_track.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -70,7 +70,6 @@ impl From for ReleaseTrack { } } - impl From for u8 { fn from(rt: ReleaseTrack) -> Self { rt as u8 diff --git a/updater/src/types/version_info.rs b/updater/src/types/version_info.rs index 4409153e2ad2e9d4833b4998f126e3805b00b7e8..df2026b28c31cedb21dda939329a9f4f40539639 100644 --- a/updater/src/types/version_info.rs +++ b/updater/src/types/version_info.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -55,14 +55,14 @@ impl VersionInfo { let t = track.into(); VersionInfo { version: Version { - major: (semver >> 16) as u64, - minor: ((semver >> 8) & 0xff) as u64, - patch: (semver & 0xff) as u64, + major: u64::from(semver >> 16), + minor: u64::from((semver >> 8) & 0xff), + patch: u64::from(semver & 0xff), build: vec![], pre: vec![], }, track: t, - hash: hash, + hash, } } } diff --git a/updater/src/updater.rs b/updater/src/updater.rs index f8a98f3b0f432d3f13f2d84e932b19ec63f570bf..a3ed413c44ae7d7d21d4aa79c4935f7c463c8bc7 100644 --- a/updater/src/updater.rs +++ b/updater/src/updater.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -27,15 +27,16 @@ use target_info::Target; use bytes::Bytes; use ethcore::BlockNumber; -use ethcore::filter::Filter; use ethcore::client::{BlockId, BlockChainClient, ChainNotify, ChainRoute}; +use ethcore::filter::Filter; use ethereum_types::H256; -use sync::{SyncProvider}; use hash_fetch::{self as fetch, HashFetch}; use path::restrict_permissions_owner; use service::Service; +use sync::{SyncProvider}; use types::{ReleaseInfo, OperationsInfo, CapState, VersionInfo, ReleaseTrack}; use version; +use semver::Version; use_contract!(operations_contract, "Operations", "res/operations.json"); @@ -155,7 +156,7 @@ pub struct Updater, } -const CLIENT_ID: &'static str = "parity"; +const CLIENT_ID: &str = "parity"; lazy_static! { static ref CLIENT_ID_HASH: H256 = CLIENT_ID.as_bytes().into(); @@ -189,7 +190,7 @@ pub trait OperationsClient: Send + Sync + 'static { fn release_block_number(&self, from: BlockNumber, release: &ReleaseInfo) -> Option; } -/// OperationsClient that delegates calls to the operations contract. +/// `OperationsClient` that delegates calls to the operations contract. pub struct OperationsContractClient { operations_contract: operations_contract::Operations, client: Weak, @@ -267,7 +268,7 @@ impl OperationsClient for OperationsContractClient { // get the release info for the latest version in track let in_track = self.release_info(latest_in_track, &do_call)?; let mut in_minor = Some(in_track.clone()); - const PROOF: &'static str = "in_minor initialised and assigned with Some; loop breaks if None assigned; qed"; + const PROOF: &str = "in_minor initialized and assigned with Some; loop breaks if None assigned; qed"; // if the minor version has changed, let's check the minor version on a different track while in_minor.as_ref().expect(PROOF).version.version.minor != this.version.minor { @@ -308,7 +309,7 @@ impl OperationsClient for OperationsContractClient { from_block: BlockId::Number(from), to_block: BlockId::Latest, address: Some(vec![address]), - topics: topics, + topics, limit: None, }; @@ -333,7 +334,7 @@ pub trait TimeProvider: Send + Sync + 'static { fn now(&self) -> Instant; } -/// TimeProvider implementation that delegates calls to std::time. +/// `TimeProvider` implementation that delegates calls to `std::time`. pub struct StdTimeProvider; impl TimeProvider for StdTimeProvider { @@ -349,7 +350,7 @@ pub trait GenRange: Send + Sync + 'static { fn gen_range(&self, low: u64, high: u64) -> u64; } -/// GenRange implementation that uses a rand::thread_rng for randomness. +/// `GenRange` implementation that uses a `rand::thread_rng` for randomness. pub struct ThreadRngGenRange; impl GenRange for ThreadRngGenRange { @@ -359,14 +360,15 @@ impl GenRange for ThreadRngGenRange { } impl Updater { + /// `Updater` constructor pub fn new( - client: Weak, - sync: Weak, + client: &Weak, + sync: &Weak, update_policy: UpdatePolicy, fetcher: fetch::Client, ) -> Arc { let r = Arc::new(Updater { - update_policy: update_policy, + update_policy, weak_self: Mutex::new(Default::default()), client: client.clone(), sync: Some(sync.clone()), @@ -375,12 +377,21 @@ impl Updater { operations_contract::Operations::default(), client.clone()), exit_handler: Mutex::new(None), - this: VersionInfo::this(), + this: if cfg!(feature = "test-updater") { + VersionInfo { + track: ReleaseTrack::Stable, + version: Version::new(1, 3, 7), + hash: 0.into(), + } + } else { + VersionInfo::this() + }, time_provider: StdTimeProvider, rng: ThreadRngGenRange, state: Mutex::new(Default::default()), }); *r.weak_self.lock() = Arc::downgrade(&r); + r.poll(); r } @@ -447,7 +458,7 @@ impl Updater { - let delay = 2usize.pow(retries) as u64; + let delay = 2_usize.pow(retries) as u64; // cap maximum backoff to 1 day let delay = cmp::min(delay, 24 * 60 * 60); let backoff = (retries, self.time_provider.now() + Duration::from_secs(delay)); @@ -599,14 +610,19 @@ impl Updater Updater. - extern crate siphasher; use std::cmp; @@ -208,7 +207,6 @@ pub struct BloomJournal { pub entries: Vec<(usize, u64)>, } - #[cfg(test)] mod tests { use super::Bloom; diff --git a/util/bloomchain/.gitignore b/util/bloomchain/.gitignore deleted file mode 100644 index d4f917d3d50d56523378d8c6d57fbe0ad068937f..0000000000000000000000000000000000000000 --- a/util/bloomchain/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -target -Cargo.lock -*.swp diff --git a/util/bloomchain/Cargo.toml b/util/bloomchain/Cargo.toml deleted file mode 100644 index 6bcf6a9b1465e0a8a4732a6ac0e01ebc5682d1ad..0000000000000000000000000000000000000000 --- a/util/bloomchain/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -description = "Standalone blockchain bloom filter" -homepage = "https://github.com/debris/bloomchain" -name = "bloomchain" -version = "0.2.0" -authors = ["debris "] -license = "MIT" -keywords = ["ethereum", "ethcore", "bloom", "chain", "filter"] - -[dependencies] -ethbloom = "0.5" - -[dev-dependencies] -rustc-hex = "1.0" -rand = "0.4" diff --git a/util/bloomchain/README.md b/util/bloomchain/README.md deleted file mode 100644 index f5a1fafc8c1d58ff232b146db2b7a197717b5b26..0000000000000000000000000000000000000000 --- a/util/bloomchain/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# bloomchain -Standalone blockchain bloom filter. - -[![Build Status][travis-image]][travis-url] - -[travis-image]: https://travis-ci.org/paritytech/bloomchain.svg?branch=master -[travis-url]: https://travis-ci.org/paritytech/bloomchain - -[Documentation](http://paritytech.github.io/bloomchain/bloomchain/index.html) diff --git a/util/bloomchain/src/chain.rs b/util/bloomchain/src/chain.rs deleted file mode 100644 index ba7bc21b356aeaef02711ce5dbc8d821fc6a6858..0000000000000000000000000000000000000000 --- a/util/bloomchain/src/chain.rs +++ /dev/null @@ -1,158 +0,0 @@ -use std::collections::{HashMap, HashSet}; -use std::ops::Range; -use number::Number; -use position::{Position, Manager as PositionManager}; -use bloom::Bloom; -use filter::Filter; -use config::Config; -use database::BloomDatabase; - -/// Prepares all bloom database operations. -pub struct BloomChain<'a> { - positioner: PositionManager, - db: &'a BloomDatabase, -} - -impl<'a> BloomChain<'a> { - /// Creates new bloom chain. - pub fn new(config: Config, db: &'a BloomDatabase) -> Self { - let positioner = PositionManager::new(config.elements_per_index, config.levels); - - BloomChain { - positioner: positioner, - db: db, - } - } - - /// Internal function which does bloom search recursively. - fn blocks(&self, range: &Range, bloom: &Bloom, level: usize, offset: usize) -> Option> { - let index = self.positioner.position(offset, level); - - match self.db.bloom_at(&index) { - None => return None, - Some(level_bloom) => match level { - // if we are on the lowest level - 0 if level_bloom.contains_bloom(bloom) => return Some(vec![offset]), - // return None if current level doesnt contain given bloom - _ if !level_bloom.contains_bloom(bloom) => return None, - // continue processing && go down - _ => () - } - }; - - let level_size = self.positioner.level_size(level - 1); - let from_position = self.positioner.position(range.start, level - 1); - let to_position = self.positioner.position(range.end, level - 1); - let res: Vec = self.positioner.lower_level_positions(&index).into_iter() - // chose only blooms in range - .filter(|li| li.index >= from_position.index && li.index <= to_position.index) - // map them to offsets - .map(|li| li.index * level_size) - // get all blocks that may contain our bloom - // filter existing ones - .filter_map(|off| self.blocks(range, bloom, level - 1, off)) - // flatten nested structures - .flat_map(|v| v) - .collect(); - Some(res) - } - - /// Inserts the bloom at all filter levels. - pub fn insert(&self, number: Number, bloom: Bloom) -> HashMap { - let mut result: HashMap = HashMap::new(); - - for level in 0..self.positioner.levels() { - let position = self.positioner.position(number, level); - let new_bloom = match self.db.bloom_at(&position) { - Some(mut old_bloom) => { - old_bloom.accrue_bloom(&bloom); - old_bloom - }, - None => bloom.clone(), - }; - - result.insert(position, new_bloom); - } - - result - } - - /// Resets data in range. - /// Inserts new data. - /// Inserted data may exceed reseted range. - pub fn replace(&self, range: &Range, blooms: Vec) -> HashMap { - let mut result: HashMap = HashMap::new(); - - // insert all new blooms at level 0 - for (i, bloom) in blooms.iter().enumerate() { - result.insert(self.positioner.position(range.start + i, 0), bloom.clone()); - } - - // reset the rest of blooms - for reset_number in range.start + blooms.len()..(range.end + 1) { - result.insert(self.positioner.position(reset_number, 0), Bloom::default()); - } - - for level in 1..self.positioner.levels() { - for i in 0..blooms.len() { - - let index = self.positioner.position(range.start + i, level); - let new_bloom = { - // use new blooms before db blooms where necessary - let bloom_at = | index | { result.get(&index).cloned().or_else(|| self.db.bloom_at(&index)) }; - - self.positioner.lower_level_positions(&index) - .into_iter() - // get blooms - // filter existing ones - .filter_map(bloom_at) - // BitOr all of them - .fold(Bloom::default(), |mut acc, bloom| { - acc.accrue_bloom(&bloom); - acc - }) - }; - - result.insert(index, new_bloom); - } - } - - result - } - - /// Returns all numbers with given bloom. - pub fn with_bloom(&self, range: &Range, bloom: &Bloom) -> Vec { - let mut result = vec![]; - // lets start from highest level - let max_level = self.positioner.max_level(); - let level_size = self.positioner.level_size(max_level); - let from_position = self.positioner.position(range.start, max_level); - let to_position = self.positioner.position(range.end, max_level); - - for index in from_position.index..to_position.index + 1 { - // offset will be used to calculate where we are right now - let offset = level_size * index; - - // go doooown! - if let Some(blocks) = self.blocks(range, bloom, max_level, offset) { - result.extend(blocks); - } - } - - result - } - - /// Filter the chain returing all numbers matching the filter. - pub fn filter(&self, filter: &Filter) -> Vec { - let range = filter.range(); - let mut blocks = filter.bloom_possibilities() - .into_iter() - .flat_map(|ref bloom| self.with_bloom(&range, bloom)) - .collect::>() - .into_iter() - .collect::>(); - - blocks.sort(); - blocks - } -} diff --git a/util/bloomchain/src/config.rs b/util/bloomchain/src/config.rs deleted file mode 100644 index 3e729922a17962015a8b89d42377d17ad61b01be..0000000000000000000000000000000000000000 --- a/util/bloomchain/src/config.rs +++ /dev/null @@ -1,17 +0,0 @@ -/// `BloomChain` configuration. -#[derive(Debug, PartialEq, Clone, Copy)] -pub struct Config { - /// Number of levels. - pub levels: usize, - /// Number of elements in a single index. - pub elements_per_index: usize, -} - -impl Default for Config { - fn default() -> Self { - Config { - levels: 3, - elements_per_index: 16, - } - } -} diff --git a/util/bloomchain/src/database.rs b/util/bloomchain/src/database.rs deleted file mode 100644 index 9aba41e7c6427c977340986775263e66fbb4fd10..0000000000000000000000000000000000000000 --- a/util/bloomchain/src/database.rs +++ /dev/null @@ -1,7 +0,0 @@ -use position::Position; -use bloom::Bloom; - -/// Readonly `Bloom` database. -pub trait BloomDatabase { - fn bloom_at(&self, position: &Position) -> Option; -} diff --git a/util/bloomchain/src/filter.rs b/util/bloomchain/src/filter.rs deleted file mode 100644 index 06d657ba4427483c5d91c5eb1a82f5068ee6e7df..0000000000000000000000000000000000000000 --- a/util/bloomchain/src/filter.rs +++ /dev/null @@ -1,11 +0,0 @@ -use std::ops::Range; -use bloom::Bloom; -use number::Number; - -/// Should be used to filter blocks from `BloomChain`. -pub trait Filter { - /// All bloom possibilities that we are searching for. - fn bloom_possibilities(&self) -> Vec; - /// Range of search. - fn range(&self) -> Range; -} diff --git a/util/bloomchain/src/group/bridge.rs b/util/bloomchain/src/group/bridge.rs deleted file mode 100644 index b01650157c6326755b9df6d6f7baf1a9964d3e54..0000000000000000000000000000000000000000 --- a/util/bloomchain/src/group/bridge.rs +++ /dev/null @@ -1,31 +0,0 @@ -use bloom::Bloom; -use config::Config; -use database::BloomDatabase; -use position::Position; -use group::position::Manager as PositionManager; -use super::BloomGroupDatabase; - -/// Bridge between `BloomDatabase` and `BloomGroupDatabase`. -pub struct GroupDatabaseBridge<'a> { - positioner: PositionManager, - db: &'a BloomGroupDatabase, -} - -impl<'a> GroupDatabaseBridge<'a> { - pub fn new(config: Config, db: &'a BloomGroupDatabase) -> Self { - let positioner = PositionManager::new(config.elements_per_index); - - GroupDatabaseBridge { - positioner: positioner, - db: db, - } - } -} - -impl<'a> BloomDatabase for GroupDatabaseBridge<'a> { - fn bloom_at(&self, position: &Position) -> Option { - let position = self.positioner.position(position); - self.db.blooms_at(&position.group) - .and_then(|group| group.blooms.into_iter().nth(position.number)) - } -} diff --git a/util/bloomchain/src/group/chain.rs b/util/bloomchain/src/group/chain.rs deleted file mode 100644 index cfd7796f4d08d6fff46d708dbd478ea9b0ff5d57..0000000000000000000000000000000000000000 --- a/util/bloomchain/src/group/chain.rs +++ /dev/null @@ -1,70 +0,0 @@ -use std::collections::HashMap; -use std::ops::Range; -use bloom::Bloom; -use chain::BloomChain; -use config::Config; -use number::Number; -use filter::Filter; -use position::Position as BloomPosition; -use super::{GroupDatabaseBridge, BloomGroupDatabase, BloomGroup, GroupPosition}; -use super::position::Manager as PositionManager; - -/// Performs all bloom database operations using `BloomGroup`s. -pub struct BloomGroupChain<'a> { - config: Config, - db: &'a BloomGroupDatabase, - bridge: GroupDatabaseBridge<'a>, -} - -impl<'a> BloomGroupChain<'a> { - pub fn new(config: Config, db: &'a BloomGroupDatabase) -> Self { - let bridge = GroupDatabaseBridge::new(config, db); - - BloomGroupChain { - config: config, - db: db, - bridge: bridge, - } - } - - fn group_blooms(&self, blooms: HashMap) -> HashMap { - let positioner = PositionManager::new(self.config.elements_per_index); - blooms.into_iter() - .fold(HashMap::new(), | mut acc, (position, bloom) | { - { - let position = positioner.position(&position); - let group = acc - .entry(position.group.clone()) - .or_insert_with(|| self.db - .blooms_at(&position.group) - .unwrap_or_else(|| BloomGroup::new(self.config.elements_per_index)) - ); - assert_eq!(self.config.elements_per_index, group.blooms.len()); - group.blooms[position.number] = bloom; - } - acc - }) - } - - pub fn insert(&self, number: Number, bloom: Bloom) -> HashMap { - let bloom_chain = BloomChain::new(self.config, &self.bridge); - let modified_blooms = bloom_chain.insert(number, bloom); - self.group_blooms(modified_blooms) - } - - pub fn replace(&self, range: &Range, blooms: Vec) -> HashMap { - let bloom_chain = BloomChain::new(self.config, &self.bridge); - let modified_blooms = bloom_chain.replace(range, blooms); - self.group_blooms(modified_blooms) - } - - pub fn with_bloom(&self, range: &Range, bloom: &Bloom) -> Vec { - let bloom_chain = BloomChain::new(self.config, &self.bridge); - bloom_chain.with_bloom(range, bloom) - } - - pub fn filter(&self, filter: &Filter) -> Vec { - let bloom_chain = BloomChain::new(self.config, &self.bridge); - bloom_chain.filter(filter) - } -} diff --git a/util/bloomchain/src/group/database.rs b/util/bloomchain/src/group/database.rs deleted file mode 100644 index 494184f3ebcff6d80616b0f6059840f091946249..0000000000000000000000000000000000000000 --- a/util/bloomchain/src/group/database.rs +++ /dev/null @@ -1,6 +0,0 @@ -use group::{GroupPosition, BloomGroup}; - -/// Readonly `BloomGroup` database. -pub trait BloomGroupDatabase { - fn blooms_at(&self, position: &GroupPosition) -> Option; -} diff --git a/util/bloomchain/src/group/group.rs b/util/bloomchain/src/group/group.rs deleted file mode 100644 index 084c8f8e48e044d99f4919178af42d0cb6cb6deb..0000000000000000000000000000000000000000 --- a/util/bloomchain/src/group/group.rs +++ /dev/null @@ -1,17 +0,0 @@ -use bloom::Bloom; - -/// Group of blooms that are in the same index. -#[derive(Debug, Clone)] -pub struct BloomGroup { - pub blooms: Vec, -} - -impl BloomGroup { - pub fn new(size: usize) -> Self { - let blooms = (0..size).into_iter().map(|_| Bloom::default()).collect(); - - BloomGroup { - blooms: blooms - } - } -} diff --git a/util/bloomchain/src/group/mod.rs b/util/bloomchain/src/group/mod.rs deleted file mode 100644 index b6cabf628fca25b61594e1bf35371140dd452f21..0000000000000000000000000000000000000000 --- a/util/bloomchain/src/group/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! Bloom grouping. -//! -//! Optimization gathering together blooms that are in the same index and are likely to be retrived together. - -mod bridge; -mod chain; -mod database; -mod group; -mod position; - -pub use self::bridge::GroupDatabaseBridge; -pub use self::chain::BloomGroupChain; - -pub use self::database::BloomGroupDatabase; -pub use self::group::BloomGroup; -pub use self::position::GroupPosition; diff --git a/util/bloomchain/src/group/position/manager.rs b/util/bloomchain/src/group/position/manager.rs deleted file mode 100644 index 611a5bb784c32c0929ff128b71b8a4ab8fa2a1a5..0000000000000000000000000000000000000000 --- a/util/bloomchain/src/group/position/manager.rs +++ /dev/null @@ -1,28 +0,0 @@ -use super::{Position, GroupPosition}; -use position::Position as BloomPosition; - -pub struct Manager { - index_size: usize -} - -impl Manager { - pub fn new(index_size: usize) -> Self { - Manager { - index_size: index_size - } - } - - pub fn group_position(&self, pos: &BloomPosition) -> GroupPosition { - GroupPosition { - level: pos.level, - index: pos.index / self.index_size, - } - } - - pub fn position(&self, pos: &BloomPosition) -> Position { - Position { - group: self.group_position(pos), - number: pos.index % self.index_size, - } - } -} diff --git a/util/bloomchain/src/group/position/mod.rs b/util/bloomchain/src/group/position/mod.rs deleted file mode 100644 index fc95de4dd057bf01b783809f33f3b181e14ace3f..0000000000000000000000000000000000000000 --- a/util/bloomchain/src/group/position/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod position; -mod manager; - -pub use self::position::{Position, GroupPosition}; -pub use self::manager::Manager; diff --git a/util/bloomchain/src/group/position/position.rs b/util/bloomchain/src/group/position/position.rs deleted file mode 100644 index 88f26d69abaa76928d01309ad65b4ed0740c9847..0000000000000000000000000000000000000000 --- a/util/bloomchain/src/group/position/position.rs +++ /dev/null @@ -1,17 +0,0 @@ -/// Uniquely identifies bloom group position. -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub struct GroupPosition { - /// Bloom level. - pub level: usize, - /// Index of the group. - pub index: usize, -} - -/// Uniquely identifies bloom position including the position in the group. -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub struct Position { - /// Group position. - pub group: GroupPosition, - /// Number in group. - pub number: usize, -} diff --git a/util/bloomchain/src/lib.rs b/util/bloomchain/src/lib.rs deleted file mode 100644 index 997ae083912ed3442a0bfb39cd874e11d1ad1a1e..0000000000000000000000000000000000000000 --- a/util/bloomchain/src/lib.rs +++ /dev/null @@ -1,17 +0,0 @@ -extern crate ethbloom as bloom; - -mod chain; -mod config; -mod database; -pub mod group; -mod number; -mod position; -mod filter; - -pub use bloom::{Bloom, BloomRef, Input}; -pub use chain::BloomChain; -pub use config::Config; -pub use database::BloomDatabase; -pub use number::Number; -pub use position::Position; -pub use filter::Filter; diff --git a/util/bloomchain/src/number.rs b/util/bloomchain/src/number.rs deleted file mode 100644 index 3ff82f195731e52fea673d65a29c13461929ff08..0000000000000000000000000000000000000000 --- a/util/bloomchain/src/number.rs +++ /dev/null @@ -1,2 +0,0 @@ -/// Represents block number. -pub type Number = usize; diff --git a/util/bloomchain/src/position/manager.rs b/util/bloomchain/src/position/manager.rs deleted file mode 100644 index a405878ab52eeb3692e002880a132bac7306444e..0000000000000000000000000000000000000000 --- a/util/bloomchain/src/position/manager.rs +++ /dev/null @@ -1,142 +0,0 @@ -//! Simplifies working with bloom indexes. - -use super::Position; - -/// Simplifies working with bloom indexes. -pub struct Manager { - index_size: usize, - level_sizes: Vec, -} - -impl Manager { - /// Creates new indexer. - pub fn new(index_size: usize, levels: usize) -> Self { - if levels == 0 { - panic!("Manager requires at least 1 level."); - } - - let mut level_sizes = vec![1]; - level_sizes.extend_from_slice(&(1..).into_iter() - .scan(1, |acc, _| { - *acc = *acc * index_size; - Some(*acc) - }) - .take(levels - 1) - .collect::>()); - - Manager { - index_size: index_size, - level_sizes: level_sizes, - } - } - - /// Unsafely get level size. - pub fn level_size(&self, level: usize) -> usize { - self.level_sizes[level as usize] - } - - /// Converts block number and level to `Position`. - pub fn position(&self, block_number: usize, level: usize) -> Position { - Position { - level: level, - index: block_number / self.level_size(level), - } - } - - /// Return bloom which are dependencies for given index. - /// - /// Bloom indexes are ordered from lowest to highest. - pub fn lower_level_positions(&self, index: &Position) -> Vec { - // this is the lowest level - if index.level == 0 { - return vec![]; - } - - let new_level = index.level - 1; - let offset = self.index_size * index.index; - - (0..self.index_size) - .map(|i| Position { - level: new_level, - index: offset + i - }) - .collect() - } - - /// Return number of levels. - pub fn levels(&self) -> usize { - self.level_sizes.len() - } - - /// Returns max indexer level. - pub fn max_level(&self) -> usize { - self.level_sizes.len() - 1 - } -} - -#[cfg(test)] -mod tests { - use position::Position; - use super::*; - #[test] - fn test_level_size() { - let indexer = Manager::new(16, 3); - assert_eq!(indexer.level_size(0), 1); - assert_eq!(indexer.level_size(1), 16); - assert_eq!(indexer.level_size(2), 256); - } - - #[test] - fn test_position() { - let indexer = Manager::new(16, 3); - - let bi0 = indexer.position(0, 0); - assert_eq!(bi0.level, 0); - assert_eq!(bi0.index, 0); - - let bi1 = indexer.position(1, 0); - assert_eq!(bi1.level, 0); - assert_eq!(bi1.index, 1); - - let bi2 = indexer.position(2, 0); - assert_eq!(bi2.level, 0); - assert_eq!(bi2.index, 2); - - let bi3 = indexer.position(3, 1); - assert_eq!(bi3.level, 1); - assert_eq!(bi3.index, 0); - - let bi4 = indexer.position(15, 1); - assert_eq!(bi4.level, 1); - assert_eq!(bi4.index, 0); - - let bi5 = indexer.position(16, 1); - assert_eq!(bi5.level, 1); - assert_eq!(bi5.index, 1); - - let bi6 = indexer.position(255, 2); - assert_eq!(bi6.level, 2); - assert_eq!(bi6.index, 0); - - let bi7 = indexer.position(256, 2); - assert_eq!(bi7.level, 2); - assert_eq!(bi7.index, 1); - } - - #[test] - fn test_lower_level_positions() { - let indexer = Manager::new(16, 3); - - let bi = indexer.position(256, 2); - assert_eq!(bi.level, 2); - assert_eq!(bi.index, 1); - - let mut ebis = vec![]; - for i in 16..32 { - ebis.push(Position { level: 1, index: i}); - } - - let bis = indexer.lower_level_positions(&bi); - assert_eq!(ebis, bis); - } -} diff --git a/util/bloomchain/src/position/mod.rs b/util/bloomchain/src/position/mod.rs deleted file mode 100644 index 4fa736a1636bd772393453b124bc20f12b2c8b03..0000000000000000000000000000000000000000 --- a/util/bloomchain/src/position/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod position; -pub mod manager; - -pub use self::position::Position; -pub use self::manager::Manager; diff --git a/util/bloomchain/src/position/position.rs b/util/bloomchain/src/position/position.rs deleted file mode 100644 index 32845cbcc5db591a8098d5755f6c16cea58d40ea..0000000000000000000000000000000000000000 --- a/util/bloomchain/src/position/position.rs +++ /dev/null @@ -1,8 +0,0 @@ -/// Uniquely identifies bloom position. -#[derive(Debug, PartialEq, Eq, Hash)] -pub struct Position { - /// Bloom level. - pub level: usize, - /// Index of the bloom. - pub index: usize, -} diff --git a/util/bloomchain/tests/bloomchain.rs b/util/bloomchain/tests/bloomchain.rs deleted file mode 100644 index 4a77407a7a2b3eee642c27f2c28c00457abc2d6c..0000000000000000000000000000000000000000 --- a/util/bloomchain/tests/bloomchain.rs +++ /dev/null @@ -1,170 +0,0 @@ -extern crate bloomchain; -extern crate rustc_hex; - -mod util; - -use bloomchain::{Bloom, BloomChain, Config}; -use util::{BloomMemoryDatabase, FromHex, for_each_bloom, generate_n_random_blooms}; - -#[test] -fn simple_bloom_search() { - let config = Config::default(); - let mut db = BloomMemoryDatabase::default(); - let bloom = Bloom::from_hex("00000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000008000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - - let modified_blooms = { - let chain = BloomChain::new(config, &db); - let block_number = 23; - chain.insert(block_number, bloom.clone()) - }; - - // number of modified blooms should always be equal number of levels - assert_eq!(modified_blooms.len(), config.levels); - db.insert_blooms(modified_blooms); - - let chain = BloomChain::new(config, &db); - assert_eq!(chain.with_bloom(&(0..100), &bloom), vec![23]); - assert_eq!(chain.with_bloom(&(0..22), &bloom), vec![]); - assert_eq!(chain.with_bloom(&(23..23), &bloom), vec![23]); - assert_eq!(chain.with_bloom(&(24..100), &bloom), vec![]); -} - -#[test] -fn partly_matching_bloom_searach() { - let config = Config::default(); - let mut db = BloomMemoryDatabase::default(); - let bloom0 = Bloom::from_hex("10100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - let bloom1 = Bloom::from_hex("11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - let bloom2 = Bloom::from_hex("10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - - let modified_blooms_0 = { - let chain = BloomChain::new(config, &db); - let block_number = 14; - chain.insert(block_number, bloom0) - }; - - db.insert_blooms(modified_blooms_0); - - let modified_blooms_1 = { - let chain = BloomChain::new(config, &db); - let block_number = 15; - chain.insert(block_number, bloom1) - }; - - db.insert_blooms(modified_blooms_1); - - - let chain = BloomChain::new(config, &db); - assert_eq!(chain.with_bloom(&(0..100), &bloom2), vec![14, 15]); -} - -#[test] -fn bloom_replace() { - let config = Config::default(); - let mut db = BloomMemoryDatabase::default(); - let bloom0 = Bloom::from_hex("10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - let bloom1 = Bloom::from_hex("01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - let bloom2 = Bloom::from_hex("00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - let bloom3 = Bloom::from_hex("00010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - let bloom4 = Bloom::from_hex("00001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - let bloom5 = Bloom::from_hex("00000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - - let modified_blooms_0 = { - let chain = BloomChain::new(config, &db); - let block_number = 14; - chain.insert(block_number, bloom0.clone()) - }; - - db.insert_blooms(modified_blooms_0); - - let modified_blooms_1 = { - let chain = BloomChain::new(config, &db); - let block_number = 15; - chain.insert(block_number, bloom1.clone()) - }; - - db.insert_blooms(modified_blooms_1); - - let modified_blooms_2 = { - let chain = BloomChain::new(config, &db); - let block_number = 16; - chain.insert(block_number, bloom2.clone()) - }; - - db.insert_blooms(modified_blooms_2); - - let modified_blooms_3 = { - let chain = BloomChain::new(config, &db); - let block_number = 17; - chain.insert(block_number, bloom3.clone()) - }; - - db.insert_blooms(modified_blooms_3); - - - let reset_modified_blooms = { - let chain = BloomChain::new(config, &db); - chain.replace(&(15..17), vec![bloom4.clone(), bloom5.clone()]) - }; - - db.insert_blooms(reset_modified_blooms); - - let chain = BloomChain::new(config, &db); - assert_eq!(chain.with_bloom(&(0..100), &bloom0), vec![14]); - assert_eq!(chain.with_bloom(&(0..100), &bloom1), vec![]); - assert_eq!(chain.with_bloom(&(0..100), &bloom2), vec![]); - assert_eq!(chain.with_bloom(&(0..100), &bloom3), vec![]); - assert_eq!(chain.with_bloom(&(0..100), &bloom4), vec![15]); - assert_eq!(chain.with_bloom(&(0..100), &bloom5), vec![16]); -} - -#[test] -fn file_test_bloom_search() { - let config = Config::default(); - let mut db = BloomMemoryDatabase::default(); - let blooms_file = include_bytes!("data/blooms.txt"); - - for_each_bloom(blooms_file, | block_number, bloom | { - let modified_blooms = { - let chain = BloomChain::new(config, &db); - chain.insert(block_number, bloom) - }; - - // number of modified blooms should always be equal number of levels - assert_eq!(modified_blooms.len(), config.levels); - db.insert_blooms(modified_blooms); - }); - - for_each_bloom(blooms_file, | block_number, bloom | { - let chain = BloomChain::new(config, &db); - let blocks = chain.with_bloom(&(block_number..block_number), &bloom); - assert_eq!(blocks.len(), 1); - assert_eq!(blocks[0], block_number); - }); -} - -#[test] -fn random_bloom_replacement() { - let insertions = 10_000; - - let config = Config::default(); - let mut db = BloomMemoryDatabase::default(); - let blooms = generate_n_random_blooms(insertions); - - for (i, bloom) in blooms.iter().enumerate() { - - let modified_blooms = { - let chain = BloomChain::new(config, &db); - chain.replace(&(i..i), vec![bloom.clone()]) - }; - - db.insert_blooms(modified_blooms); - } - - for (i, bloom) in blooms.iter().enumerate() { - let chain = BloomChain::new(config, &db); - let blocks = chain.with_bloom(&(i..i), bloom); - assert_eq!(blocks.len(), 1); - assert_eq!(blocks[0], i); - } -} diff --git a/util/bloomchain/tests/data/blooms.txt b/util/bloomchain/tests/data/blooms.txt deleted file mode 100644 index 204186ec34923b4b61ab6a5f03064591dcd01d4b..0000000000000000000000000000000000000000 --- a/util/bloomchain/tests/data/blooms.txt +++ /dev/null @@ -1,739 +0,0 @@ -300054 0x00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -300059 0x00000020000000000000000000000000000000000000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000002000 -300221 0x00000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000008000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -301826 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -303166 0x00000000000000000000000000000000000000001000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000808000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000020000000001000000000000000000000000000000000000000000000000000000000000000000 -303345 0x00000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000008000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -303379 0x00000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000800000000000000001000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000080000000006000008000000000000000000080000000000000000000000000000000000000000001000000000000000000000008000000000400000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000800000000000000000000000000000000000002004000000000000 -303388 0x00000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000800000040000000001000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000080000000006001008000000000000008000080000000000000000000000000000000000000000001000000000000000000000008000000000400000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000800000000000000040000000000000000000002004000000000000 -303621 0x00000000000000000000008000000000200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000080000000000000000000000080000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000 -303670 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000400200000000000000 -303674 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000040000000000000000000000000000000000000000000000000000000000000000000000001000000000000200000000000000 -303683 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000400200000000000000 -303689 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000000400000000000000000000000000000000000000000000000000000000001000000000040200000000000000 -303692 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000400000000000000000000000000000000000000000000000000000000001000000000040200000000000000 -303716 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000040000000000000000000000000000000000000000000000000000000000000000000000001000000000000200000000000000 -303717 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000040000000000000000000000000000000000000000000000000000000000000000000000001000000000000200000000000000 -303748 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000400200000000000000 -303756 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000000400000000000000000000000000000000000000000000000000000000001000000000040200000000000000 -303758 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000400000000000000000000000000000000000000000000000000000000001000000000040200000000000000 -304090 0x00000000000000000000000000000000100000000000000000000000000000000000000000000000000200000000000000800000000000000000000000040000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000003000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000 -304095 0x04000000000000000000000000000000100000000000000000000000000000000000000000000000000200000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000 -304107 0x00000000000000000000000000000000100000000000000000000000000000000000000000000000000200000000000000800000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008800000000000000000400000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -304113 0x00000000000000000000000000000000100000000000000000000000000000000000000000000000000200000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000002000000000000000000000000000000000000000000000000003008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -304222 0x00000000000000000000000000000000100000000000000000000000000000000000000000000000000200000000000000800000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000800000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -304245 0x00000000000000000000000000000000100000000000000000000000000000000000000000000000000200000000000000800000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000080000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -304247 0x000000080000000000000000000000800000020000000000000000000000000000000000000000000202000000000000008000004004000000000000000000000000000000000000000000000200000000200000000080000000000000000000000004000000000000000000000000000000001040000000000000000000000000000004000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000c0002000000000000000000000000000000001000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -304312 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000040000000000000200000000000000000000000000000000000000000000000000000000000000000000000000 -304319 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000100000000000020000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000080000000000000000000000000008000000000000000000000000000000000008000000000000000000000000000000000000020000000000002000000000000000000040000000000000200000000000000000000000000000000000000000000000000000000000000000000000000 -304367 0x00000000000000000000001000000000000000000400020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000100000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -304375 0x00000000004000000000001000000000000000000400020000000800000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000020000000000000000000000000000000000000000000000000008000000000000010000000008000000000000000000000000000000000008000800000000000000000000000100000000000000000000000000000000000000000100000000000000002000000000002000000040010010000000000000000000000000000000000000000000000000000000000000000000000000000000000 -304407 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -304431 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -304433 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -304608 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000400000000000000000000040000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000 -304609 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000400000000000000000000040000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000 -304788 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -304794 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -304819 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -304835 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -304849 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -304856 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -304862 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -304872 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -304881 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -304902 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -304996 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -304999 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -305006 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -305010 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -305425 0x00000000004000000000000000000001000000000000020000000000000000000000000000000000000000000000000000000000008000000080000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010400000048000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000400000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -305445 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000080000100000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -305448 0x00000000004000000000000000000000000000000000020000000000000000000004000008000000000000000000000000000000000000000000000000000800000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000080000100000000002000000000000000000040000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 -305450 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000080000000000000000000000000000020000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000004000000000000000000000000000 -305452 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000002000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000080000000000000000000000000000020000000000000000000000000000000000000000000008002000000000000000000040000000000000000000000000400000000000000000000000000000000004000000000000000000000000000 -305454 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000001000000040000000000000000000000000000000000000000000000000000000000000000000000000840000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -305457 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -305463 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000200080000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -305464 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000008000000000000000000000000000000000240000000200480000000000000000000000000000000000000000000000000000002000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -305468 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008080000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000008800000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -305488 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000002000000000000008000000000000010000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -305492 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000008000000000000000000000000000000008040000000000000000000000000000002000000000001000000000000000000000000000400000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000200000000000000000000000000000000000000000000 -305501 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000008000000000000000000040000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000080000000000000 -305502 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000008000000000000008000000000000000000040000000001000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000080000000000000000000000000000000000010000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000080000000000000 -305510 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000044000004000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -305616 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -305620 0x0000000000400000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000040000000000000080000000000000000000000000000800000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000040000000001000000000a000000000000000010000000000000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -305622 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000080000000000000000000000000200000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000080000000000000 -305624 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000001000000000000000080000000000000000000000000200000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000004000000000000000000000000004000000000000000000000000000000000000080000000000000 -305626 0x00000000004000000000100000000000000000000000020000000000000000000000000002000000000000000000000000000000200000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000004000000000002000000000000002000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -305627 0x00000001000000000000000000000200000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -305629 0x00000001004000000000000000000200000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000040000000000000000001040000000000000000000000000000000000000000000000000000000000000000000 -305634 0x00000000005080000000000000000000000000000000020000400000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008020000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000400000000000000000000000 -305826 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000400000000000000002000000000000000000840000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -305827 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000100000000000000000000000000040000000000000000000000000000000000000000000000000000000000000040000000000000000000000010000000008000000000000000000000000000000100008000000000000000000000000000000000000000000000000000000000000000000000400000000000000002004000000000000000840000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -305829 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000008000000000080000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000080000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -305834 0x00000000004002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000041000000000000000000000000000000000000008000000000080000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000020000000000000000000000000000008000000000000000000000000000000000000000000000080000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -305839 0x00000000000000000000000000000000000010000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000080000000000000000000000000000000000000000000000000000000000000 -305841 0x40000000004000000000000000000000000010000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000008000000008000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000080000000000000000000000000000000000000000000008000000000000000 -306889 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -307290 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -307508 0x00000000000000000000000000000000000000000000020000000000000000000000200000000000400000000000000000000000000000000000000000000000002000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -307509 0x00000000004000000000000000000000000000000000020000000000000000000000200000000000400000000000000000000000000000000000000000000000002000000000000000008000000000000000000000000000000000040000000000040000000000000000000000000000000000000000000000000000000000000000000000000010000000008000010000004000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -307513 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000004000000000000000000000000010000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000200000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -307519 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000001000000000000002000000000000000000040000000000000000000000000000000000000000000080000000000000000000000000000000000000000000 -307528 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000020000000000000000000000000000000000000000000000000000000000000000100000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -308010 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000080000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000 -308115 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000040000000000000000000000000000000000000000000000000000000000000000000000001000000000000200000000000000 -308124 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000400200000000000000 -308127 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000040000000000000000000000000000000000000000000000000000000000000000000000001000000000000200000000000000 -308157 0x00000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000020000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000 -308183 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000002020000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -308190 0x00000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000020000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000 -308216 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000002020000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000 -308224 0x00000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000020000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000 -308257 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -308265 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -308267 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -308268 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -308285 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -308599 0x00000000000000000000000000000000000000000000080000000000000800000000000000000010000000000000000000200002000000000000000000000000000000000000000000020000001000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004010010000002000000000000000400000000000000000000000000000000000000000000040000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -309175 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -309177 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -309184 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -309186 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -309190 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -309194 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -309198 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -309417 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -309881 0x00400000000000000000000000000000000000000000004000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000 -309883 0x00400000000000000000000000000000000000000000004000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000 -309892 0x00400000000000000000000000000000000000000000004000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000 -310069 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -310114 0x00400000000000000000000000000000000000000000004000000000000000000000000000100000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -310116 0x00400000000000000000000000000000000000000000004000000000000000000000000000100000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -310177 0x00400000000000000000000000000000000000000000004000000000000000000000000000100000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -310533 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -310589 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -310592 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -310599 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -310601 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -310604 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -311317 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -311758 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -311858 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -311859 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -311865 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -311888 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -312096 0x00400000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000200000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -312124 0x00400000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000200000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -312367 0x00400000000000000000000000000000000400000000004000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -312371 0x00400000000000000000000000000000000400000000004000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -312383 0x00400000000000000000000000000000000400000000004000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -313355 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -313368 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -313507 0x00000000000000000000000000000000000000000200000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -313526 0x00000000000000000000000000000000000000000200000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -313724 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -313789 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -314190 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -314375 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000008000000000000000008000400000000000000000000000000 -315698 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -315705 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -315780 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -316726 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000040000000000000000 -316747 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -317179 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000040000000000000000000000000000000000000000000000000000000000000000000000001000000000000200000000000000 -317522 0x04000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000800000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000006001008000000000000008000080000000000000000000000000000000000000000001000000000100000000000008000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000040000000000000008000002004000000000000 -317526 0x00000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -317536 0x00000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000020000000000800000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000006000008000000000000000000080000000000000000000000000000000000000000001000000000000000000000008000000800400000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000002004000000000000 -317567 0x00000000000000200000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000001004000000000000000004000000020000000000000000000000000000000000000000000000000000000000000000000000000000000001000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -317588 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -317597 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000400000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 -317606 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -317610 0x00000000000000200000000000000000000000000000000000020000000000000000000000000000000000400000000000000000000800000080000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000001044000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000400000000000000000000000000000000000000000000000000000000000000000000440000000000000000 -317643 0x00000000000000200000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000010000000000000000000000000000004000000000020000000000000000000000000000000000000000000001004000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -317646 0x00000000000000000000000000000000000000000000000000004000000000000000000000000000000000400000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000010000000000000000000000000000004000000000020000000000000000000000000000000000000000000001000000000000000000004000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -317660 0x00000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000800000000000000001000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000080000000006000008000000000000000000080000000000000000000000000000000000000000001000000000000000000000008000000000400002000000000000000000000000000000000000000000000000000008000000000000000000000000000000000800000000000000000000000000000000000002004000000000000 -317957 0x00000000000000000000000000000000000000000200000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -318030 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -318032 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -318033 0x00000000001000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000000000000000800000000000000001000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000004000000000000000080000000006000000000000000000000000080000000000000000000000000000000000000000005000000000000000000000000000000008400000000000000000000000000000000000000000000000000008000000000000000000000000020000000000000800000000000000000000000000000000000002004000000000000 -318034 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -318036 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -318063 0x00000000001000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000000000000000800000040000000001000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000080000000006000000000000000000000000080000000000000000000000000000000000000000005000000000000000000000000000000008400000000000000000000000000000000000000000000000000008000000000000000000000000040000000000000800000000000000000000000000000000000002004000000000000 -318074 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000100000010020000000000000000000200000000000000000080000000020000000000000000000800000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000008000000000000000000000000000000000000000000000000000008000000000000000000000000020000000000000000000000000000000000000000000000000102000000000000000 -318096 0x04000000001000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000000000000000800000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000080000000006000000000000000000000000080000000000000000000000000000000000000000005000000000100000000000000000000008400000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000800000000000000000000000000000008000002004000000000000 -318137 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -318528 0x00000000001000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000020000000000800000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000080000000006000000000000000000000000080000000000000000000000000000000000000000005000000000000000000000000000000808400000000000000400000000000000000000000000000000000008000000000000000000000000000000000000000800000000000000000000000000000000000002004000000000000 -318627 0x00000000001000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000000000000000800000000000000001000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000004000000000000000080000000006000000000000000000000000080000000000000000000000000000000000000000005000000000000000000000000000000008400002000000000000000000000000000000000000000000000008000008000000000000000000000000000000000800000000000000000000000000000000000002004000000000000 -318639 0x00000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000800000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000002000000000000000000000010000000000000004800000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000080000000000000000000000000 -318650 0x00000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000800000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000010000000000000004000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000 -318653 0x00000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000004000000000000000000000000080000000000000000000000000000000000000000000000000000000200000000000000000000000000800000000000000000000000000000000000000000000000000000000000010000000000000000000000000800000000000000000000000000000000000000000000000000000 -318904 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -319523 0x00000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000400000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -321346 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -321884 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -321900 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000040000000000000000 -322038 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -322041 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -322043 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -322047 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -322048 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -322056 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -322059 0x00000000001000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000000000000000800000000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000080000000006000000000000000000000001080000800000000000000000000000000000000000005000000000000000000000000000000008400000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000800000000000000000000000000000000000002004000000000000 -322083 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -322090 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -322108 0x04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000010020000000000000000000200000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000080000000000000000000000000000000000000000004000000000100000000000000000000008000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000800000000000000000000000000000008000100000000000000000 -322121 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000010000000000100000010020000000000000000000200000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000001080000800000000000000000000000000000000000004000000000000000000000000000000808000000000000000400000000000000000000000000000000000008000000000000000000000000000000000000000800000000000000000000000000000000000100000000000000000 -322122 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000100000010020000000000000000040200000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000080000000000000000000000000000000000000000004000000000000000000000000000000008000000000000000000000000000000000000000000000000000008000000000000000000000000040000000000000800000000000000000000000000000000000100000000000000000 -322128 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000010020000000000000000000200000000000000000088000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000080000000000000000000000000000000000000000004000000000000000000000000000000008000002000000000000000000000000000000000000000000000008000008000000000000000000000000000000000800000000000000000000000000000000000100000000000000000 -322454 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008010000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000010000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000080000000000000000000000000000000000000000000000000000000000000000000000000 -322509 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008010000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000080000000000000000000000000000008000000000200000000000000000010000000000000000000000000000000000000000000000000000000002000000000200000000040000000000000080000000000000000000000000000000000000000000000000000000000000000000000000 -322550 0x00000000000000000000000000000000000000000200000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -322749 0x00000000001000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000000400000000800000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000080000000006400000000000000000000000080000000000000000000000000000000000000000005000000000000000000000000000000008400000000080000000000000000000000000000000000000000008000000000000000000000000000000000000000800000000000000000000000000000000000002004000000000000 -322750 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000080000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000020000000000000040000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -322752 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000008000000000000000000080000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000080000020000000000000040000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000080000000000000000000000 -322758 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -322760 0x00000004004000000000000000000000000000000000020000000000000000000000100000000000000000000000000000000000000000000000000000000000010000000000000000008000000000000000000000000000000000040000000000002000000000000000000000000000000000000000000004000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -322764 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000001000000000000000000000000000000000000000000000000000000000000001000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000020000000000000000000000000000000 -322765 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000001000000000000000000000000000000000000000000000000000000000000001000000000000000002000000000200000000040000000000000000000000000000000000000000000000000000000020000000000000000000000000000000 -322767 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002080000000000000000040000000000000000000000000000000000000000000002000000000000000000000000000000000000000000 -322768 0x00000000004000000000000000000000000000000000120000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000400000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002080004000000000000040000000000000000000000000000000000000000000002000000000000000000000000000000000000000000 -322774 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000008000000000000000000000000000000000000000000000000000000000000000000002001000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -322776 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000010000000000000000000000000040000000000000000000000000000000010000000008000000000000000000000000000000000009000000000000000008000000000000000000000000000000000000000000000000000000000000000000002001000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -322777 0x00000000004000000000008000100000000000000000020000000000000002000000000000000000000000000000000000000004000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000020000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000001000000000000000000000000000000000000000000000000 -324029 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -324316 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000004000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -324318 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000 -324322 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000400000000000000000000000000000000000000000000000000000008000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -325807 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -326760 0x00000000000000000000000000000000000000000000000000000040000000000000001000000000000000000000000000008000000000000000000000000000000000008000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000002000000000000008000000000000000 -327103 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -327105 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -327227 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000040000000000000000 -327399 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 -327544 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 -327690 0x00000000000000000000000000000100000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -328002 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000200000000000 -328269 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -328529 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 -328585 0x20000000000000000000100000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -328870 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 -329480 0x00000000000000000000000000000000000000000000020000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000200000000000000000000000020000000000000000000000000000000000000000000 -329484 0x00000000004000000000000008000000000000000000020000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000040000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000200000000000000000000000020000000000000000000000000000000000000000000 -329485 0x00000000000000000000000000000000001000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -329491 0x00000000000000000000000000000000001000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -329513 0x00000000000000000000000000000000001000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -329519 0x00000000000000000000000000000000001000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -329659 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000020000000000000000000000000000000000000000000000000000000000020000000010000000008000000000000000000000000000000000008000000400000000000000000000000000000000000000000000000000000000000000000000000000000002000000080000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000020000000 -329667 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000100000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000002000000000000000000000000000000000000000000 -329668 0x0000000000400000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000004000000000000010000000000000000000000000000000000000000000000000001000000000000000000001000000000c000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000002000000000000000000800000000000000000000000 -329673 0x00000000004000001000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000004000000000000000000000000000000000000000000000000004000000000000000000010000000008000000000000000000000000000002000008000000000000000000000000000000000000000000000000000000000000000000000400400000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -329740 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000010000000000000 -329749 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000008000000000000000000000000000000000000000002000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -329750 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000008000000000000000000000000000000000040000000040000000000000000000000010000000000000000000000000000000000000000000000000000010000000008000000000000000000000080000000000008000000000000000000000000000000000000000002000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000400000000000000000000000000000000000000000000 -329824 0x00000000000000000000000000000000000000000000200000000000000000000000001000000000000000000000000000008000000008000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -329964 0x00000000000000000000000000000000000000000000000000000000100000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -330023 0x00000000000000000000000000000000000000000000000000000000100000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -330207 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000004000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000200000000000000000000000008000000000000000 -330473 0x00000000000400000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000001000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -330511 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000002000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000040000000000000000 -330579 0x00000000000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000001000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -330683 0x00000000000000000000000000000000000000000000080000000000004000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -330919 0x00020000000000000000000000000000000000000000000000000000000000000008001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -331009 0x00000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -331542 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000100000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000004000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -332007 0x00000000000000000000000000000000000000000000000000000200000080000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008200000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -333256 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000400000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000010000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -333294 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -333583 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000200000000000000000000000000000000000000000000000000010008000000000000000 -333640 0x80000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000004000000008000000000000000000000000000000000000010000000000000000000000000000000000008000000000000000 -334263 0x00000000000000080000000000000000000000000000000000000000000000000100001000000000000010000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -334279 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000040000020000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000 -334883 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 -334915 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000004000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 -334919 0x00000020000000000000000000000000000000000000000000000000000000000000001000000000000020000000000000008000000000000000000000000000000000000020000000000000020000812000002000000000000000000000000001000000000000000000000000000000400000000000000000000000000000000000000000000000040000800000000010000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000008000400000000008000000000000000 -335076 0x00000000000000001000000000000000000000000000000000000000000000000000001000000000000000000100000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -335348 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000008000000000000000000000040000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000008000000000 -335643 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -335649 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -335652 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -335684 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000002000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000 -336089 0x0000000000000000000000000000000000000000000000000000000000020000000000100000000000000000000000000000800000000000000000000000000000000000000000000000000000000080200000a000000000000000000000000001000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -336231 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336234 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336242 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336243 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336244 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336245 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336247 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336248 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336255 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336260 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336263 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336264 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336266 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336334 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336336 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336337 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336338 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336439 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336451 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336452 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336453 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336461 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336495 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336497 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336507 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336508 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336509 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336510 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336518 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336520 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336521 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336522 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336526 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336527 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336528 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -336543 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 -337012 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000001000000000000000000000000400000000000000802000002000000200000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -337642 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000408000000000000000000000000000000000040000080000000000000000080000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000020000000000000000002000000000000000000040000000000000001000000000000000000000000000000000000000000000000000000000000000000000000 -337647 0x00000000000000000000000000000000000000000000020000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000800000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -337649 0x00000000004000000000000000000000000000000000020000000000000080000000100000000000000000000000000000000000000000000000000000000000000000000000000000008002000000000000000000000000000000040000000000000000000000000000000800000000000000000000000000000000000000000000000002000010000000008000000000000000000000000000000000008000000000000000000000000000000000200000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -337653 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000040000000000000000000040000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -337654 0x00000000004000000000008000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000020000040000000000000000000040000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -337655 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000040000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000400000000040000000000000000000000000000000000000000000000000000000000000000000000 -337656 0x00000000004000000000000000000000000400000000020000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000008000040000000000000000000000000000040000000000000000000000000000000000000000000000000000004000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000400000000040000000000000000000000000000000000000000000000000000000000000000000000 -337663 0x00000000004000000000000000000000080000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000001000000000000000000000000000050000000000000000000000000040000000000000000000000000000000000000000004000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000080000000000000000000000000000000000000 -337664 0x00000000000000000000000000000000000000000000020000000010000000000000000000000000001000000000000000000000000000000000000000000000000200000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -337669 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000020000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000008000000000 -337672 0x40000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000020000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000020000000000000010000000008000000000000000000000000008000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000008000008000000000 -337731 0x00000000000000000000000020000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000800000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -338275 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010004000200000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -338281 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010004000200000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -338336 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -338424 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008004000000000000000000000000000000000000100000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -338435 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000008000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000004000000000000000000000000010000000000000000000000000000000000000 -338439 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000010802000002000000000000000000000000001000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000040000000000000000000000000000000000000000000000008000000000000000 -338661 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 -338991 0x00000000000000000000000000200000000000000008000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000400800000000000000000000000000000010000000000000000000000000000000000000000000000000 -339173 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002400000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -339369 0x00000020000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 -339427 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000020000000000000000000001000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -340633 0x00000000000000000000000000000000000000000000020000000004000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000008000000000000001000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -340635 0x00000000004000000000000000000000000000000000020000000004000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000008000000000000001000000000000200000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000001000000000200000000000000000000000000000000000000000000000000000000000000000000 -340653 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000001000000002000000000000000000040000000000000000000000000000000000000000000000000000000010000000000000000000000000000000 -340658 0x0000000000400000000000000000000400000000000002000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000001000000000800000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000100000000a000000000000000000040000000000000000000000000000000000000000000000000000000010000000000000000000000000000000 -340674 0x00000000000800000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000100000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040080000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -340675 0x00000000004800000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000100000000000000000000000000000000000000000000000000000000000000000000000000000002000010000000000000040080000000000000000000000000000000000002000000000000000000080000000000000000000000000000 -340685 0x00000000000000000000000000000000000000000000020010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000008000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -340686 0x00004000004000000000000000000000000000000000820010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000010000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000008000000000000040000000000000000000000000000000000000000000000000002000000000000000000000000000000000000 -340700 0x00000000004000000000000000000000000000000000020001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000080000000000000000000000000000000000008000000000000000000000000000000000000000000002004200000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000001000 -340708 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000008000000000000000000000000000040000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000080000000000000000000000000000000000000 -340710 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000008000000000000000000000000000040000000000000100000000000000000800000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000400000000000000000000000000000000000000000000000000002000002000000000000040000000000000000000000000000000000000000000000000080000000000000000000000000000000000000 -340712 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000008000000000200000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -340713 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000080840000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000028000000100000000000000000000000000008000000000200000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000001000000000000000000000 -340718 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000100000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000002000000000000 -340719 0x00000000004000000000000000000000000000000000020000000040000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000008000000000000080000002000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000100000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000002000000000000 -340727 0x00000000004000000000040000002000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000200000000000080000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000002000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000001000000000000000000000000000000 -340728 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000002000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000100000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -340835 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -340988 0x00000000000000000010000000000000000000000010000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000010000000000008000000000000000 -341695 0x00000000000000000000000010000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000001000000000000000000000000000000000000000000000000000000000008000000000000000 -341985 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000100000000000004000000000000001000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -341997 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000104000000000004000000000000001000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -342001 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000100000000000004000000000000001000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -342004 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000100000000000004000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 -342007 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000004000000000000001000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 -342008 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000004000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 -342026 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000002000000004000000000000000000000000000000000000000000000000000000001000000000000000000004000000020000080000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 -342027 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 -342033 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 -342035 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 -342036 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 -342041 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 -342047 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000100000000000000000000000000000000002000000104000000000044100000000000001000002000000000000000000000001000000000000000000004000000000000080000000000000000000000000000000000000002000000000000000000000000020000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 -342053 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 -342080 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000400000002000000000000000000000000000000000000000000040000000000000000000001040000000000000000000000000000000080000000010000000000000000000000000000000000000000000000000000000020000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000440000000000000000 -342101 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 -342107 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 -342111 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 -342115 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 -342118 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000400000002000000004000000000000000000000000000000000000000000000000000000001000000000000000000004000000000000080000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 -342125 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 -342140 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 -342141 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 -342145 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000400000002000000000000000000000000000000000000000000040000000000000000000001040000000000000000000000000000000080000000010000000000000000000000000000000000000000000000000000000020000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000440000000000000000 -342162 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 -342173 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 -342188 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 -342272 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000400000000000000000 -342386 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000008000000000000000000000000000000000000000000000000000004000000000000000000000000000008000000000000000000000000001000000000000000000004000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000010000000004000000000000000000000000010000000000000000000400000000000000000 -342399 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000 -342466 0x00000000000000000000000000000000000000000000000000002000000000000000001000000000080000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -342601 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 -342616 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 -342618 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 -342924 0x00000000000000000000000000000000000010000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -342964 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000081000000000000000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -343006 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000080000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000 -343021 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000004000000000000000000000000000000000000000000000000080000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000 -343059 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000008000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -343079 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000200000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 -343083 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000040000000000000802000002000000000000000000000000001000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -343133 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -343162 0x00000020000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000100000000000000000000000000008000400000000000000000000000000 -343185 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000008000400000000000000000000000000 -343339 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000080000000000000000802000002000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -343946 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -343966 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -343971 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -344121 0x00000000000000000000000000000000000000000000000000000040000000000000001000000000000000000000000000008000000000000000000000000000000000008000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000002000000000000008000000000000000 -344164 0x00000000000000000000000000000000000000000000000000000040000000000000001000000000000000000000000000008000000000000000000000000000000000008000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000002000000000000008000000000000000 -344839 0x00000000000000000000000000000000000000000000000000000000000000000200001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000008000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -345506 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -346112 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -346392 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -346395 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -346398 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -346425 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -346448 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -346451 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -346454 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -346464 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -346466 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -347014 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000400000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -347301 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000200000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000002000000000000000000000000000000000000000000000000000000000000000008000000000000000 -347333 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000200000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000002000000000000000000000000000000000000000000000000000000000000000008000000000000000 -347613 0x00000000000000000000000000000000000000000800000000000000000000000000000000000000000001000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010004000000002000000000000000000000000000000000000000000000000000000001000000040000000000000000000000800000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000001000000000000000000000 -347700 0x00000000000000000000000000000000000000000000000000000000002000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400010000000000000 -347705 0x00000000000000000000000000000000000000000000000000000000002000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400010000000000000 -347711 0x00000000000000000000000000000000000000004000000000020000002000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040010000000000000 -347853 0x00000000000000000000000000000000000000000000000000000000002000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000 -347953 0x00000000000000000000000000000000000000000000000000000000002000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000 -347958 0x00000000000000000000000000000000000000004000000000020000002000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040010000000000000 -347960 0x00000000000000000000000000000000000000000000000000020000002000000001000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040010000000000000 -348019 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -348244 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000004000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -348443 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000400000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -348675 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000080000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000400100000000000000000000000000000000000000000000000008000000000000000 -348743 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -348936 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000100000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000002000000000000000000000000000000000000000008000000000000000 -350544 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -351473 0x00000000000000000000000000000000000000000000000000000000002000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000 -353157 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -353181 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000400000000000000000 -353196 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000080000000000000000000000000000000000000040000000000000000 -353273 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000 -353276 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000080000000000000000000000000000000000000040000000000000000 -353359 0x00000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000200000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000100000040 -353360 0x00000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000040 -353361 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008002400000000000000000000000000 -353367 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000080000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000008000000000000000 -353370 0x02000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 -353438 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000080000000000000000000000000000000000000000000000000002000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000040 -353443 0x0000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000a000400000000000000000000000000 -353447 0x00000028000000000000000000000080000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 -353479 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000002000001000000000000000000000000100000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -354071 0x02000000000000000000000000000000000000000000020000000000000000000000000040000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000001000000000020000000000000000000000200000000000000020000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000 -354151 0x00000000000000000000000000000000000000000000002000000000000000000000400000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004040000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000080000000400000000000000000000000000000000000000000000000000000000000000000000000000000 -354162 0x00000000000000000000000000004000000000000000000000000000000000000000410000000000200000000000000002000000000002000000000040000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000 -354233 0x00000000000000000000000000000000000000000000000000000000000000000000400040000004000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024040000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000400000000000000000000000040000000000000000000000000000000000100000000000000000 -354585 0x00000000000000000000000000000000000000000000000000100000000000000000400000000000200000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004001000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000 -354866 0x00000000000000000000000000000000000000000000000000001000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000001 -356461 0x00000000000000000000000000200000000000000000000000000000010000000000000000000000000000000000000000202000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -356488 0x00000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000200000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000020000000000000080000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000 -356513 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000100001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000080000000000000a00000000000000000000000 -356526 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -356535 0x00000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000 -356543 0x00000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000800080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000 -357195 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 -357579 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -357588 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -357590 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000200000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 -357592 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -357600 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -357622 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -357630 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -358290 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000400000002000000004000000000000000000000000000000000000000000000000000000001000000000000000000004000000000000080000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 -358426 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 -358556 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 -358811 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000400000000000000000000000000000000002000000000008000000000000000 -359114 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 -359375 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000100000000000000000 -359378 0x00000020000000000010000000000000000004000000000000000200400000000000000000000000000000000002000000000000000000020000000000000000000000000000000000000000000000010000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000040000000000040010000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000400000000000 -359538 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 -361585 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 -361588 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 -361732 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000842000002000000000000000000000000001000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000080000000000000000000000000000000000000000000000000000008000000000000000 -361757 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 -361775 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -362002 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000010000000000000000000000000802000002000000000000000000000400001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -365791 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000040 -365793 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000010000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000400010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 -369141 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000200000000000000000000000000000000000000000000000000000000000000000008000000000010000 -369239 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -369249 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -369253 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -369259 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -369261 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -369263 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -369274 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -369426 0x00000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000200000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000100000040 -369428 0x20000020000000000000000000800000000004000000000000000200400000000000000040000000000000000000000000000000000000020000000000000000000000000000000000000000000000010000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000040000000000000010000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000008000400800000000000000000000000 -369431 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018000400000000000100000000000040 -369538 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000040 -369540 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000008000400000000000000000000000000 -370399 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000001000000000000802000002000000000000000000000000001000000100000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -370517 0x00000000000000000000000000000080200000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000080004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 -370545 0x00000000000000000000000000000080200000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000080004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 -371190 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -371280 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -371286 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -371288 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -371299 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -371307 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -371327 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -371329 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -371352 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -371360 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -371362 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -371369 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -371378 0x00000000000000000000000000000080200000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000080004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 -371450 0x00000000000000000000000000000080200000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000080004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 -371489 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 -371509 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 -371532 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -371658 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 -371660 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -371876 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 -371904 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 -371906 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -371912 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 -371914 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -371918 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 -371931 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 -371933 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -371938 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 -371940 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -371973 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 -372006 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 -372014 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -372847 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -374209 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -374225 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -374365 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -374388 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020001000000000000000000000200000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -375079 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 -375093 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -375401 0x00000000000000000000000000000000000400000400000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -375440 0x00000000000000000000000000000000000400000400000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -375447 0x00000000000000000000000000000000000400000400000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -376493 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -376573 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -376588 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -376644 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -376650 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -376668 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -376906 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -377026 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 -377139 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000001000000000000080000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000080000000000000000000000000000000000000040000000000000000 -377506 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -377523 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 -377525 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -377581 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000040 -377586 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000040000000000000000000000100000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 -377608 0x00000000000000000000000000000000000000000200000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -377627 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000080000000000000000000000000000000000000040000000000000000 -377629 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000080000000000000000000000000000000000000040000000000000000 -377703 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000001000000000000080000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000080000000000000000000000000000000000000040000000000000000 -377730 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 -377746 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000400000000000000000 -377877 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000400000002000000004000000000000000000000000000000000000000000000000000000001000000000000000000004000000000000080000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 -377894 0x00000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -377905 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000400000002000000004000000000000000000000000000000000000000000000000000000001000000000000000000004000000000000080000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 -377917 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 -377922 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 -377925 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -378345 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 -378347 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 -379027 0x00000020000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 -379032 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 -379039 0x08000020000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 -379158 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000400000000000000000002000040000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -379161 0x00000400004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000040000000000000000000000000000000000000000000010000000008000000000000000000000000000000020008000000000000000000000000000000000000000000000000000000000000000000400000000000000000002000040000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -379163 0x00000000000000000000000000000000000000000000020000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000008000010000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000080000000000000000000000000000000000000000 -379164 0x00000000004000000000000000000000000000100000020000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000008000010000000000000000000000000000040000000000001000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000100000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000080000000000000000000000000000000000000000 -379167 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000004 -379170 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -379171 0x00000000004000000000000000800000000000000000020000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000008000000000000000000000000000002000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000004 -379172 0x00000000000000000010000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000200000000000000000000000000000000000000000000000000000000000000000000000 -379176 0x00000000004000000010000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000100000000000000000000000000000000000000000200000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000040000000000000000000000000000000002000000000000000000040000000000000000200000000000000000000000000000000000001000000000000000000000000000000000 -379180 0x00000000000080000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000800000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -379182 0x00000000004080000000000002000000000000000800020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000800000000000000000000050000000008000000000000000000000000800000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -379210 0x00000000000000040000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000004000000000000000000000400000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -379212 0x00000000004000040000000000000000000000000000020000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000200000000000008000000000000000000000000000000000000000004000000000000000000000400000000000000000000002000000000000000000040002000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -379214 0x00000001000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -379216 0x00000001004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000008000000000000008000000000000000000000000000000000040000000000000000000000000000000000020000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000020002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -379217 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000800000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000020000000000000000000000000000000000000000000000000000000000000000 -379219 0x00000000004000000000000000000000000000000000020000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000008000000000000000000000000010000000000000000010000000008800000000000000000000000000000000008000020000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000020000000000000000000000000000000000000000000000000000000000000000 -379220 0x00000000000000000000000000200000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000100000000000100002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -379224 0x00000000004000000000000000200000000000000000020000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000008000000000000000040000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000100000000000100002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000400000000000000 -379235 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000080000000000000000000000000000000000000000800000000000000000000000000000 -379237 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000100000000008000000000000000000000000000000000000010000000008008000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000080000000000000040000000000000000080000000000000000000000000000000000000000800000000000000000000000000000 -381271 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 -381276 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -381689 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -382200 0x00000020000000000000000008000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 -382217 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000400000010000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 -382644 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000200000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000002000000000000000000000000000000000000000000000000000000000000000008000000000000000 -383284 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -383337 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -383354 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -383361 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -383427 0x00000000000000000000000000000000000004000800000000000000000000000000000000000000000001000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000800000001000000000008000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000040000000000000000000 -383466 0x00000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -383469 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000001000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -383515 0x00000000000000000000000000000000000004000800000000000000000000000000000000000000000001000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000800000001000000000008000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000040000000000000000000 -383519 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000010000000800000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000002000000000000000000000000000 -383630 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000400000000000000000 -383760 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -383802 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000080000000000400000000000000000 -383815 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000000001000000000000000000004000000000000000000000010000000000000000000000040000000000000000000000000000000020000000100000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -383844 0x00000000000000000000000000000000100000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -383852 0x00000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000002000000000000000000000000000400000000000000004000000000000000080000000000000000000000000000000000000001000000000000000000004000000000000000000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -383859 0x00000000000000000000000000000000000000804000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000002000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 -383864 0x00000000000000000000000000000000000000800000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000080000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 -383968 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000001000000000000080000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000080000000000000000000000000000000000000040000000000000000 -383973 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 -384127 0x00000000000000000000000000000000000004000800000000000000000000000000000000000000000001000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000800000001000000000008000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000040000000000000000000 -384138 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -384149 0x00000000000000000000000000000000100000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -384173 0x00000000000000000000000000000000100000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000400000000000000000000080000000000000000000000000000000000008000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000001000000000000000000005000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000800000000000000000000000000000400000000000000000 -384301 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000040000000000000000000000000000000000000000400000000000000000 -384422 0x00000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000400000000000000000 -384506 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 -384511 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 -384546 0x00000000000000000000000000000000000004000800000000000000000000000000000000000000000001000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000800000001000000000008000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000040000000000000000000 -384771 0x00001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000800000 -384825 0x00001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000 -384861 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000100000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -384917 0x00000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000400000000000000000 -384923 0x00002000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000001000000 -384965 0x00000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -385067 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000008000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000400000000000000000 -385073 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000008000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000400000000000000000 -385356 0x00002000000000000000000000000000000000010000000000000000000000000000000400000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000004000000000000000000000000000000004000000000000000000000000000000000000000000000000000000001000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000001000000 -386571 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -386620 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000 -386736 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000040000000000000000000000000000010000000020000000000000000000000000000000000000000000000000000000000000000010 -386786 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000280000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000040000000000000000000000000000010000000040000000000000000000000000000000000000000000000000000000000000000010 -386795 0x04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000040000000000000000000000000000000000040000000000000000000000000000010000000000000000000000000000000000000000000000000000008000000000000000000010 -386804 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000040000000000400000000000000000000000040000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000010 -386812 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000040000000000000000008000000000010000000000000000000000000000000000000000000000000000000000000000000000000010 -386818 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000800000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000040000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000010 -386899 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000080000000000000000000000000000040000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000010 -386939 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000000000000000000000000000000000200000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000010000000020000000000000000000000000000000000000000000000000000000000000000000 -386945 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000020000000000000000000800000000000000000000000000000000000000000200000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000 -386975 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000100000000000000000020000000000000000000000000000000000000000000000000000000000000000000 -387011 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000010000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000 -387014 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000001000000000000000000000040000000000000000000000000000000000000000000000040000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000 -387016 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000400000000800000000 -387032 0x04000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000 -387044 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000020000000000000000000000000000000000000000000080000000000000000000000 -387045 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000400000000800000000 -387206 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -387225 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -387241 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -387276 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000008000000000000000004000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000021000000000000000000004000000000000000000000400000000000000000000000000000000080000000000000000000000000000000000000040000000000001000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -387284 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000040000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -387365 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000440000000000000000 -387615 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000800008000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -387627 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000800000000000000000400000000000000000 -387641 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800008000000000000000000000001000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -387648 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000800008000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -387654 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000800008000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 -387658 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000800008000000000000000000000001000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 -387683 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000800008000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -387688 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000800008000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 -387690 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000800008000000000000000000000001000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 -387761 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 -388108 0x00000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -388111 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000800000000 -388150 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000800000000 -388246 0x00000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000001000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000 -388285 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -388296 0x00000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000001000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000 -388516 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -388860 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000020000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000 -388893 0x00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000008000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000020000000000000000000010000000000001000000000000000000000000000000000000000000000000000000000000000400000000000000000 -388894 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000020000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000 -388907 0x00000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000104000000000004000000000000001000000000000000000000000000001000000000000000000004080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000004000000000000000400000000000000000 -388909 0x00000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000400000000000000000 -388912 0x00000000000000000000000000000000000000004000000000020000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000004000000000000000040000000000000000 -388918 0x00000000000000000000000000000000000000000000000000020000002000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000004000000000000000040000000000000000 -388923 0x00000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000008000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000001000000000000000000000080000000000000000000000000000000000000000000000000000000000008000000000000000020000000000000000000000000000000001000000000000000000000000000000000000000000000004000000000000000400000000000000000 -388940 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000020000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000 -388971 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000004000000000000000000000000000000000000000800000000000000000000000000000000000 -388990 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000 -389012 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000 -389158 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000 -389206 0x00000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000400000000000000000 -389238 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000 -389277 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000100000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000400000000000000000 -389292 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000800000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -389301 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000020000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 -389309 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000020000000000000000000000000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -389324 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000008000000000000000000000000004000000000000000000000000004000000000000000000000000000000000000000000000000000000001000000000000800000024000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000440000000000000000 -389328 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000 -389343 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000020000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 -390001 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000001000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -390004 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000200000000000000000000000000000000000000020000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -390024 0x00000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -390042 0x00000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -390236 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -390306 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000001000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -390867 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -391685 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000010000000800000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000002000000000000000000000000000 -391690 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000010000000800000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000002000000000000000000000000000 -391691 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000010000000800000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000002000000000000000000000000000 -391697 0x00000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000040000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000 -391713 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000 -391849 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000100000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000400000000000000000 -392002 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000 -392097 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000020000000000000000000000000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -392104 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -392110 0x00000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000 -392294 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000004000000000000000000000000000000000000000000000000000000000 -392697 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000010000000000000000000000000000400000000000000000 -392960 0x00000000000000200000400000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -392970 0x00000000000000200000400000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -392990 0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -393302 0x00000010000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000400000000000000000 -393370 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -393752 0x00000000000000000000000000000000001000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 -394354 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000800000024000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -394389 0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -394390 0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -394391 0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -394393 0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -394394 0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -394395 0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -394426 0x00000000000000200000400000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000200000000000000000000000000000000000000000000000000000000000000000000000008000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -394800 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000100000010000000000000000000000000000000000000000000000000000000000020000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 -395595 0x00000000000000000000000000000000000000000000000000000000000100000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000800000000000000000000000000000000000000000000000000000000000000000008000000000000000 -395969 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -396348 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000010000000000000000000000000000400000000000000000 -397108 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000 -397588 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000 -397591 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000 -398412 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 -398456 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 -398477 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -398679 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -398968 0x00000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020200000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000 -398972 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000400000000000000000 -399058 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 -399804 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000010000000000000000000000000000400000000000000000 -399849 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000 diff --git a/util/bloomchain/tests/groupchain.rs b/util/bloomchain/tests/groupchain.rs deleted file mode 100644 index ec396346ac30ebf5d80da2c40a5e89cde4517707..0000000000000000000000000000000000000000 --- a/util/bloomchain/tests/groupchain.rs +++ /dev/null @@ -1,172 +0,0 @@ -extern crate bloomchain; -extern crate rustc_hex; - -mod util; - -use bloomchain::{Bloom, Config}; -use bloomchain::group::BloomGroupChain; -use util::{BloomGroupMemoryDatabase, FromHex, for_each_bloom, generate_n_random_blooms}; - -#[test] -fn simple_bloom_group_search() { - let config = Config::default(); - let mut db = BloomGroupMemoryDatabase::default(); - let bloom = Bloom::from_hex("00000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000008000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - - let modified_blooms = { - let chain = BloomGroupChain::new(config, &db); - let block_number = 23; - chain.insert(block_number, bloom.clone()) - }; - - // number of modified blooms should always be equal number of levels - assert_eq!(modified_blooms.len(), config.levels); - db.insert_blooms(modified_blooms); - - - let chain = BloomGroupChain::new(config, &db); - assert_eq!(chain.with_bloom(&(0..100), &bloom), vec![23]); - assert_eq!(chain.with_bloom(&(0..22), &bloom), vec![]); - assert_eq!(chain.with_bloom(&(23..23), &bloom), vec![23]); - assert_eq!(chain.with_bloom(&(24..100), &bloom), vec![]); -} - -#[test] -fn partly_matching_bloom_group_searach() { - let config = Config::default(); - let mut db = BloomGroupMemoryDatabase::default(); - let bloom0 = Bloom::from_hex("10100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - let bloom1 = Bloom::from_hex("11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - let bloom2 = Bloom::from_hex("10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - - let modified_blooms_0 = { - let chain = BloomGroupChain::new(config, &db); - let block_number = 14; - chain.insert(block_number, bloom0) - }; - - db.insert_blooms(modified_blooms_0); - - let modified_blooms_1 = { - let chain = BloomGroupChain::new(config, &db); - let block_number = 15; - chain.insert(block_number, bloom1) - }; - - db.insert_blooms(modified_blooms_1); - - - let chain = BloomGroupChain::new(config, &db); - assert_eq!(chain.with_bloom(&(0..100), &bloom2), vec![14, 15]); -} - -#[test] -fn bloom_group_replace() { - let config = Config::default(); - let mut db = BloomGroupMemoryDatabase::default(); - let bloom0 = Bloom::from_hex("10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - let bloom1 = Bloom::from_hex("01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - let bloom2 = Bloom::from_hex("00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - let bloom3 = Bloom::from_hex("00010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - let bloom4 = Bloom::from_hex("00001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - let bloom5 = Bloom::from_hex("00000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - - let modified_blooms_0 = { - let chain = BloomGroupChain::new(config, &db); - let block_number = 14; - chain.insert(block_number, bloom0.clone()) - }; - - db.insert_blooms(modified_blooms_0); - - let modified_blooms_1 = { - let chain = BloomGroupChain::new(config, &db); - let block_number = 15; - chain.insert(block_number, bloom1.clone()) - }; - - db.insert_blooms(modified_blooms_1); - - let modified_blooms_2 = { - let chain = BloomGroupChain::new(config, &db); - let block_number = 16; - chain.insert(block_number, bloom2.clone()) - }; - - db.insert_blooms(modified_blooms_2); - - let modified_blooms_3 = { - let chain = BloomGroupChain::new(config, &db); - let block_number = 17; - chain.insert(block_number, bloom3.clone()) - }; - - db.insert_blooms(modified_blooms_3); - - - let reset_modified_blooms = { - let chain = BloomGroupChain::new(config, &db); - chain.replace(&(15..17), vec![bloom4.clone(), bloom5.clone()]) - }; - - db.insert_blooms(reset_modified_blooms); - - let chain = BloomGroupChain::new(config, &db); - assert_eq!(chain.with_bloom(&(0..100), &bloom0), vec![14]); - assert_eq!(chain.with_bloom(&(0..100), &bloom1), vec![]); - assert_eq!(chain.with_bloom(&(0..100), &bloom2), vec![]); - assert_eq!(chain.with_bloom(&(0..100), &bloom3), vec![]); - assert_eq!(chain.with_bloom(&(0..100), &bloom4), vec![15]); - assert_eq!(chain.with_bloom(&(0..100), &bloom5), vec![16]); -} - -#[test] -fn file_test_bloom_group_search() { - let config = Config::default(); - let mut db = BloomGroupMemoryDatabase::default(); - let blooms_file = include_bytes!("data/blooms.txt"); - - for_each_bloom(blooms_file, | block_number, bloom | { - let modified_blooms = { - let chain = BloomGroupChain::new(config, &db); - chain.insert(block_number, bloom) - }; - - // number of modified blooms should always be equal number of levels - assert_eq!(modified_blooms.len(), config.levels); - db.insert_blooms(modified_blooms); - }); - - for_each_bloom(blooms_file, | block_number, bloom | { - let chain = BloomGroupChain::new(config, &db); - let blocks = chain.with_bloom(&(block_number..block_number), &bloom); - assert_eq!(blocks.len(), 1); - assert_eq!(blocks[0], block_number); - }); -} - -#[test] -fn random_bloom_group_replacement() { - let insertions = 10_000; - - let config = Config::default(); - let mut db = BloomGroupMemoryDatabase::default(); - let blooms = generate_n_random_blooms(insertions); - - for (i, bloom) in blooms.iter().enumerate() { - - let modified_blooms = { - let chain = BloomGroupChain::new(config, &db); - chain.replace(&(i..i), vec![bloom.clone()]) - }; - - db.insert_blooms(modified_blooms); - } - - for (i, bloom) in blooms.iter().enumerate() { - let chain = BloomGroupChain::new(config, &db); - let blocks = chain.with_bloom(&(i..i), bloom); - assert_eq!(blocks.len(), 1); - assert_eq!(blocks[0], i); - } -} diff --git a/util/bloomchain/tests/util/db.rs b/util/bloomchain/tests/util/db.rs deleted file mode 100644 index 8101b37848d41e2af70608390e22088966feac27..0000000000000000000000000000000000000000 --- a/util/bloomchain/tests/util/db.rs +++ /dev/null @@ -1,39 +0,0 @@ -use std::collections::HashMap; -use bloomchain::{Position, Bloom, BloomDatabase}; -use bloomchain::group::{GroupPosition, BloomGroup, BloomGroupDatabase}; - -#[derive(Default)] -pub struct BloomMemoryDatabase { - mem: HashMap, -} - -impl BloomMemoryDatabase { - #[allow(dead_code)] - pub fn insert_blooms(&mut self, blooms: HashMap) { - self.mem.extend(blooms); - } -} - -impl BloomDatabase for BloomMemoryDatabase { - fn bloom_at(&self, position: &Position) -> Option { - self.mem.get(position).cloned() - } -} - -#[derive(Default)] -pub struct BloomGroupMemoryDatabase { - mem: HashMap, -} - -impl BloomGroupMemoryDatabase { - #[allow(dead_code)] - pub fn insert_blooms(&mut self, groups: HashMap) { - self.mem.extend(groups); - } -} - -impl BloomGroupDatabase for BloomGroupMemoryDatabase { - fn blooms_at(&self, position: &GroupPosition) -> Option { - self.mem.get(position).cloned() - } -} diff --git a/util/bloomchain/tests/util/each.rs b/util/bloomchain/tests/util/each.rs deleted file mode 100644 index 19ca1b67cf5a6a936e7b1329f5559d8cf8321c2f..0000000000000000000000000000000000000000 --- a/util/bloomchain/tests/util/each.rs +++ /dev/null @@ -1,24 +0,0 @@ -use std::io::{BufReader, Read, BufRead}; -use bloomchain::Bloom; -use super::FromHex; - -pub fn for_each_bloom(bytes: &[u8], mut f: F) where F: FnMut(usize, Bloom) { - let mut reader = BufReader::new(bytes); - let mut line = String::new(); - while reader.read_line(&mut line).unwrap() > 0 { - { - let mut number_bytes = vec![]; - let mut bloom_bytes = [0; 512]; - - let mut line_reader = BufReader::new(line.as_ref() as &[u8]); - line_reader.read_until(b' ', &mut number_bytes).unwrap(); - line_reader.consume(2); - line_reader.read_exact(&mut bloom_bytes).unwrap(); - - let number = String::from_utf8(number_bytes).map(|s| s[..s.len() -1].to_owned()).unwrap().parse::().unwrap(); - let bloom = Bloom::from_hex(&String::from_utf8(bloom_bytes.to_vec()).unwrap()); - f(number, bloom); - } - line.clear(); - } -} diff --git a/util/bloomchain/tests/util/from_hex.rs b/util/bloomchain/tests/util/from_hex.rs deleted file mode 100644 index 9152d304fdf33e508345009e2b6c99c227e4e37b..0000000000000000000000000000000000000000 --- a/util/bloomchain/tests/util/from_hex.rs +++ /dev/null @@ -1,16 +0,0 @@ -use rustc_hex::FromHex as RustcFromHex; -use bloomchain::Bloom; - -pub trait FromHex { - fn from_hex(s: &str) -> Self where Self: Sized; -} - -impl FromHex for Bloom { - fn from_hex(s: &str) -> Self { - let mut res = [0u8; 256]; - let v = s.from_hex().unwrap(); - assert_eq!(res.len(), v.len()); - res.copy_from_slice(&v); - From::from(res) - } -} diff --git a/util/bloomchain/tests/util/mod.rs b/util/bloomchain/tests/util/mod.rs deleted file mode 100644 index 2a1e55af9a0a27ffd722bbf1880695450d1c11f3..0000000000000000000000000000000000000000 --- a/util/bloomchain/tests/util/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod db; -mod each; -mod from_hex; -mod random; - -pub use self::db::{BloomMemoryDatabase, BloomGroupMemoryDatabase}; -pub use self::each::for_each_bloom; -pub use self::from_hex::FromHex; -pub use self::random::{generate_random_bloom, generate_n_random_blooms}; diff --git a/util/bloomchain/tests/util/random.rs b/util/bloomchain/tests/util/random.rs deleted file mode 100644 index 3d50b5ac10a8516af31d1ef29d9a69b9f1bcb064..0000000000000000000000000000000000000000 --- a/util/bloomchain/tests/util/random.rs +++ /dev/null @@ -1,24 +0,0 @@ -extern crate rand; - -use self::rand::random; -use bloomchain::Bloom; - -pub fn generate_random_bloom() -> Bloom { - let mut res = [0u8; 256]; - let p0 = random::(); - let b0 = random::() % 8; - let p1 = random::(); - let b1 = random::() % 8; - let p2 = random::(); - let b2 = random::() % 8; - - res[p0 as usize] |= 1 << b0; - res[p1 as usize] |= 1 << b1; - res[p2 as usize] |= 1 << b2; - - From::from(res) -} - -pub fn generate_n_random_blooms(n: usize) -> Vec { - (0..n).map(|_| generate_random_bloom()).collect() -} diff --git a/util/blooms-db/Cargo.toml b/util/blooms-db/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..23048a7d571c455443c58de72276ef1ea82114f0 --- /dev/null +++ b/util/blooms-db/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "blooms-db" +version = "0.1.0" +license = "GPL-3.0" +authors = ["Parity Technologies "] + +[dependencies] +byteorder = "1.2" +ethbloom = "0.5" +parking_lot = "0.6" +tiny-keccak = "1.4" + +[dev-dependencies] +tempdir = "0.3" diff --git a/util/blooms-db/benches/blooms.rs b/util/blooms-db/benches/blooms.rs new file mode 100644 index 0000000000000000000000000000000000000000..7a27260b35aa497ca5dcf5cf0297c21b2bb92e37 --- /dev/null +++ b/util/blooms-db/benches/blooms.rs @@ -0,0 +1,81 @@ +// 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 test; +extern crate tempdir; +extern crate blooms_db; +extern crate ethbloom; + +use std::iter; +use test::Bencher; +use tempdir::TempDir; +use blooms_db::Database; +use ethbloom::Bloom; + +#[bench] +fn blooms_filter_1_million_ok(b: &mut Bencher) { + let tempdir = TempDir::new("").unwrap(); + let database = Database::open(tempdir.path()).unwrap(); + database.insert_blooms(999_999, iter::once(&Bloom::from(0))).unwrap(); + let bloom = Bloom::from(0x001); + database.insert_blooms(200_000, iter::once(&bloom)).unwrap(); + database.insert_blooms(400_000, iter::once(&bloom)).unwrap(); + database.insert_blooms(600_000, iter::once(&bloom)).unwrap(); + database.insert_blooms(800_000, iter::once(&bloom)).unwrap(); + + b.iter(|| { + let matches = database.filter(0, 999_999, Some(&bloom)).unwrap(); + assert_eq!(matches, vec![200_000, 400_000, 600_000, 800_000]); + }); +} + +#[bench] +fn blooms_filter_1_million_miss(b: &mut Bencher) { + let tempdir = TempDir::new("").unwrap(); + let database = Database::open(tempdir.path()).unwrap(); + database.insert_blooms(999_999, iter::once(&Bloom::from(0))).unwrap(); + let bloom = Bloom::from(0x001); + let bad_bloom = Bloom::from(0x0001); + database.insert_blooms(200_000, iter::once(&bloom)).unwrap(); + database.insert_blooms(400_000, iter::once(&bloom)).unwrap(); + database.insert_blooms(600_000, iter::once(&bloom)).unwrap(); + database.insert_blooms(800_000, iter::once(&bloom)).unwrap(); + + b.iter(|| { + let matches = database.filter(0, 999_999, Some(&bad_bloom)).unwrap(); + assert_eq!(matches, vec![200_000, 400_000, 600_000, 800_000]); + }); +} + +#[bench] +fn blooms_filter_1_million_miss_and_ok(b: &mut Bencher) { + let tempdir = TempDir::new("").unwrap(); + let database = Database::open(tempdir.path()).unwrap(); + database.insert_blooms(999_999, iter::once(&Bloom::from(0))).unwrap(); + let bloom = Bloom::from(0x001); + let bad_bloom = Bloom::from(0x0001); + database.insert_blooms(200_000, iter::once(&bloom)).unwrap(); + database.insert_blooms(400_000, iter::once(&bloom)).unwrap(); + database.insert_blooms(600_000, iter::once(&bloom)).unwrap(); + database.insert_blooms(800_000, iter::once(&bloom)).unwrap(); + + b.iter(|| { + let matches = database.filter(0, 999_999, &vec![bad_bloom, bloom]).unwrap(); + assert_eq!(matches, vec![200_000, 400_000, 600_000, 800_000]); + }); +} diff --git a/util/blooms-db/src/db.rs b/util/blooms-db/src/db.rs new file mode 100644 index 0000000000000000000000000000000000000000..faeb038f296cbdf138ab62b51eebc60bce411714 --- /dev/null +++ b/util/blooms-db/src/db.rs @@ -0,0 +1,288 @@ +// 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 . + +use std::{io, fmt}; +use std::path::{Path, PathBuf}; + +use ethbloom; + +use file::{File, FileIterator}; + +/// Bloom positions in database files. +#[derive(Debug)] +struct Positions { + top: u64, + mid: u64, + bot: u64 +} + +impl Positions { + fn from_index(index: u64) -> Self { + Positions { + top: index >> 8, + mid: index >> 4, + bot: index, + } + } +} + +/// Blooms database. +pub struct Database { + /// Top level bloom file + /// + /// Every bloom represents 16 blooms on mid level + top: File, + /// Mid level bloom file + /// + /// Every bloom represents 16 blooms on bot level + mid: File, + /// Bot level bloom file + /// + /// Every bloom is an ethereum header bloom + bot: File, + /// Database path + path: PathBuf, +} + +impl Database { + /// Opens blooms database. + pub fn open

(path: P) -> io::Result where P: AsRef { + let path = path.as_ref(); + let database = Database { + top: File::open(path.join("top.bdb"))?, + mid: File::open(path.join("mid.bdb"))?, + bot: File::open(path.join("bot.bdb"))?, + path: path.to_owned(), + }; + + Ok(database) + } + + /// Reopens the database at the same location. + pub fn reopen(&mut self) -> io::Result<()> { + self.top = File::open(self.path.join("top.bdb"))?; + self.mid = File::open(self.path.join("mid.bdb"))?; + self.bot = File::open(self.path.join("bot.bdb"))?; + Ok(()) + } + + /// Insert consecutive blooms into database starting with positon from. + pub fn insert_blooms<'a, I, B>(&mut self, from: u64, blooms: I) -> io::Result<()> + where ethbloom::BloomRef<'a>: From, I: Iterator { + for (index, bloom) in (from..).into_iter().zip(blooms.map(Into::into)) { + let pos = Positions::from_index(index); + + // constant forks make lead to increased ration of false positives in bloom filters + // since we do not rebuild top or mid level, but we should not be worried about that + // most of the time events at block n(a) occur also on block n(b) or n+1(b) + self.top.accrue_bloom::(pos.top, bloom)?; + self.mid.accrue_bloom::(pos.mid, bloom)?; + self.bot.replace_bloom::(pos.bot, bloom)?; + } + self.top.flush()?; + self.mid.flush()?; + self.bot.flush() + } + + /// Returns an iterator yielding all indexes containing given bloom. + pub fn iterate_matching<'a, 'b, B, I, II>(&'a mut self, from: u64, to: u64, blooms: II) -> io::Result> + where ethbloom::BloomRef<'b>: From, 'b: 'a, II: IntoIterator + Copy, I: Iterator { + let index = from / 256 * 256; + let pos = Positions::from_index(index); + + let iter = DatabaseIterator { + top: self.top.iterator_from(pos.top)?, + mid: self.mid.iterator_from(pos.mid)?, + bot: self.bot.iterator_from(pos.bot)?, + state: IteratorState::Top, + from, + to, + index, + blooms, + }; + + Ok(iter) + } +} + +fn contains_any<'a, I, B>(bloom: ethbloom::Bloom, mut iterator: I) -> bool +where ethbloom::BloomRef<'a>: From, I: Iterator { + iterator.any(|item| bloom.contains_bloom(item)) +} + +/// Blooms database iterator +pub struct DatabaseIterator<'a, I> { + top: FileIterator<'a>, + mid: FileIterator<'a>, + bot: FileIterator<'a>, + state: IteratorState, + from: u64, + to: u64, + index: u64, + blooms: I, +} + +impl<'a, I> fmt::Debug for DatabaseIterator<'a, I> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("DatabaseIterator") + .field("state", &self.state) + .field("from", &self.from) + .field("to", &self.to) + .field("index", &self.index) + .field("blooms", &"...") + .field("top", &"...") + .field("mid", &"...") + .field("bot", &"...") + .finish() + } +} + +/// Database iterator state. +#[derive(Debug)] +enum IteratorState { + /// Iterator should read top level bloom + Top, + /// Iterator should read mid level bloom `x` more times + Mid(usize), + /// Iterator should read mid level bloom `mid` more times + /// and bot level `mix * 16 + bot` times + Bot { mid: usize, bot: usize }, +} + +impl<'a, 'b, B, I, II> Iterator for DatabaseIterator<'a, II> +where ethbloom::BloomRef<'b>: From, 'b: 'a, II: IntoIterator + Copy, I: Iterator { + type Item = io::Result; + + fn next(&mut self) -> Option { + macro_rules! try_o { + ($expr: expr) => { + match $expr { + Err(err) => return Some(Err(err)), + Ok(ok) => ok, + } + } + } + + macro_rules! next_bloom { + ($iter: expr) => { + try_o!($iter.next()?) + } + } + + loop { + if self.index > self.to { + return None; + } + + self.state = match self.state { + IteratorState::Top => { + if contains_any(next_bloom!(self.top), self.blooms.into_iter()) { + IteratorState::Mid(16) + } else { + self.index += 256; + try_o!(self.mid.advance(16)); + try_o!(self.bot.advance(256)); + IteratorState::Top + } + }, + IteratorState::Mid(left) => { + if left == 0 { + IteratorState::Top + } else if contains_any(next_bloom!(self.mid), self.blooms.into_iter()) && self.index + 16 >= self.from { + IteratorState::Bot { mid: left - 1, bot: 16 } + } else { + self.index += 16; + try_o!(self.bot.advance(16)); + IteratorState::Mid(left - 1) + } + }, + IteratorState::Bot { mid, bot } => { + if bot == 0 { + IteratorState::Mid(mid) + } else if contains_any(next_bloom!(self.bot), self.blooms.into_iter()) && self.index >= self.from { + let result = self.index; + self.index += 1; + self.state = IteratorState::Bot { mid, bot: bot - 1 }; + return Some(Ok(result)); + } else { + self.index += 1; + IteratorState::Bot { mid, bot: bot - 1 } + } + } + } + } + } +} + +#[cfg(test)] +mod tests { + use ethbloom::Bloom; + use tempdir::TempDir; + use super::Database; + + #[test] + fn test_database() { + let tempdir = TempDir::new("").unwrap(); + let mut database = Database::open(tempdir.path()).unwrap(); + database.insert_blooms(0, vec![Bloom::from(0), Bloom::from(0x01), Bloom::from(0x10), Bloom::from(0x11)].iter()).unwrap(); + + let matches = database.iterate_matching(0, 3, Some(&Bloom::from(0))).unwrap().collect::, _>>().unwrap(); + assert_eq!(matches, vec![0, 1, 2, 3]); + + let matches = database.iterate_matching(0, 4, Some(&Bloom::from(0))).unwrap().collect::, _>>().unwrap(); + assert_eq!(matches, vec![0, 1, 2, 3]); + + let matches = database.iterate_matching(1, 3, Some(&Bloom::from(0))).unwrap().collect::, _>>().unwrap(); + assert_eq!(matches, vec![1, 2, 3]); + + let matches = database.iterate_matching(1, 2, Some(&Bloom::from(0))).unwrap().collect::, _>>().unwrap(); + assert_eq!(matches, vec![1, 2]); + + let matches = database.iterate_matching(0, 3, Some(&Bloom::from(0x01))).unwrap().collect::, _>>().unwrap(); + assert_eq!(matches, vec![1, 3]); + + let matches = database.iterate_matching(0, 3, Some(&Bloom::from(0x10))).unwrap().collect::, _>>().unwrap(); + assert_eq!(matches, vec![2, 3]); + + let matches = database.iterate_matching(2, 2, Some(&Bloom::from(0x10))).unwrap().collect::, _>>().unwrap(); + assert_eq!(matches, vec![2]); + } + + #[test] + fn test_database2() { + let tempdir = TempDir::new("").unwrap(); + let mut database = Database::open(tempdir.path()).unwrap(); + database.insert_blooms(254, vec![Bloom::from(0x100), Bloom::from(0x01), Bloom::from(0x10), Bloom::from(0x11)].iter()).unwrap(); + + let matches = database.iterate_matching(0, 257, Some(&Bloom::from(0x01))).unwrap().collect::, _>>().unwrap(); + assert_eq!(matches, vec![255, 257]); + + let matches = database.iterate_matching(0, 258, Some(&Bloom::from(0x100))).unwrap().collect::, _>>().unwrap(); + assert_eq!(matches, vec![254]); + + let matches = database.iterate_matching(0, 256, Some(&Bloom::from(0x01))).unwrap().collect::, _>>().unwrap(); + assert_eq!(matches, vec![255]); + + let matches = database.iterate_matching(255, 255, Some(&Bloom::from(0x01))).unwrap().collect::, _>>().unwrap(); + assert_eq!(matches, vec![255]); + + let matches = database.iterate_matching(256, 256, Some(&Bloom::from(0x10))).unwrap().collect::, _>>().unwrap(); + assert_eq!(matches, vec![256]); + + let matches = database.iterate_matching(256, 257, Some(&Bloom::from(0x10))).unwrap().collect::, _>>().unwrap(); + assert_eq!(matches, vec![256, 257]); + } +} diff --git a/util/blooms-db/src/file.rs b/util/blooms-db/src/file.rs new file mode 100644 index 0000000000000000000000000000000000000000..64766c5cde7aeb747e26327ec81b6a284a049f02 --- /dev/null +++ b/util/blooms-db/src/file.rs @@ -0,0 +1,153 @@ +// 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 . + +use std::io::{Seek, SeekFrom, Write, Read}; +use std::path::Path; +use std::{io, fs}; + +use ethbloom; + +/// Autoresizable file containing blooms. +pub struct File { + /// Backing file. + file: fs::File, + /// Current file len. + len: u64, +} + +impl File { + /// Opens database file. Creates new file if database file does not exist. + pub fn open

(path: P) -> io::Result where P: AsRef { + let file = fs::OpenOptions::new() + .read(true) + .write(true) + .create(true) + // appending is done manually by calling `ensure_space_for_write` + .append(false) + .open(path)?; + let len = file.metadata()?.len(); + + let file = File { + file, + len, + }; + + Ok(file) + + } + + /// Resizes the file if there is not enough space to write bloom at given position. + fn ensure_space_for_write(&mut self, pos: u64) -> io::Result<()> { + // position to write + 256 bytes + let required_space = (pos + 1) * 256; + if required_space > self.len { + self.file.set_len(required_space)?; + self.len = required_space; + } + Ok(()) + } + + /// Read bloom at given position. + pub fn read_bloom(&self, pos: u64) -> io::Result { + let mut file_ref = &self.file; + file_ref.seek(SeekFrom::Start(pos * 256))?; + let mut bloom = ethbloom::Bloom::default(); + file_ref.read_exact(&mut bloom)?; + Ok(bloom) + } + + /// Accrue bloom into bloom at given position. + pub fn accrue_bloom<'a, B>(&mut self, pos: u64, bloom: B) -> io::Result<()> where ethbloom::BloomRef<'a>: From { + self.ensure_space_for_write(pos)?; + let mut old_bloom: ethbloom::Bloom = self.read_bloom(pos)?; + old_bloom.accrue_bloom(bloom); + let mut file_ref = &self.file; + file_ref.seek(SeekFrom::Start(pos * 256))?; + file_ref.write_all(&old_bloom) + } + + /// Replace bloom at given position with a new one. + pub fn replace_bloom<'a, B>(&mut self, pos: u64, bloom: B) -> io::Result<()> where ethbloom::BloomRef<'a>: From { + self.ensure_space_for_write(pos)?; + let mut file_ref = &self.file; + file_ref.seek(SeekFrom::Start(pos * 256))?; + file_ref.write_all(ethbloom::BloomRef::from(bloom).data()) + } + + /// Returns an iterator over file. + /// + /// This function needs to be mutable `fs::File` is just a shared reference a system file handle. + /// https://users.rust-lang.org/t/how-to-handle-match-with-irrelevant-ok--/6291/15 + pub fn iterator_from(&mut self, pos: u64) -> io::Result { + let mut buf_reader = io::BufReader::new(&self.file); + buf_reader.seek(SeekFrom::Start(pos * 256))?; + + let iter = FileIterator { + file: buf_reader, + }; + + Ok(iter) + } + + /// Flush outstanding modifications to the disk + pub fn flush(&mut self) -> io::Result<()> { + self.file.flush() + } +} + +/// Iterator over blooms of a single file. +pub struct FileIterator<'a> { + /// Backing file. + file: io::BufReader<&'a fs::File>, +} + +impl<'a> FileIterator<'a> { + /// Advance file by n blooms + pub fn advance(&mut self, n: u64) -> io::Result<()> { + self.file.seek(SeekFrom::Current(n as i64 * 256))?; + Ok(()) + } +} + +impl<'a> Iterator for FileIterator<'a> { + type Item = io::Result; + + fn next(&mut self) -> Option { + let mut bloom = ethbloom::Bloom::default(); + match self.file.read_exact(&mut bloom) { + Ok(_) => Some(Ok(bloom)), + Err(ref err) if err.kind() == io::ErrorKind::UnexpectedEof => None, + Err(err) => Some(Err(err)), + } + } +} + +#[cfg(test)] +mod tests { + use ethbloom::Bloom; + use tempdir::TempDir; + use super::File; + + #[test] + fn test_file() { + let tempdir = TempDir::new("").unwrap(); + let mut file = File::open(tempdir.path().join("file")).unwrap(); + file.accrue_bloom(0, &Bloom::from(1)).unwrap(); + file.flush().unwrap(); + assert_eq!(file.read_bloom(0).unwrap(), Bloom::from(1)); + + } +} diff --git a/util/blooms-db/src/lib.rs b/util/blooms-db/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..c638154229b3f02d692f848b35d1f4db0e46ce6b --- /dev/null +++ b/util/blooms-db/src/lib.rs @@ -0,0 +1,86 @@ +// 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 . + +//! Ethereum blooms database + +extern crate byteorder; +extern crate ethbloom; +extern crate parking_lot; +extern crate tiny_keccak; + +#[cfg(test)] +extern crate tempdir; + +mod db; +mod file; + +use std::io; +use std::path::Path; +use parking_lot::Mutex; + +/// Threadsafe API for blooms database. +/// +/// # Warning +/// +/// This database does not guarantee atomic writes. +pub struct Database { + database: Mutex, +} + +impl Database { + /// Creates new database handle. + /// + /// # Arguments + /// + /// * `path` - database directory + pub fn open

(path: P) -> io::Result where P: AsRef { + let result = Database { + database: Mutex::new(db::Database::open(path)?), + }; + + Ok(result) + } + + /// Reopens database at the same location. + pub fn reopen(&self) -> io::Result<()> { + self.database.lock().reopen() + } + + /// Inserts one or more blooms into database. + /// + /// # Arguments + /// + /// * `from` - index of the first bloom that needs to be inserted + /// * `blooms` - iterator over blooms + pub fn insert_blooms<'a, I, B>(&self, from: u64, blooms: I) -> io::Result<()> + where ethbloom::BloomRef<'a>: From, I: Iterator { + self.database.lock().insert_blooms(from, blooms) + } + + /// Returns indexes of all headers matching given bloom in a specified range. + /// + /// # Arguments + /// + /// * `from` - index of the first bloom that needs to be checked + /// * `to` - index of the last bloom that needs to be checked (inclusive range) + /// * `blooms` - searched pattern + pub fn filter<'a, B, I, II>(&self, from: u64, to: u64, blooms: II) -> io::Result> + where ethbloom::BloomRef<'a>: From, II: IntoIterator + Copy, I: Iterator { + self.database.lock() + .iterate_matching(from, to, blooms)? + .collect::, _>>() + } +} diff --git a/util/bytes/Cargo.toml b/util/bytes/Cargo.toml deleted file mode 100644 index b20e38a2aad7092ad2925ef9c353924b15f000a4..0000000000000000000000000000000000000000 --- a/util/bytes/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "ethcore-bytes" -version = "0.1.0" -authors = ["Parity Technologies "] -description = "byte utilities for Parity" -license = "GPL-3.0" - -[dependencies] diff --git a/util/bytes/src/lib.rs b/util/bytes/src/lib.rs deleted file mode 100644 index 4303f7015012a71f5afcc4d53a3b613d83251e74..0000000000000000000000000000000000000000 --- a/util/bytes/src/lib.rs +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2015-2017 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 bytes-related utilities. -//! -//! Includes a pretty-printer for bytes, in the form of `ToPretty` and `PrettySlice` -//! as - -use std::fmt; -use std::cmp::min; -use std::ops::{Deref, DerefMut}; - -/// Slice pretty print helper -pub struct PrettySlice<'a> (&'a [u8]); - -impl<'a> fmt::Debug for PrettySlice<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for i in 0..self.0.len() { - match i > 0 { - true => { write!(f, "·{:02x}", self.0[i])?; }, - false => { write!(f, "{:02x}", self.0[i])?; }, - } - } - Ok(()) - } -} - -impl<'a> fmt::Display for PrettySlice<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for i in 0..self.0.len() { - write!(f, "{:02x}", self.0[i])?; - } - Ok(()) - } -} - -/// Trait to allow a type to be pretty-printed in `format!`, where unoverridable -/// defaults cannot otherwise be avoided. -pub trait ToPretty { - /// Convert a type into a derivative form in order to make `format!` print it prettily. - fn pretty(&self) -> PrettySlice; - /// Express the object as a hex string. - fn to_hex(&self) -> String { - format!("{}", self.pretty()) - } -} - -impl> ToPretty for T { - fn pretty(&self) -> PrettySlice { - PrettySlice(self.as_ref()) - } -} - -/// A byte collection reference that can either be a slice or a vector -pub enum BytesRef<'a> { - /// This is a reference to a vector - Flexible(&'a mut Bytes), - /// This is a reference to a slice - Fixed(&'a mut [u8]) -} - -impl<'a> BytesRef<'a> { - /// Writes given `input` to this `BytesRef` starting at `offset`. - /// Returns number of bytes written to the ref. - /// NOTE can return number greater then `input.len()` in case flexible vector had to be extended. - pub fn write(&mut self, offset: usize, input: &[u8]) -> usize { - match *self { - BytesRef::Flexible(ref mut data) => { - let data_len = data.len(); - let wrote = input.len() + if data_len > offset { 0 } else { offset - data_len }; - - data.resize(offset, 0); - data.extend_from_slice(input); - wrote - }, - BytesRef::Fixed(ref mut data) if offset < data.len() => { - let max = min(data.len() - offset, input.len()); - for i in 0..max { - data[offset + i] = input[i]; - } - max - }, - _ => 0 - } - } -} - -impl<'a> Deref for BytesRef<'a> { - type Target = [u8]; - - fn deref(&self) -> &[u8] { - match *self { - BytesRef::Flexible(ref bytes) => bytes, - BytesRef::Fixed(ref bytes) => bytes, - } - } -} - -impl <'a> DerefMut for BytesRef<'a> { - fn deref_mut(&mut self) -> &mut [u8] { - match *self { - BytesRef::Flexible(ref mut bytes) => bytes, - BytesRef::Fixed(ref mut bytes) => bytes, - } - } -} - -/// Vector of bytes. -pub type Bytes = Vec; - -#[cfg(test)] -mod tests { - use super::BytesRef; - - #[test] - fn should_write_bytes_to_fixed_bytesref() { - // given - let mut data1 = vec![0, 0, 0]; - let mut data2 = vec![0, 0, 0]; - let (res1, res2) = { - let mut bytes1 = BytesRef::Fixed(&mut data1[..]); - let mut bytes2 = BytesRef::Fixed(&mut data2[1..2]); - - // when - let res1 = bytes1.write(1, &[1, 1, 1]); - let res2 = bytes2.write(3, &[1, 1, 1]); - (res1, res2) - }; - - // then - assert_eq!(&data1, &[0, 1, 1]); - assert_eq!(res1, 2); - - assert_eq!(&data2, &[0, 0, 0]); - assert_eq!(res2, 0); - } - - #[test] - fn should_write_bytes_to_flexible_bytesref() { - // given - let mut data1 = vec![0, 0, 0]; - let mut data2 = vec![0, 0, 0]; - let mut data3 = vec![0, 0, 0]; - let (res1, res2, res3) = { - let mut bytes1 = BytesRef::Flexible(&mut data1); - let mut bytes2 = BytesRef::Flexible(&mut data2); - let mut bytes3 = BytesRef::Flexible(&mut data3); - - // when - let res1 = bytes1.write(1, &[1, 1, 1]); - let res2 = bytes2.write(3, &[1, 1, 1]); - let res3 = bytes3.write(5, &[1, 1, 1]); - (res1, res2, res3) - }; - - // then - assert_eq!(&data1, &[0, 1, 1, 1]); - assert_eq!(res1, 3); - - assert_eq!(&data2, &[0, 0, 0, 1, 1, 1]); - assert_eq!(res2, 3); - - assert_eq!(&data3, &[0, 0, 0, 0, 0, 1, 1, 1]); - assert_eq!(res3, 5); - } -} diff --git a/util/dir/Cargo.toml b/util/dir/Cargo.toml index e1a13401a25ee855d41e6ba37d28d20460c4c1e9..092d45408456bda238f27a1aa801e02d613990e8 100644 --- a/util/dir/Cargo.toml +++ b/util/dir/Cargo.toml @@ -1,7 +1,8 @@ [package] name = "dir" -version = "0.1.0" +version = "0.1.1" authors = ["Parity Technologies "] +license = "GPL3" [dependencies] ethereum-types = "0.3" diff --git a/util/dir/src/helpers.rs b/util/dir/src/helpers.rs index 95f8090c87834c8e8a78ee8947b1cdffaef50a2c..820b9dc5af65db3392fcc02db0141ed3f67a05ba 100644 --- a/util/dir/src/helpers.rs +++ b/util/dir/src/helpers.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/dir/src/lib.rs b/util/dir/src/lib.rs index bb36a46a834261e603d9e85fd5ec5da42c4fc760..aac672b1f25047b0663064046fe61522ec8ca29a 100644 --- a/util/dir/src/lib.rs +++ b/util/dir/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -31,19 +31,23 @@ use app_dirs::{AppInfo, get_app_root, AppDataType}; // re-export platform-specific functions use platform::*; -/// Platform-specific chains path - Windows only -#[cfg(target_os = "windows")] pub const CHAINS_PATH: &'static str = "$LOCAL/chains"; -/// Platform-specific chains path -#[cfg(not(target_os = "windows"))] pub const CHAINS_PATH: &'static str = "$BASE/chains"; +/// Platform-specific chains path for standard client - Windows only +#[cfg(target_os = "windows")] pub const CHAINS_PATH: &str = "$LOCAL/chains"; +/// Platform-specific chains path for light client - Windows only +#[cfg(target_os = "windows")] pub const CHAINS_PATH_LIGHT: &str = "$LOCAL/chains_light"; +/// Platform-specific chains path for standard client +#[cfg(not(target_os = "windows"))] pub const CHAINS_PATH: &str = "$BASE/chains"; +/// Platform-specific chains path for light client +#[cfg(not(target_os = "windows"))] pub const CHAINS_PATH_LIGHT: &str = "$BASE/chains_light"; /// 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 @@ -58,8 +62,6 @@ pub struct Directories { pub keys: String, /// Signer dir pub signer: String, - /// Dir to store dapps - pub dapps: String, /// Secrets dir pub secretstore: String, } @@ -74,7 +76,6 @@ impl Default for Directories { cache: replace_home_and_local(&data_dir, &local_dir, CACHE_PATH), keys: replace_home(&data_dir, "$BASE/keys"), signer: replace_home(&data_dir, "$BASE/signer"), - dapps: replace_home(&data_dir, "$BASE/dapps"), secretstore: replace_home(&data_dir, "$BASE/secretstore"), } } @@ -82,7 +83,7 @@ impl Default for Directories { impl Directories { /// Create local directories - pub fn create_dirs(&self, dapps_enabled: bool, signer_enabled: bool, secretstore_enabled: bool) -> Result<(), String> { + pub fn create_dirs(&self, signer_enabled: bool, secretstore_enabled: bool) -> Result<(), String> { fs::create_dir_all(&self.base).map_err(|e| e.to_string())?; fs::create_dir_all(&self.db).map_err(|e| e.to_string())?; fs::create_dir_all(&self.cache).map_err(|e| e.to_string())?; @@ -90,9 +91,6 @@ impl Directories { if signer_enabled { fs::create_dir_all(&self.signer).map_err(|e| e.to_string())?; } - if dapps_enabled { - fs::create_dir_all(&self.dapps).map_err(|e| e.to_string())?; - } if secretstore_enabled { fs::create_dir_all(&self.secretstore).map_err(|e| e.to_string())?; } @@ -262,9 +260,9 @@ pub fn parity(chain: &str) -> PathBuf { #[cfg(target_os = "macos")] 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(); @@ -286,9 +284,9 @@ mod platform { #[cfg(windows)] mod platform { use std::path::PathBuf; - pub const AUTHOR: &'static str = "Parity"; - pub const PRODUCT: &'static str = "Ethereum"; - pub const PRODUCT_HYPERVISOR: &'static str = "EthereumUpdates"; + pub const AUTHOR: &str = "Parity"; + pub const PRODUCT: &str = "Ethereum"; + pub const PRODUCT_HYPERVISOR: &str = "EthereumUpdates"; pub fn parity_base() -> PathBuf { let mut home = super::home(); @@ -312,9 +310,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(); @@ -353,7 +351,6 @@ mod tests { ), keys: replace_home(&data_dir, "$BASE/keys"), signer: replace_home(&data_dir, "$BASE/signer"), - dapps: replace_home(&data_dir, "$BASE/dapps"), secretstore: replace_home(&data_dir, "$BASE/secretstore"), }; assert_eq!(expected, Directories::default()); diff --git a/util/error/Cargo.toml b/util/error/Cargo.toml deleted file mode 100644 index d9da3e5c516f93bc694e9f8b088edd3471446541..0000000000000000000000000000000000000000 --- a/util/error/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "util-error" -version = "0.1.0" -authors = ["Parity Technologies "] - -[dependencies] -rlp = { path = "../rlp" } -kvdb = { path = "../kvdb" } -ethereum-types = "0.3" -error-chain = { version = "0.11", 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 9a1ab875364f27d654e70e67342ceb888a07a386..0000000000000000000000000000000000000000 --- a/util/error/src/lib.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2015-2017 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; -extern crate kvdb; - -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; - } - - links { - Db(kvdb::Error, kvdb::ErrorKind); - } - - foreign_links { - Io(::std::io::Error); - FromHex(FromHexError); - Decoder(DecoderError); - BaseData(BaseDataError); - } -} - diff --git a/util/fake-hardware-wallet/Cargo.toml b/util/fake-hardware-wallet/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..600cd098c5d650dfd0696d29ac2af60f45e06828 --- /dev/null +++ b/util/fake-hardware-wallet/Cargo.toml @@ -0,0 +1,10 @@ +[package] +description = "Fake hardware-wallet, for OS' that don't support libusb" +name = "fake-hardware-wallet" +version = "0.0.1" +license = "GPL-3.0" +authors = ["Parity Technologies "] + +[dependencies] +ethereum-types = "0.3" +ethkey = { path = "../../ethkey" } diff --git a/util/fake-hardware-wallet/src/lib.rs b/util/fake-hardware-wallet/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..2bf905d7bf7fd1a6925a64b2257738b3251731f9 --- /dev/null +++ b/util/fake-hardware-wallet/src/lib.rs @@ -0,0 +1,101 @@ +// 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 . + +//! Dummy module for platforms that does not provide support for hardware wallets (libusb) + +extern crate ethereum_types; +extern crate ethkey; + +use std::fmt; +use ethereum_types::U256; +use ethkey::{Address, Signature}; + +pub struct WalletInfo { + pub address: Address, + pub name: String, + pub manufacturer: String, +} + +#[derive(Debug)] +/// `ErrorType` for devices with no `hardware wallet` +pub enum Error { + NoWallet, + KeyNotFound, +} + +pub struct TransactionInfo { + /// Nonce + pub nonce: U256, + /// Gas price + pub gas_price: U256, + /// Gas limit + pub gas_limit: U256, + /// Receiver + pub to: Option

, + /// Value + pub value: U256, + /// Data + pub data: Vec, + /// Chain ID + pub chain_id: Option, +} + +pub enum KeyPath { + /// Ethereum. + Ethereum, + /// Ethereum classic. + EthereumClassic, +} + +/// `HardwareWalletManager` for devices with no `hardware wallet` +pub struct HardwareWalletManager; + +impl HardwareWalletManager { + pub fn new() -> Result { + Err(Error::NoWallet) + } + + pub fn set_key_path(&self, _key_path: KeyPath) {} + + pub fn wallet_info(&self, _: &Address) -> Option { + None + } + + pub fn list_wallets(&self) -> Vec { + Vec::with_capacity(0) + } + + pub fn list_locked_wallets(&self) -> Result, Error> { + Err(Error::NoWallet) + } + + pub fn pin_matrix_ack(&self, _: &str, _: &str) -> Result { + Err(Error::NoWallet) + } + + pub fn sign_transaction(&self, _address: &Address, _transaction: &TransactionInfo, _rlp_transaction: &[u8]) -> Result { + Err(Error::NoWallet) } + + pub fn sign_message(&self, _address: &Address, _msg: &[u8]) -> Result { + Err(Error::NoWallet) + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "No hardware wallet!!") + } +} diff --git a/util/fetch/Cargo.toml b/util/fetch/Cargo.toml index 98b1fc58234bb096a2f54b011bc28a65a44bb843..8f87c6c0f938200e1b6a346ae0cc71a7c120b153 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 9bb55aad0e032cb350dd791f7c5b5aecc3962e05..03a3a5a2c00889e18e0820471f51fd8199cff4fa 100644 --- a/util/fetch/src/client.rs +++ b/util/fetch/src/client.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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 f42aacec5b810dd285d4a258bf4e7b54702ae4f4..37225dfa1a4129e5b163cb136d0532c185d8ec1e 100644 --- a/util/fetch/src/lib.rs +++ b/util/fetch/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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/hash/Cargo.toml b/util/hash/Cargo.toml deleted file mode 100644 index 4ca503751aa9bd73c8d4a4a66d3741f296c2a032..0000000000000000000000000000000000000000 --- a/util/hash/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -description = "Rust bindings for tinykeccak C library" -homepage = "https://github.com/paritytech/keccak-hash" -readme = "README.md" -license = "GPL-3.0" -name = "keccak-hash" -version = "0.1.2" -authors = ["Parity Technologies "] - -[dependencies] -ethereum-types = "0.3" -tiny-keccak = "1.4" - -[dev-dependencies] -tempdir = "0.3" diff --git a/util/hash/benches/keccak_256.rs b/util/hash/benches/keccak_256.rs deleted file mode 100644 index 8b398417d8b5694af4e8fe5975a871d76e581a03..0000000000000000000000000000000000000000 --- a/util/hash/benches/keccak_256.rs +++ /dev/null @@ -1,36 +0,0 @@ -#![feature(test)] - -extern crate test; -extern crate ethereum_types; -extern crate keccak_hash; - -use keccak_hash::{keccak, write_keccak}; -use test::Bencher; - -#[bench] -fn bench_keccak_256_with_empty_input(b: &mut Bencher) { - let empty = [0u8;0]; - b.bytes = empty.len() as u64; - b.iter(|| { - let _out = keccak(empty); - }) -} - -#[bench] -fn bench_keccak_256_with_typical_input(b: &mut Bencher) { - let data: Vec = From::from("some medum length string with important information"); - b.bytes = data.len() as u64; - b.iter(|| { - let _out = keccak(&data); - }) -} - -#[bench] -fn bench_keccak_256_with_large_input(b: &mut Bencher) { - // 4096 chars - let data: Vec = From::from("IGxcKBr1Qp7tuqtpSVhAbvt7UgWLEi7mCA6Wa185seLSIJLFS8K1aAFO9AwtO9b3n9SM3Qg136JMmy9Mj9gZ84IaUm8XioPtloabFDU5ZR1wvauJT6jNTkvBVBpUigIsyU7C1u3s99vKP64LpXqvo1hwItZKtISxmUAgzzjv5q14V4G9bkKAnmc4M5xixgLsDGZmnj6HcOMY3XRkWtxN3RscSKwPA0bfpgtz27ZVHplbXwloYRgRLpjRhZJc7sqO8RFnTHKasVkxVRcUoDBvWNJK27TbLvQQcfxETI2Q1H6c2cBAchi8unSiuxqy5rIvVxcl9rsmmRY4IXLEG9qKntUGbiIRLjEffIP9ODoWog0GbWLmMtfvtf24hWVwXz6Ap5oUAR0kLgb7HYIYrOwKjvfV25iEF7GW8cjhl8yowXx1zcgW4t6NJNqJlGzRKx8MvRWQXvHz8h8JxcHl7S64i6PAkxI9eCLXLvs8cpbEQQHt05Zu6GKm6IInjc9mSh52WFuGhgjbno69XzfkBufJs6c9tZuBf6ErVPj4UxmT82ajCruDusk79Tlvb8oQMLjoplQc1alQaLQwSsMac9iVp9MiE3PeYnTTepJ1V10tp79fciDAnNPJgPcRfDYv0REcSFgR9Q7yWhbpPpyBjO7HwOykDQVGtV0ZbDFrFRygLAXagAIkOPc9HDfcBNID1Q2MGk8ijVWMyvmGz1wzbpNfFcQaSOm8olhwoLyHUGvkyXegh44iNsPBUvSicNxTTDowtMqO5azleuWEjzxCobYbASDopvl6JeJjRtEBBO5YCQJiHsYjlXh9QR5Q543GsqhzRLgcHNRSZYLMZqDmIABXZi8VRNJMZyWXDRKHOGDmcHWe55uZomW6FnyU0uSRKxxz66K0JWfxuFzzxAR0vR4ZZCTemgDRQuDwL1loC3KUMjDpU13jUgoPc4UJUVfwQ4f4BUY3X51Cfw9FLw4oX39KoFoiCP2Z6z27gZUY1IlE59WoXGLj4KjTp4C16ZihG080gfDIWlXnDEk3VwBuBFyKWARB63sGLrGnn27b1gHWMaop6sPvkQgWxkEKIqsxDIvXLZJg2s23V8Gqtt0FeA7R3RCvBysF4jNjQ7NiQTIQWQZ8G9gO4mEsftolSZv6FlSpNeBKIIwYWSO2R6vkgeiz06euE9bwwnenOjwPNGTGk8WHIOZBJ1hIP0ejVU2i2ca9ON0phSAnewqjo5W3PtZf2Q7mDvp9imuVWoy4t8XcZq8I2Un9jVjes9Xi0FLN2t71vLFWLWZmGDzwXxpqEgkARS1WjtJoYXCBmRnXEPj6jQfwMZWKPYSIrmOogxMVoWvA8wrof6utfJna9JezyTnrBJSCuGTSNmwwAXRLoFYxF1RITyN8mI2KmHSfvLXBrbE6kmAkjsm4XJb6kria7oUQQ1gzJuCyB7oNHjZTBFNhNa7VeQ1s1xLOwZXLOAjZ4MDTYKnF7giGJGyswb5KQxkOV9orbuAu6pJsjtql6h1UD3BcNUkG3oz8kJNepbuCN3vNCJcZOX1VrQi0PWkDwyvECrQ2E1CgbU6GpWatpg2sCTpo9W62pCcWBK2FKUFWqU3qo2T7T1Mk2ZtM6hE9I8op0M7xlGE91Mn7ea6aq93MWp7nvFlBvbaMIoeU4MpDx0BeOSkROY03ZBJ0x7K8nJrNUhAtvxp17c9oFk0VxLiuRbAAcwDUormOmpVXZNIcqnap4twEVYaSIowfcNojyUSrFL5nPc8ZG93WgNNl9rpUPZhssVml3DvXghI80A9SW3QauzohTQAX2bkWelFBHnuG2LKrsJ8en51N6CkjcS5b87y1DVMZELcZ1n5s8PCAA1wyn7OSZlgw00GRzch1YwMoHzBBgIUtMO9HrMyuhgqIPJP7KcKbQkKhtvBXKplX8SCfSlOwUkLwHNKm3HYVE0uVfJ91NAsUrGoCOjYiXYpoRT8bjAPWTm6fDlTq2sbPOyTMoc4xRasmiOJ7B0PT6UxPzCPImM4100sPFxp7Kofv4okKZWTPKTefeYiPefI3jRgfDtEIP9E6a35LZD75lBNMXYlAqL3qlnheUQD1WQimFTHiDsW6bmURptNvtkMjEXzXzpWbnyxBskUGTvP2YQjtSAhWliDXkv6t1x71cYav7TQbqvbIzMRQQsguSGYMbs8YIC4DC9ep5reWAfanlTxcxksbEhQ7FGzXOvcufeGnDl2C85gWfryVzwN7kOZiSEktFMOQ1ngRC23y1fCOiHQVQJ2nLnaW7GILb9wkN1mBTRuHsOefRJST0TnRxcn4bBq4MIibIitVyjPRy7G5XvPEcL4pFaW1HCPGm6pUOEEwTer32JObNGCyTFB1BI2cRLJu5BHPjgG3mmb0gGkGlIfh8D2b2amogpivqEn2r9Y1KOKQ8ufJvG2mYfkevco9DuEZ9Nmzkm6XkCTZaFMNHqbfQaKqsEYK7i2N1KfkBct1leW2H9MQ9QO7AHCqXHK47b1kWVIm6pSJA1yV4funzCqXnIJCEURQgHiKf38YpN7ylLhe1J4UvSG3KeesZNeFFIZOEP9HZUSFMpnN1MOrwejojK0D4qzwucYWtXrTQ8I7UP5QhlijIsCKckUa9C1Osjrq8cgSclYNGt19wpy0onUbX1rOQBUlAAUJs4CyXNU0wmVUjw7tG1LUC8my4s9KZDUj4R5UcPz3VaZRrx1RqYu6YxjroJW70I1LyG4WEiQbOkCoLmaiWo9WzbUS2cErlOo2RPymlkWHxbNnZawX2Bc872ivRHSWqNpRHyuR5QewXmcyghH3EhESBAxTel5E2xuQXfLCEVK0kEk0Mj22KPsckKKyH7sVYC1F4YItQh5hj9Titb7KflQb9vnXQ44UHxY3zBhTQT5PSYv1Kv8HxXCsnpmhZCiBru16iX9oEB33icBVB2KKcZZEEKnCGPVxJlM9RTlyNyQmjHf7z4GeTDuMAUrsMO31WvgZBnWcAOtn6ulBTUCAaqxJiWqzlMx2FSANAlyAjAxqzmQjzPLvQRjskUnBFN3woKB1m2bSo2c5thwA1fKiPvN5LW8tl1rnfNy3rJ0GJpK8nZjkzHMztYrKYAe56pX4SvplpTyibTIiRXLyEVsmuByTHCZhO3fvGoFsav3ZuRhe9eAAWeqAh13eKDTcA0ufME3ZnmJheXEZ3OwrxnFjSf3U0clkWYVont3neh77ODKHhYnX0bOmnJJlr4RqFoLBitskY0kcGMKcZlaej21SENjDcFgaka3CfHbAH5vIFqnoX1JZrZPkQ65PZqQWImP79U3gXWKvz96lElyJZAFqn0Mbltllqw4MhlI766AvHraOmMsJoNvjv1QR7pCSnC0iX6nbqW1eVPaUSZDuZRtRIxfLA8HC9VbxufT2KZV3qG0l7wrZna5Di2MNcBE9uthuVLZcqp8vCmEhINDhRRlipR7tC2iRBHecS5WtxBCpbEm1y1kgNG5o60UKgAswxxuJ3RQ9Y49mPIApBMmp4LFpuKRfcrZb4UJnCfR3pNbQ70nnZ6Be2M7tuJUCoFfHrhqHXNz5A0uWMgxUS50c60zLl6QAELxHaCGba4WCMOHIo5nSKcUuYtDyDoDlrezALW5mZR4PRPRxnjrXxbJI14qrpymRReC3QgFDJp6sT5TLwvSHaavPlEbt2Eu0Kh5SXklGHXP9YuF3glGuJzSob3NakW1RXF5786U1MHhtJby64LyGWvNn4QXie3VjeL3QQu4C9crEAxSSiOJOfnL3DYIVOY4ipUkKFlF7Rp2q6gZazDvcUCp1cbcr7T7B4s22rXzjN7mHYWOyWuZGwlImeorY3aVKi7BaXbhgOFw6BUmIc1HeGFELHIEnPE9MwOjZam3LOm0rhBHlvJJZkXvJKmDUJrGlyqC5GtC5lDWLfXewyDWDqq7PY0atVQily5GWqib6wub6u6LZ3HZDNP8gK64Nf4kC259AE4V2hCohDnSsXAIoOkehwXyp6CkDT42NJb6sXHUv2N6cm292MiKA22PKWrwUGsan599KI2V67YRDfcfiB4ZHRDiSe62MBE0fGLIgXLIWw1xTWYbPQ9YAj3xovBvmewbJ1De4k6uS"); - b.bytes = data.len() as u64; - b.iter(|| { - let _out = keccak(&data); - }) -} \ No newline at end of file diff --git a/util/hash/src/lib.rs b/util/hash/src/lib.rs deleted file mode 100644 index b75e095a681d71f76025a9f918b663a1b8580f68..0000000000000000000000000000000000000000 --- a/util/hash/src/lib.rs +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2015-2017 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 . - -extern crate ethereum_types; -extern crate tiny_keccak; - -use std::io; -use std::slice; -use tiny_keccak::Keccak; - -pub use ethereum_types::H256; - -/// Get the KECCAK (i.e. Keccak) hash of the empty bytes string. -pub const KECCAK_EMPTY: H256 = H256( [0xc5, 0xd2, 0x46, 0x01, 0x86, 0xf7, 0x23, 0x3c, 0x92, 0x7e, 0x7d, 0xb2, 0xdc, 0xc7, 0x03, 0xc0, 0xe5, 0x00, 0xb6, 0x53, 0xca, 0x82, 0x27, 0x3b, 0x7b, 0xfa, 0xd8, 0x04, 0x5d, 0x85, 0xa4, 0x70] ); - -/// The KECCAK of the RLP encoding of empty data. -pub const KECCAK_NULL_RLP: 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] ); - -/// The KECCAK of the RLP encoding of empty list. -pub const KECCAK_EMPTY_LIST_RLP: H256 = H256( [0x1d, 0xcc, 0x4d, 0xe8, 0xde, 0xc7, 0x5d, 0x7a, 0xab, 0x85, 0xb5, 0x67, 0xb6, 0xcc, 0xd4, 0x1a, 0xd3, 0x12, 0x45, 0x1b, 0x94, 0x8a, 0x74, 0x13, 0xf0, 0xa1, 0x42, 0xfd, 0x40, 0xd4, 0x93, 0x47] ); - - -pub fn keccak>(s: T) -> H256 { - let mut result = [0u8; 32]; - write_keccak(s, &mut result); - H256(result) -} - -pub unsafe fn keccak_256_unchecked(out: *mut u8, outlen: usize, input: *const u8, inputlen: usize) { - // This is safe since `keccak_*` uses an internal buffer and copies the result to the output. This - // means that we can reuse the input buffer for both input and output. - Keccak::keccak256( - slice::from_raw_parts(input, inputlen), - slice::from_raw_parts_mut(out, outlen) - ); -} - -pub unsafe fn keccak_512_unchecked(out: *mut u8, outlen: usize, input: *const u8, inputlen: usize) { - // This is safe since `keccak_*` uses an internal buffer and copies the result to the output. This - // means that we can reuse the input buffer for both input and output. - Keccak::keccak512( - slice::from_raw_parts(input, inputlen), - slice::from_raw_parts_mut(out, outlen) - ); -} - -pub fn keccak_256(input: &[u8], mut output: &mut [u8]) { Keccak::keccak256(input, &mut output); } - -pub fn keccak_512(input: &[u8], mut output: &mut [u8]) { Keccak::keccak512(input, &mut output); } - -pub fn write_keccak>(s: T, dest: &mut [u8]) { Keccak::keccak256(s.as_ref(), dest); } - -pub fn keccak_pipe(r: &mut io::BufRead, w: &mut io::Write) -> Result { - let mut output = [0u8; 32]; - let mut input = [0u8; 1024]; - let mut keccak = Keccak::new_keccak256(); - - // read file - loop { - let some = r.read(&mut input)?; - if some == 0 { - break; - } - keccak.update(&input[0..some]); - w.write_all(&input[0..some])?; - } - - keccak.finalize(&mut output); - Ok(output.into()) -} - -pub fn keccak_buffer(r: &mut io::BufRead) -> Result { - keccak_pipe(r, &mut io::sink()) -} - -#[cfg(test)] -mod tests { - extern crate tempdir; - - use std::fs; - use std::io::{Write, BufReader}; - use self::tempdir::TempDir; - use super::{keccak, write_keccak, keccak_buffer, KECCAK_EMPTY}; - - #[test] - fn keccak_empty() { - assert_eq!(keccak([0u8; 0]), KECCAK_EMPTY); - } - - #[test] - fn keccak_as() { - assert_eq!(keccak([0x41u8; 32]), From::from("59cad5948673622c1d64e2322488bf01619f7ff45789741b15a9f782ce9290a8")); - } - - #[test] - fn write_keccak_with_content() { - let data: Vec = From::from("hello world"); - let expected = vec![ - 0x47, 0x17, 0x32, 0x85, 0xa8, 0xd7, 0x34, 0x1e, - 0x5e, 0x97, 0x2f, 0xc6, 0x77, 0x28, 0x63, 0x84, - 0xf8, 0x02, 0xf8, 0xef, 0x42, 0xa5, 0xec, 0x5f, - 0x03, 0xbb, 0xfa, 0x25, 0x4c, 0xb0, 0x1f, 0xad - ]; - let mut dest = [0u8;32]; - write_keccak(data, &mut dest); - - assert_eq!(dest, expected.as_ref()); - } - - #[test] - fn should_keccak_a_file() { - // given - let tempdir = TempDir::new("keccak").unwrap(); - let mut path = tempdir.path().to_owned(); - path.push("should_keccak_a_file"); - // Prepare file - { - let mut file = fs::File::create(&path).unwrap(); - file.write_all(b"something").unwrap(); - } - - let mut file = BufReader::new(fs::File::open(&path).unwrap()); - // when - let hash = keccak_buffer(&mut file).unwrap(); - - // then - assert_eq!(format!("{:x}", hash), "68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"); - } -} diff --git a/util/hashdb/Cargo.toml b/util/hashdb/Cargo.toml deleted file mode 100644 index d4e055f9ff0e844248703b85d7f010cd593238fb..0000000000000000000000000000000000000000 --- a/util/hashdb/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "hashdb" -version = "0.1.1" -authors = ["Parity Technologies "] -description = "trait for hash-keyed databases." -license = "GPL-3.0" - -[dependencies] -elastic-array = "0.10" -ethereum-types = "0.3" diff --git a/util/hashdb/src/lib.rs b/util/hashdb/src/lib.rs deleted file mode 100644 index b65f304e423673f0d7dcb9b84a264b602866dca4..0000000000000000000000000000000000000000 --- a/util/hashdb/src/lib.rs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Database of byte-slices keyed to their Keccak hash. -extern crate elastic_array; -extern crate ethereum_types; - -use std::collections::HashMap; -use elastic_array::ElasticArray128; -use ethereum_types::H256; - -/// `HashDB` value type. -pub type DBValue = ElasticArray128; - -/// Trait modelling datastore keyed by a 32-byte Keccak hash. -pub trait HashDB: AsHashDB + Send + Sync { - /// Get the keys in the database together with number of underlying references. - 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; - - /// Check for the existance of a hash-key. - fn contains(&self, key: &H256) -> 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; - - /// Like `insert()` , except you provide the key and the data is all moved. - fn emplace(&mut self, key: H256, 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); -} - -/// Upcast trait. -pub trait AsHashDB { - /// Perform upcast to HashDB for anything that derives from 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; -} - -impl AsHashDB for T { - fn as_hashdb(&self) -> &HashDB { - self - } - fn as_hashdb_mut(&mut self) -> &mut HashDB { - 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 71688661605f4f5c457c383bbe2c656f6d136357..0e1dfbbc10ac39a6a0ece811e084cb40af4f4a08 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/io/src/lib.rs b/util/io/src/lib.rs index cd635121fffa86fe2ef3ada9fa0d015e93bde592..02dbf223be408ffd70bb690f8eb289d61f65ed7b 100644 --- a/util/io/src/lib.rs +++ b/util/io/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/io/src/service_mio.rs b/util/io/src/service_mio.rs index 2ae3d55e0ffc6b8ad5910a82b1997a0ad95ca8a2..089d54cc45859d9cf313fe6bbe6338b1fbdf242d 100644 --- a/util/io/src/service_mio.rs +++ b/util/io/src/service_mio.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/io/src/service_non_mio.rs b/util/io/src/service_non_mio.rs index 22a795e4e8df04ab887216ababcc2f0d021b4745..315f84c4d1d0822068a91ee506fc781522ee0588 100644 --- a/util/io/src/service_non_mio.rs +++ b/util/io/src/service_non_mio.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/io/src/worker.rs b/util/io/src/worker.rs index 89657810dcfdb24814db57a9dc1898136579a7fd..da144afea492ee0e213b5ad3f19f1687e10a6c8f 100644 --- a/util/io/src/worker.rs +++ b/util/io/src/worker.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/journaldb/Cargo.toml b/util/journaldb/Cargo.toml index dea70bd6a4361835a7fbb00e709a7ca7c62d5891..27b0ae195b7acc1eac714fce44a2994d895e4746 100644 --- a/util/journaldb/Cargo.toml +++ b/util/journaldb/Cargo.toml @@ -1,24 +1,24 @@ [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" [dependencies] -ethcore-bytes = { path = "../bytes" } +parity-bytes = { git = "https://github.com/paritytech/parity-common" } ethereum-types = "0.3" -hashdb = { path = "../hashdb" } +hashdb = { git = "https://github.com/paritytech/parity-common" } heapsize = "0.4" -kvdb = { path = "../kvdb" } +keccak-hasher = { path = "../keccak-hasher" } +kvdb = { git = "https://github.com/paritytech/parity-common" } log = "0.3" -memorydb = { path = "../memorydb" } -parking_lot = "0.5" -plain_hasher = { path = "../plain_hasher" } -rlp = { path = "../rlp" } -util-error = { path = "../error" } +memorydb = { git = "https://github.com/paritytech/parity-common" } +parking_lot = "0.6" +plain_hasher = { git = "https://github.com/paritytech/parity-common" } +rlp = { git = "https://github.com/paritytech/parity-common" } [dev-dependencies] ethcore-logger = { path = "../../logger" } -keccak-hash = { path = "../hash" } -kvdb-memorydb = { path = "../kvdb-memorydb" } +keccak-hash = { git = "https://github.com/paritytech/parity-common" } +kvdb-memorydb = { git = "https://github.com/paritytech/parity-common" } diff --git a/util/journaldb/src/archivedb.rs b/util/journaldb/src/archivedb.rs index b58558a332af59adb9590dcd410dcc08fd9b44d2..3993887e470c32d1b2638ca5b59259746ae89ae2 100644 --- a/util/journaldb/src/archivedb.rs +++ b/util/journaldb/src/archivedb.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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 0000000000000000000000000000000000000000..bd3b0e2d76f315d2dcb49eae7a3aab236d816559 --- /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 c26a67e0ad262a3b3fa042a26f96772f78b631a1..68b8675af588cfa602990cf3a8f0b7a5ca9a3e31 100644 --- a/util/journaldb/src/earlymergedb.rs +++ b/util/journaldb/src/earlymergedb.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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(), @@ -394,7 +396,6 @@ impl JournalDB for EarlyMergeDB { .filter_map(|(k, (v, r))| if r > 0 { assert!(r == 1); Some((k, v)) } else { assert!(r >= -1); None }) .collect(); - // TODO: check all removes are in the db. // Process the new inserts. @@ -425,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 @@ -487,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 } @@ -496,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) } @@ -513,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 c1fb23b6cd15eff9e685d40cbded05016772fc3b..b14ef88e9238c48ebbcda8bf2e3e0937665f87ee 100644 --- a/util/journaldb/src/lib.rs +++ b/util/journaldb/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -21,14 +21,14 @@ extern crate heapsize; extern crate log; extern crate ethereum_types; -extern crate ethcore_bytes as bytes; +extern crate parity_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 54d0bb12d7691f327bdbdefc68a592e7b5387831..f4b20b2193b72d3b72f22550387eb1e7b431c2ce 100644 --- a/util/journaldb/src/overlaydb.rs +++ b/util/journaldb/src/overlaydb.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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 2c9ce5cb1ddcd422b57df842438ff846c9a43588..b63168e547cf28bb75f5af5b7a9bbaf33abe44db 100644 --- a/util/journaldb/src/overlayrecentdb.rs +++ b/util/journaldb/src/overlayrecentdb.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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 d182d5cf803476de90df8123d2cca7d8e3578ddd..7cbe9022d813cd1d9d1e85f7bcecda60de317f37 100644 --- a/util/journaldb/src/refcounteddb.rs +++ b/util/journaldb/src/refcounteddb.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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 aaf5b27970141962d0cfc16142f95d94273e3f5c..075a546005bc1fa9ea966ac2d1dc9b69bd0d74b3 100644 --- a/util/journaldb/src/traits.rs +++ b/util/journaldb/src/traits.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -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 0000000000000000000000000000000000000000..0367b17673be7f51435dd1bc63271e2d401f3a5d --- /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 = { git = "https://github.com/paritytech/parity-common" } +plain_hasher = { git = "https://github.com/paritytech/parity-common" } \ No newline at end of file diff --git a/dapps/ui-deprecation/src/lib.rs b/util/keccak-hasher/src/lib.rs similarity index 54% rename from dapps/ui-deprecation/src/lib.rs rename to util/keccak-hasher/src/lib.rs index 79a4a424974881c576340e32cf67e98560bf6146..bb2b5b45ffe1ba342246eb071e66169905f7bc8e 100644 --- a/dapps/ui-deprecation/src/lib.rs +++ b/util/keccak-hasher/src/lib.rs @@ -14,8 +14,26 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -#[cfg(feature = "with-syntex")] -include!(concat!(env!("OUT_DIR"), "/lib.rs")); +//! Hasher implementation for the Keccak-256 hash +extern crate hashdb; +extern crate ethereum_types; +extern crate tiny_keccak; +extern crate plain_hasher; -#[cfg(not(feature = "with-syntex"))] -include!("lib.rs.in"); +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 deleted file mode 100644 index 4dbad628c4243cd36b3e379aa1f3b0472ff66f36..0000000000000000000000000000000000000000 --- a/util/kvdb-memorydb/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "kvdb-memorydb" -version = "0.1.0" -authors = ["Parity Technologies "] - -[dependencies] -parking_lot = "0.5" -kvdb = { path = "../kvdb" } diff --git a/util/kvdb-memorydb/src/lib.rs b/util/kvdb-memorydb/src/lib.rs deleted file mode 100644 index 0530c613e3185e95268469859a5fddb3edd386bd..0000000000000000000000000000000000000000 --- a/util/kvdb-memorydb/src/lib.rs +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2015-2017 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 . - -extern crate parking_lot; -extern crate kvdb; - -use std::collections::{BTreeMap, HashMap}; -use parking_lot::RwLock; -use kvdb::{DBValue, DBTransaction, KeyValueDB, DBOp, Result}; - -/// A key-value database fulfilling the `KeyValueDB` trait, living in memory. -/// This is generally intended for tests and is not particularly optimized. -#[derive(Default)] -pub struct InMemory { - columns: RwLock, BTreeMap, DBValue>>>, -} - -/// Create an in-memory database with the given number of columns. -/// Columns will be indexable by 0..`num_cols` -pub fn create(num_cols: u32) -> InMemory { - let mut cols = HashMap::new(); - cols.insert(None, BTreeMap::new()); - - for idx in 0..num_cols { - cols.insert(Some(idx), BTreeMap::new()); - } - - InMemory { - columns: RwLock::new(cols) - } -} - -impl KeyValueDB for InMemory { - fn get(&self, col: Option, key: &[u8]) -> Result> { - let columns = self.columns.read(); - match columns.get(&col) { - None => Err(format!("No such column family: {:?}", col).into()), - Some(map) => Ok(map.get(key).cloned()), - } - } - - fn get_by_prefix(&self, col: Option, prefix: &[u8]) -> Option> { - let columns = self.columns.read(); - match columns.get(&col) { - None => None, - Some(map) => - map.iter() - .find(|&(ref k ,_)| k.starts_with(prefix)) - .map(|(_, v)| v.to_vec().into_boxed_slice()) - } - } - - fn write_buffered(&self, transaction: DBTransaction) { - let mut columns = self.columns.write(); - let ops = transaction.ops; - for op in ops { - match op { - DBOp::Insert { col, key, value } => { - if let Some(col) = columns.get_mut(&col) { - col.insert(key.into_vec(), value); - } - }, - DBOp::Delete { col, key } => { - if let Some(col) = columns.get_mut(&col) { - col.remove(&*key); - } - }, - } - } - } - - fn flush(&self) -> Result<()> { - Ok(()) - } - - fn iter<'a>(&'a self, col: Option) -> Box, Box<[u8]>)> + 'a> { - match self.columns.read().get(&col) { - Some(map) => Box::new( // TODO: worth optimizing at all? - map.clone() - .into_iter() - .map(|(k, v)| (k.into_boxed_slice(), v.into_vec().into_boxed_slice())) - ), - None => Box::new(None.into_iter()), - } - } - - fn iter_from_prefix<'a>(&'a self, col: Option, prefix: &'a [u8]) - -> Box, Box<[u8]>)> + 'a> - { - match self.columns.read().get(&col) { - Some(map) => Box::new( - map.clone() - .into_iter() - .skip_while(move |&(ref k, _)| !k.starts_with(prefix)) - .map(|(k, v)| (k.into_boxed_slice(), v.into_vec().into_boxed_slice())) - ), - None => Box::new(None.into_iter()), - } - } - - fn restore(&self, _new_db: &str) -> Result<()> { - Err("Attempted to restore in-memory database".into()) - } -} diff --git a/util/kvdb-rocksdb/Cargo.toml b/util/kvdb-rocksdb/Cargo.toml deleted file mode 100644 index 07016b68a2de7feabec8f3c729ec35434f1a70e6..0000000000000000000000000000000000000000 --- a/util/kvdb-rocksdb/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "kvdb-rocksdb" -version = "0.1.0" -authors = ["Parity Technologies "] - -[dependencies] -elastic-array = "0.10" -ethereum-types = "0.3" -kvdb = { path = "../kvdb" } -log = "0.3" -num_cpus = "1.0" -parking_lot = "0.5" -regex = "0.2" -rocksdb = { git = "https://github.com/paritytech/rust-rocksdb" } -interleaved-ordered = "0.1.0" - -[dev-dependencies] -tempdir = "0.3" diff --git a/util/kvdb-rocksdb/src/lib.rs b/util/kvdb-rocksdb/src/lib.rs deleted file mode 100644 index 4f2220a11dd179637bbaba13db7b86e2580c8018..0000000000000000000000000000000000000000 --- a/util/kvdb-rocksdb/src/lib.rs +++ /dev/null @@ -1,860 +0,0 @@ -// Copyright 2015-2017 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 . - -#[macro_use] -extern crate log; - -extern crate elastic_array; -extern crate interleaved_ordered; -extern crate num_cpus; -extern crate parking_lot; -extern crate regex; -extern crate rocksdb; - -extern crate ethereum_types; -extern crate kvdb; - -use std::cmp; -use std::collections::HashMap; -use std::marker::PhantomData; -use std::path::{PathBuf, Path}; -use std::{fs, io, mem, result}; - -use parking_lot::{Mutex, MutexGuard, RwLock}; -use rocksdb::{ - DB, Writable, WriteBatch, WriteOptions, IteratorMode, DBIterator, - Options, BlockBasedOptions, Direction, Cache, Column, ReadOptions -}; -use interleaved_ordered::{interleave_ordered, InterleaveOrdered}; - -use elastic_array::ElasticArray32; -use kvdb::{KeyValueDB, DBTransaction, DBValue, DBOp, Result}; - -#[cfg(target_os = "linux")] -use regex::Regex; -#[cfg(target_os = "linux")] -use std::process::Command; -#[cfg(target_os = "linux")] -use std::fs::File; - -const DB_DEFAULT_MEMORY_BUDGET_MB: usize = 128; - -enum KeyState { - Insert(DBValue), - Delete, -} - -/// Compaction profile for the database settings -#[derive(Clone, Copy, PartialEq, Debug)] -pub struct CompactionProfile { - /// L0-L1 target file size - pub initial_file_size: u64, - /// block size - pub block_size: usize, - /// rate limiter for background flushes and compactions, bytes/sec, if any - pub write_rate_limit: Option, -} - -impl Default for CompactionProfile { - /// Default profile suitable for most storage - fn default() -> CompactionProfile { - CompactionProfile::ssd() - } -} - -/// Given output of df command return Linux rotational flag file path. -#[cfg(target_os = "linux")] -pub fn rotational_from_df_output(df_out: Vec) -> Option { - use std::str; - str::from_utf8(df_out.as_slice()) - .ok() - // Get the drive name. - .and_then(|df_str| Regex::new(r"/dev/(sd[:alpha:]{1,2})") - .ok() - .and_then(|re| re.captures(df_str)) - .and_then(|captures| captures.get(1))) - // Generate path e.g. /sys/block/sda/queue/rotational - .map(|drive_path| { - let mut p = PathBuf::from("/sys/block"); - p.push(drive_path.as_str()); - p.push("queue/rotational"); - p - }) -} - -impl CompactionProfile { - /// Attempt to determine the best profile automatically, only Linux for now. - #[cfg(target_os = "linux")] - pub fn auto(db_path: &Path) -> CompactionProfile { - use std::io::Read; - let hdd_check_file = db_path - .to_str() - .and_then(|path_str| Command::new("df").arg(path_str).output().ok()) - .and_then(|df_res| match df_res.status.success() { - true => Some(df_res.stdout), - false => None, - }) - .and_then(rotational_from_df_output); - // Read out the file and match compaction profile. - if let Some(hdd_check) = hdd_check_file { - if let Ok(mut file) = File::open(hdd_check.as_path()) { - let mut buffer = [0; 1]; - if file.read_exact(&mut buffer).is_ok() { - // 0 means not rotational. - if buffer == [48] { return Self::ssd(); } - // 1 means rotational. - if buffer == [49] { return Self::hdd(); } - } - } - } - // Fallback if drive type was not determined. - Self::default() - } - - /// Just default for other platforms. - #[cfg(not(target_os = "linux"))] - pub fn auto(_db_path: &Path) -> CompactionProfile { - Self::default() - } - - /// Default profile suitable for SSD storage - pub fn ssd() -> CompactionProfile { - CompactionProfile { - initial_file_size: 64 * 1024 * 1024, - block_size: 16 * 1024, - write_rate_limit: None, - } - } - - /// Slow HDD compaction profile - pub fn hdd() -> CompactionProfile { - CompactionProfile { - initial_file_size: 256 * 1024 * 1024, - block_size: 64 * 1024, - write_rate_limit: Some(16 * 1024 * 1024), - } - } -} - -/// Database configuration -#[derive(Clone)] -pub struct DatabaseConfig { - /// Max number of open files. - pub max_open_files: i32, - /// Memory budget (in MiB) used for setting block cache size, write buffer size. - pub memory_budget: Option, - /// Compaction profile - pub compaction: CompactionProfile, - /// Set number of columns - pub columns: Option, - /// Should we keep WAL enabled? - pub wal: bool, -} - -impl DatabaseConfig { - /// Create new `DatabaseConfig` with default parameters and specified set of columns. - /// Note that cache sizes must be explicitly set. - pub fn with_columns(columns: Option) -> Self { - let mut config = Self::default(); - config.columns = columns; - config - } - - pub fn memory_budget(&self) -> usize { - self.memory_budget.unwrap_or(DB_DEFAULT_MEMORY_BUDGET_MB) * 1024 * 1024 - } - - pub fn memory_budget_per_col(&self) -> usize { - self.memory_budget() / self.columns.unwrap_or(1) as usize - } -} - -impl Default for DatabaseConfig { - fn default() -> DatabaseConfig { - DatabaseConfig { - max_open_files: 512, - memory_budget: None, - compaction: CompactionProfile::default(), - columns: None, - wal: true, - } - } -} - -/// Database iterator (for flushed data only) -// The compromise of holding only a virtual borrow vs. holding a lock on the -// inner DB (to prevent closing via restoration) may be re-evaluated in the future. -// -pub struct DatabaseIterator<'a> { - iter: InterleaveOrdered<::std::vec::IntoIter<(Box<[u8]>, Box<[u8]>)>, DBIterator>, - _marker: PhantomData<&'a Database>, -} - -impl<'a> Iterator for DatabaseIterator<'a> { - type Item = (Box<[u8]>, Box<[u8]>); - - fn next(&mut self) -> Option { - self.iter.next() - } -} - -struct DBAndColumns { - db: DB, - cfs: Vec, -} - -// get column family configuration from database config. -fn col_config(config: &DatabaseConfig, block_opts: &BlockBasedOptions) -> Result { - let mut opts = Options::new(); - - opts.set_parsed_options("level_compaction_dynamic_level_bytes=true")?; - - opts.set_block_based_table_factory(block_opts); - - opts.set_parsed_options( - &format!("block_based_table_factory={{{};{}}}", - "cache_index_and_filter_blocks=true", - "pin_l0_filter_and_index_blocks_in_cache=true"))?; - - opts.optimize_level_style_compaction(config.memory_budget_per_col() as i32); - opts.set_target_file_size_base(config.compaction.initial_file_size); - - opts.set_parsed_options("compression_per_level=")?; - - Ok(opts) -} - -/// Key-Value database. -pub struct Database { - db: RwLock>, - config: DatabaseConfig, - write_opts: WriteOptions, - read_opts: ReadOptions, - block_opts: BlockBasedOptions, - path: String, - // Dirty values added with `write_buffered`. Cleaned on `flush`. - overlay: RwLock, KeyState>>>, - // Values currently being flushed. Cleared when `flush` completes. - flushing: RwLock, KeyState>>>, - // Prevents concurrent flushes. - // Value indicates if a flush is in progress. - flushing_lock: Mutex, -} - -#[inline] -fn check_for_corruption>(path: P, res: result::Result) -> result::Result { - if let Err(ref s) = res { - if s.starts_with("Corruption:") { - warn!("DB corrupted: {}. Repair will be triggered on next restart", s); - let _ = fs::File::create(path.as_ref().join(Database::CORRUPTION_FILE_NAME)); - } - } - - res -} - -fn is_corrupted(s: &str) -> bool { - s.starts_with("Corruption:") || s.starts_with("Invalid argument: You have to open all column families") -} - -impl Database { - const CORRUPTION_FILE_NAME: &'static str = "CORRUPTED"; - - /// Open database with default settings. - pub fn open_default(path: &str) -> Result { - Database::open(&DatabaseConfig::default(), path) - } - - /// Open database file. Creates if it does not exist. - pub fn open(config: &DatabaseConfig, path: &str) -> Result { - let mut opts = Options::new(); - - if let Some(rate_limit) = config.compaction.write_rate_limit { - opts.set_parsed_options(&format!("rate_limiter_bytes_per_sec={}", rate_limit))?; - } - opts.set_use_fsync(false); - opts.create_if_missing(true); - opts.set_max_open_files(config.max_open_files); - opts.set_parsed_options("keep_log_file_num=1")?; - opts.set_parsed_options("bytes_per_sync=1048576")?; - opts.set_db_write_buffer_size(config.memory_budget_per_col() / 2); - opts.increase_parallelism(cmp::max(1, ::num_cpus::get() as i32 / 2)); - - let mut block_opts = BlockBasedOptions::new(); - - { - block_opts.set_block_size(config.compaction.block_size); - let cache_size = cmp::max(8, config.memory_budget() / 3); - let cache = Cache::new(cache_size); - block_opts.set_cache(cache); - } - - // attempt database repair if it has been previously marked as corrupted - let db_corrupted = Path::new(path).join(Database::CORRUPTION_FILE_NAME); - if db_corrupted.exists() { - warn!("DB has been previously marked as corrupted, attempting repair"); - DB::repair(&opts, path)?; - fs::remove_file(db_corrupted)?; - } - - let columns = config.columns.unwrap_or(0) as usize; - - let mut cf_options = Vec::with_capacity(columns); - let cfnames: Vec<_> = (0..columns).map(|c| format!("col{}", c)).collect(); - let cfnames: Vec<&str> = cfnames.iter().map(|n| n as &str).collect(); - - for _ in 0 .. config.columns.unwrap_or(0) { - cf_options.push(col_config(&config, &block_opts)?); - } - - let mut write_opts = WriteOptions::new(); - if !config.wal { - write_opts.disable_wal(true); - } - let mut read_opts = ReadOptions::new(); - read_opts.set_verify_checksums(false); - - let mut cfs: Vec = Vec::new(); - let db = match config.columns { - Some(_) => { - match DB::open_cf(&opts, path, &cfnames, &cf_options) { - Ok(db) => { - cfs = cfnames.iter().map(|n| db.cf_handle(n) - .expect("rocksdb opens a cf_handle for each cfname; qed")).collect(); - Ok(db) - } - Err(_) => { - // retry and create CFs - match DB::open_cf(&opts, path, &[], &[]) { - Ok(mut db) => { - cfs = cfnames.iter().enumerate().map(|(i, n)| db.create_cf(n, &cf_options[i])).collect::<::std::result::Result<_, _>>()?; - Ok(db) - }, - err => err, - } - } - } - }, - None => DB::open(&opts, path) - }; - - let db = match db { - Ok(db) => db, - Err(ref s) if is_corrupted(s) => { - warn!("DB corrupted: {}, attempting repair", s); - DB::repair(&opts, path)?; - - match cfnames.is_empty() { - true => DB::open(&opts, path)?, - false => { - let db = DB::open_cf(&opts, path, &cfnames, &cf_options)?; - cfs = cfnames.iter().map(|n| db.cf_handle(n) - .expect("rocksdb opens a cf_handle for each cfname; qed")).collect(); - db - }, - } - }, - Err(s) => { return Err(s.into()); } - }; - let num_cols = cfs.len(); - Ok(Database { - db: RwLock::new(Some(DBAndColumns{ db: db, cfs: cfs })), - config: config.clone(), - write_opts: write_opts, - overlay: RwLock::new((0..(num_cols + 1)).map(|_| HashMap::new()).collect()), - flushing: RwLock::new((0..(num_cols + 1)).map(|_| HashMap::new()).collect()), - flushing_lock: Mutex::new(false), - path: path.to_owned(), - read_opts: read_opts, - block_opts: block_opts, - }) - } - - /// Helper to create new transaction for this database. - pub fn transaction(&self) -> DBTransaction { - DBTransaction::new() - } - - - fn to_overlay_column(col: Option) -> usize { - col.map_or(0, |c| (c + 1) as usize) - } - - /// Commit transaction to database. - pub fn write_buffered(&self, tr: DBTransaction) { - let mut overlay = self.overlay.write(); - let ops = tr.ops; - for op in ops { - match op { - DBOp::Insert { col, key, value } => { - let c = Self::to_overlay_column(col); - overlay[c].insert(key, KeyState::Insert(value)); - }, - DBOp::Delete { col, key } => { - let c = Self::to_overlay_column(col); - overlay[c].insert(key, KeyState::Delete); - }, - } - }; - } - - /// Commit buffered changes to database. Must be called under `flush_lock` - fn write_flushing_with_lock(&self, _lock: &mut MutexGuard) -> Result<()> { - match *self.db.read() { - Some(DBAndColumns { ref db, ref cfs }) => { - let batch = WriteBatch::new(); - mem::swap(&mut *self.overlay.write(), &mut *self.flushing.write()); - { - for (c, column) in self.flushing.read().iter().enumerate() { - for (ref key, ref state) in column.iter() { - match **state { - KeyState::Delete => { - if c > 0 { - batch.delete_cf(cfs[c - 1], &key)?; - } else { - batch.delete(&key)?; - } - }, - KeyState::Insert(ref value) => { - if c > 0 { - batch.put_cf(cfs[c - 1], &key, value)?; - } else { - batch.put(&key, &value)?; - } - }, - } - } - } - } - - check_for_corruption( - &self.path, - db.write_opt(batch, &self.write_opts))?; - - for column in self.flushing.write().iter_mut() { - column.clear(); - column.shrink_to_fit(); - } - Ok(()) - }, - None => Err("Database is closed".into()) - } - } - - /// Commit buffered changes to database. - pub fn flush(&self) -> Result<()> { - let mut lock = self.flushing_lock.lock(); - // If RocksDB batch allocation fails the thread gets terminated and the lock is released. - // The value inside the lock is used to detect that. - if *lock { - // This can only happen if another flushing thread is terminated unexpectedly. - return Err("Database write failure. Running low on memory perhaps?".into()); - } - *lock = true; - let result = self.write_flushing_with_lock(&mut lock); - *lock = false; - result - } - - /// Commit transaction to database. - pub fn write(&self, tr: DBTransaction) -> Result<()> { - match *self.db.read() { - Some(DBAndColumns { ref db, ref cfs }) => { - let batch = WriteBatch::new(); - let ops = tr.ops; - for op in ops { - // remove any buffered operation for this key - self.overlay.write()[Self::to_overlay_column(op.col())].remove(op.key()); - - match op { - DBOp::Insert { col, key, value } => { - col.map_or_else(|| batch.put(&key, &value), |c| batch.put_cf(cfs[c as usize], &key, &value))? - }, - DBOp::Delete { col, key } => { - col.map_or_else(|| batch.delete(&key), |c| batch.delete_cf(cfs[c as usize], &key))? - }, - } - } - - check_for_corruption( - &self.path, - db.write_opt(batch, &self.write_opts)).map_err(Into::into) - }, - None => Err("Database is closed".into()) - } - } - - /// Get value by key. - pub fn get(&self, col: Option, key: &[u8]) -> Result> { - match *self.db.read() { - Some(DBAndColumns { ref db, ref cfs }) => { - let overlay = &self.overlay.read()[Self::to_overlay_column(col)]; - match overlay.get(key) { - Some(&KeyState::Insert(ref value)) => Ok(Some(value.clone())), - Some(&KeyState::Delete) => Ok(None), - None => { - let flushing = &self.flushing.read()[Self::to_overlay_column(col)]; - match flushing.get(key) { - Some(&KeyState::Insert(ref value)) => Ok(Some(value.clone())), - Some(&KeyState::Delete) => Ok(None), - None => { - col.map_or_else( - || db.get_opt(key, &self.read_opts).map(|r| r.map(|v| DBValue::from_slice(&v))), - |c| db.get_cf_opt(cfs[c as usize], key, &self.read_opts).map(|r| r.map(|v| DBValue::from_slice(&v)))) - .map_err(Into::into) - }, - } - }, - } - }, - None => Ok(None), - } - } - - /// Get value by partial key. Prefix size should match configured prefix size. Only searches flushed values. - // TODO: support prefix seek for unflushed data - pub fn get_by_prefix(&self, col: Option, prefix: &[u8]) -> Option> { - self.iter_from_prefix(col, prefix).and_then(|mut iter| { - match iter.next() { - // TODO: use prefix_same_as_start read option (not availabele in C API currently) - Some((k, v)) => if k[0 .. prefix.len()] == prefix[..] { Some(v) } else { None }, - _ => None - } - }) - } - - /// Get database iterator for flushed data. - pub fn iter(&self, col: Option) -> Option { - match *self.db.read() { - Some(DBAndColumns { ref db, ref cfs }) => { - let overlay = &self.overlay.read()[Self::to_overlay_column(col)]; - let mut overlay_data = overlay.iter() - .filter_map(|(k, v)| match *v { - KeyState::Insert(ref value) => - Some((k.clone().into_vec().into_boxed_slice(), value.clone().into_vec().into_boxed_slice())), - KeyState::Delete => None, - }).collect::>(); - overlay_data.sort(); - - let iter = col.map_or_else( - || db.iterator_opt(IteratorMode::Start, &self.read_opts), - |c| db.iterator_cf_opt(cfs[c as usize], IteratorMode::Start, &self.read_opts) - .expect("iterator params are valid; qed") - ); - - Some(DatabaseIterator { - iter: interleave_ordered(overlay_data, iter), - _marker: PhantomData, - }) - }, - None => None, - } - } - - fn iter_from_prefix(&self, col: Option, prefix: &[u8]) -> Option { - match *self.db.read() { - Some(DBAndColumns { ref db, ref cfs }) => { - let iter = col.map_or_else(|| db.iterator_opt(IteratorMode::From(prefix, Direction::Forward), &self.read_opts), - |c| db.iterator_cf_opt(cfs[c as usize], IteratorMode::From(prefix, Direction::Forward), &self.read_opts) - .expect("iterator params are valid; qed")); - - Some(DatabaseIterator { - iter: interleave_ordered(Vec::new(), iter), - _marker: PhantomData, - }) - }, - None => None, - } - } - - /// Close the database - fn close(&self) { - *self.db.write() = None; - self.overlay.write().clear(); - self.flushing.write().clear(); - } - - /// Restore the database from a copy at given path. - pub fn restore(&self, new_db: &str) -> Result<()> { - self.close(); - - let mut backup_db = PathBuf::from(&self.path); - backup_db.pop(); - backup_db.push("backup_db"); - - let existed = match fs::rename(&self.path, &backup_db) { - Ok(_) => true, - Err(e) => if let io::ErrorKind::NotFound = e.kind() { - false - } else { - return Err(e.into()); - } - }; - - match fs::rename(&new_db, &self.path) { - Ok(_) => { - // clean up the backup. - if existed { - fs::remove_dir_all(&backup_db)?; - } - } - Err(e) => { - // restore the backup. - if existed { - fs::rename(&backup_db, &self.path)?; - } - return Err(e.into()) - } - } - - // reopen the database and steal handles into self - let db = Self::open(&self.config, &self.path)?; - *self.db.write() = mem::replace(&mut *db.db.write(), None); - *self.overlay.write() = mem::replace(&mut *db.overlay.write(), Vec::new()); - *self.flushing.write() = mem::replace(&mut *db.flushing.write(), Vec::new()); - Ok(()) - } - - /// The number of non-default column families. - pub fn num_columns(&self) -> u32 { - self.db.read().as_ref() - .and_then(|db| if db.cfs.is_empty() { None } else { Some(db.cfs.len()) } ) - .map(|n| n as u32) - .unwrap_or(0) - } - - /// Drop a column family. - pub fn drop_column(&self) -> Result<()> { - match *self.db.write() { - Some(DBAndColumns { ref mut db, ref mut cfs }) => { - if let Some(col) = cfs.pop() { - let name = format!("col{}", cfs.len()); - drop(col); - db.drop_cf(&name)?; - } - Ok(()) - }, - None => Ok(()), - } - } - - /// Add a column family. - pub fn add_column(&self) -> Result<()> { - match *self.db.write() { - Some(DBAndColumns { ref mut db, ref mut cfs }) => { - let col = cfs.len() as u32; - let name = format!("col{}", col); - cfs.push(db.create_cf(&name, &col_config(&self.config, &self.block_opts)?)?); - Ok(()) - }, - None => Ok(()), - } - } -} - -// duplicate declaration of methods here to avoid trait import in certain existing cases -// at time of addition. -impl KeyValueDB for Database { - fn get(&self, col: Option, key: &[u8]) -> Result> { - Database::get(self, col, key) - } - - fn get_by_prefix(&self, col: Option, prefix: &[u8]) -> Option> { - Database::get_by_prefix(self, col, prefix) - } - - fn write_buffered(&self, transaction: DBTransaction) { - Database::write_buffered(self, transaction) - } - - fn write(&self, transaction: DBTransaction) -> Result<()> { - Database::write(self, transaction) - } - - fn flush(&self) -> Result<()> { - Database::flush(self) - } - - fn iter<'a>(&'a self, col: Option) -> Box, Box<[u8]>)> + 'a> { - let unboxed = Database::iter(self, col); - Box::new(unboxed.into_iter().flat_map(|inner| inner)) - } - - fn iter_from_prefix<'a>(&'a self, col: Option, prefix: &'a [u8]) - -> Box, Box<[u8]>)> + 'a> - { - let unboxed = Database::iter_from_prefix(self, col, prefix); - Box::new(unboxed.into_iter().flat_map(|inner| inner)) - } - - fn restore(&self, new_db: &str) -> Result<()> { - Database::restore(self, new_db) - } -} - -impl Drop for Database { - fn drop(&mut self) { - // write all buffered changes if we can. - let _ = self.flush(); - } -} - -#[cfg(test)] -mod tests { - extern crate tempdir; - - use std::str::FromStr; - use self::tempdir::TempDir; - use ethereum_types::H256; - use super::*; - - fn test_db(config: &DatabaseConfig) { - let tempdir = TempDir::new("").unwrap(); - let db = Database::open(config, tempdir.path().to_str().unwrap()).unwrap(); - let key1 = H256::from_str("02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc").unwrap(); - let key2 = H256::from_str("03c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc").unwrap(); - let key3 = H256::from_str("01c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc").unwrap(); - - let mut batch = db.transaction(); - batch.put(None, &key1, b"cat"); - batch.put(None, &key2, b"dog"); - db.write(batch).unwrap(); - - assert_eq!(&*db.get(None, &key1).unwrap().unwrap(), b"cat"); - - let contents: Vec<_> = db.iter(None).into_iter().flat_map(|inner| inner).collect(); - assert_eq!(contents.len(), 2); - assert_eq!(&*contents[0].0, &*key1); - assert_eq!(&*contents[0].1, b"cat"); - assert_eq!(&*contents[1].0, &*key2); - assert_eq!(&*contents[1].1, b"dog"); - - let mut batch = db.transaction(); - batch.delete(None, &key1); - db.write(batch).unwrap(); - - assert!(db.get(None, &key1).unwrap().is_none()); - - let mut batch = db.transaction(); - batch.put(None, &key1, b"cat"); - db.write(batch).unwrap(); - - let mut transaction = db.transaction(); - transaction.put(None, &key3, b"elephant"); - transaction.delete(None, &key1); - db.write(transaction).unwrap(); - assert!(db.get(None, &key1).unwrap().is_none()); - assert_eq!(&*db.get(None, &key3).unwrap().unwrap(), b"elephant"); - - assert_eq!(&*db.get_by_prefix(None, &key3).unwrap(), b"elephant"); - assert_eq!(&*db.get_by_prefix(None, &key2).unwrap(), b"dog"); - - let mut transaction = db.transaction(); - transaction.put(None, &key1, b"horse"); - transaction.delete(None, &key3); - db.write_buffered(transaction); - assert!(db.get(None, &key3).unwrap().is_none()); - assert_eq!(&*db.get(None, &key1).unwrap().unwrap(), b"horse"); - - db.flush().unwrap(); - assert!(db.get(None, &key3).unwrap().is_none()); - assert_eq!(&*db.get(None, &key1).unwrap().unwrap(), b"horse"); - } - - #[test] - fn kvdb() { - let tempdir = TempDir::new("").unwrap(); - let _ = Database::open_default(tempdir.path().to_str().unwrap()).unwrap(); - test_db(&DatabaseConfig::default()); - } - - #[test] - #[cfg(target_os = "linux")] - fn df_to_rotational() { - use std::path::PathBuf; - // Example df output. - let example_df = vec![70, 105, 108, 101, 115, 121, 115, 116, 101, 109, 32, 32, 32, 32, 32, 49, 75, 45, 98, 108, 111, 99, 107, 115, 32, 32, 32, 32, 32, 85, 115, 101, 100, 32, 65, 118, 97, 105, 108, 97, 98, 108, 101, 32, 85, 115, 101, 37, 32, 77, 111, 117, 110, 116, 101, 100, 32, 111, 110, 10, 47, 100, 101, 118, 47, 115, 100, 97, 49, 32, 32, 32, 32, 32, 32, 32, 54, 49, 52, 48, 57, 51, 48, 48, 32, 51, 56, 56, 50, 50, 50, 51, 54, 32, 32, 49, 57, 52, 52, 52, 54, 49, 54, 32, 32, 54, 55, 37, 32, 47, 10]; - let expected_output = Some(PathBuf::from("/sys/block/sda/queue/rotational")); - assert_eq!(rotational_from_df_output(example_df), expected_output); - } - - #[test] - fn add_columns() { - let config = DatabaseConfig::default(); - let config_5 = DatabaseConfig::with_columns(Some(5)); - - let tempdir = TempDir::new("").unwrap(); - - // open empty, add 5. - { - let db = Database::open(&config, tempdir.path().to_str().unwrap()).unwrap(); - assert_eq!(db.num_columns(), 0); - - for i in 0..5 { - db.add_column().unwrap(); - assert_eq!(db.num_columns(), i + 1); - } - } - - // reopen as 5. - { - let db = Database::open(&config_5, tempdir.path().to_str().unwrap()).unwrap(); - assert_eq!(db.num_columns(), 5); - } - } - - #[test] - fn drop_columns() { - let config = DatabaseConfig::default(); - let config_5 = DatabaseConfig::with_columns(Some(5)); - - let tempdir = TempDir::new("").unwrap(); - - // open 5, remove all. - { - let db = Database::open(&config_5, tempdir.path().to_str().unwrap()).unwrap(); - assert_eq!(db.num_columns(), 5); - - for i in (0..5).rev() { - db.drop_column().unwrap(); - assert_eq!(db.num_columns(), i); - } - } - - // reopen as 0. - { - let db = Database::open(&config, tempdir.path().to_str().unwrap()).unwrap(); - assert_eq!(db.num_columns(), 0); - } - } - - #[test] - fn write_clears_buffered_ops() { - let tempdir = TempDir::new("").unwrap(); - let config = DatabaseConfig::default(); - let db = Database::open(&config, tempdir.path().to_str().unwrap()).unwrap(); - - let mut batch = db.transaction(); - batch.put(None, b"foo", b"bar"); - db.write_buffered(batch); - - let mut batch = db.transaction(); - batch.put(None, b"foo", b"baz"); - db.write(batch).unwrap(); - - assert_eq!(db.get(None, b"foo").unwrap().unwrap().as_ref(), b"baz"); - } -} diff --git a/util/kvdb/Cargo.toml b/util/kvdb/Cargo.toml deleted file mode 100644 index 820f6e35fb4037f557512e5e23d6bf1a801a4a85..0000000000000000000000000000000000000000 --- a/util/kvdb/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "kvdb" -version = "0.1.0" -authors = ["Parity Technologies "] - -[dependencies] -elastic-array = "0.10" -error-chain = { version = "0.11", default-features = false } -ethcore-bytes = { path = "../bytes" } diff --git a/util/kvdb/src/lib.rs b/util/kvdb/src/lib.rs deleted file mode 100644 index 9ed1038bffdebdef78a06180f30599f687a93125..0000000000000000000000000000000000000000 --- a/util/kvdb/src/lib.rs +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Key-Value store abstraction with `RocksDB` backend. - -#[macro_use] -extern crate error_chain; -extern crate elastic_array; -extern crate ethcore_bytes as bytes; - -use std::io; -use std::path::Path; -use std::sync::Arc; -use elastic_array::{ElasticArray128, ElasticArray32}; -use bytes::Bytes; - -/// Required length of prefixes. -pub const PREFIX_LEN: usize = 12; - -/// Database value. -pub type DBValue = ElasticArray128; - -error_chain! { - types { - Error, ErrorKind, ResultExt, Result; - } - - foreign_links { - Io(io::Error); - } -} - -/// Write transaction. Batches a sequence of put/delete operations for efficiency. -#[derive(Default, Clone, PartialEq)] -pub struct DBTransaction { - /// Database operations. - pub ops: Vec, -} - -/// Database operation. -#[derive(Clone, PartialEq)] -pub enum DBOp { - Insert { - col: Option, - key: ElasticArray32, - value: DBValue, - }, - Delete { - col: Option, - key: ElasticArray32, - } -} - -impl DBOp { - /// Returns the key associated with this operation. - pub fn key(&self) -> &[u8] { - match *self { - DBOp::Insert { ref key, .. } => key, - DBOp::Delete { ref key, .. } => key, - } - } - - /// Returns the column associated with this operation. - pub fn col(&self) -> Option { - match *self { - DBOp::Insert { col, .. } => col, - DBOp::Delete { col, .. } => col, - } - } -} - -impl DBTransaction { - /// Create new transaction. - pub fn new() -> DBTransaction { - DBTransaction::with_capacity(256) - } - - /// Create new transaction with capacity. - pub fn with_capacity(cap: usize) -> DBTransaction { - DBTransaction { - ops: Vec::with_capacity(cap) - } - } - - /// Insert a key-value pair in the transaction. Any existing value will be overwritten upon write. - pub fn put(&mut self, col: Option, key: &[u8], value: &[u8]) { - let mut ekey = ElasticArray32::new(); - ekey.append_slice(key); - self.ops.push(DBOp::Insert { - col: col, - key: ekey, - value: DBValue::from_slice(value), - }); - } - - /// Insert a key-value pair in the transaction. Any existing value will be overwritten upon write. - pub fn put_vec(&mut self, col: Option, key: &[u8], value: Bytes) { - let mut ekey = ElasticArray32::new(); - ekey.append_slice(key); - self.ops.push(DBOp::Insert { - col: col, - key: ekey, - value: DBValue::from_vec(value), - }); - } - - /// Delete value by key. - pub fn delete(&mut self, col: Option, key: &[u8]) { - let mut ekey = ElasticArray32::new(); - ekey.append_slice(key); - self.ops.push(DBOp::Delete { - col: col, - key: ekey, - }); - } -} - -/// Generic key-value database. -/// -/// This makes a distinction between "buffered" and "flushed" values. Values which have been -/// written can always be read, but may be present in an in-memory buffer. Values which have -/// been flushed have been moved to backing storage, like a RocksDB instance. There are certain -/// operations which are only guaranteed to operate on flushed data and not buffered, -/// although implementations may differ in this regard. -/// -/// The contents of an interior buffer may be explicitly flushed using the `flush` method. -/// -/// The `KeyValueDB` also deals in "column families", which can be thought of as distinct -/// stores within a database. Keys written in one column family will not be accessible from -/// any other. The number of column families must be specified at initialization, with a -/// differing interface for each database. The `None` argument in place of a column index -/// is always supported. -/// -/// The API laid out here, along with the `Sync` bound implies interior synchronization for -/// implementation. -pub trait KeyValueDB: Sync + Send { - /// Helper to create a new transaction. - fn transaction(&self) -> DBTransaction { DBTransaction::new() } - - /// Get a value by key. - fn get(&self, col: Option, key: &[u8]) -> Result>; - - /// Get a value by partial key. Only works for flushed data. - fn get_by_prefix(&self, col: Option, prefix: &[u8]) -> Option>; - - /// Write a transaction of changes to the buffer. - fn write_buffered(&self, transaction: DBTransaction); - - /// Write a transaction of changes to the backing store. - fn write(&self, transaction: DBTransaction) -> Result<()> { - self.write_buffered(transaction); - self.flush() - } - - /// Flush all buffered data. - fn flush(&self) -> Result<()>; - - /// Iterate over flushed data for a given column. - fn iter<'a>(&'a self, col: Option) -> Box, Box<[u8]>)> + 'a>; - - /// Iterate over flushed data for a given column, starting from a given prefix. - fn iter_from_prefix<'a>(&'a self, col: Option, prefix: &'a [u8]) - -> Box, Box<[u8]>)> + 'a>; - - /// Attempt to replace this database with a new one located at the given path. - fn restore(&self, new_db: &str) -> Result<()>; -} - -/// Generic key-value database handler. This trait contains one function `open`. When called, it opens database with a -/// predefined config. -pub trait KeyValueDBHandler: Send + Sync { - /// Open the predefined key-value database. - fn open(&self, path: &Path) -> Result>; -} diff --git a/util/macros/src/lib.rs b/util/macros/src/lib.rs index 78bcd0397efb33b959c94808568b7171e2af3777..cc5f92ba1506e91f99b6896cb17da4170666cf88 100644 --- a/util/macros/src/lib.rs +++ b/util/macros/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/mem/src/lib.rs b/util/mem/src/lib.rs index a8b9e53f66cca98ebe00b0779ba582455dceb809..735a58cd23286f6f30a20293c4794f7af4907554 100644 --- a/util/mem/src/lib.rs +++ b/util/mem/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -31,11 +31,9 @@ impl> From for Memzero { impl> Drop for Memzero { fn drop(&mut self) { - let n = self.mem.as_mut().len(); - let p = self.mem.as_mut().as_mut_ptr(); - for i in 0..n { - unsafe { - ptr::write_volatile(p.offset(i as isize), 0) + unsafe { + for byte_ref in self.mem.as_mut() { + ptr::write_volatile(byte_ref, 0) } } } @@ -54,4 +52,3 @@ impl> DerefMut for Memzero { &mut self.mem } } - diff --git a/util/memory_cache/src/lib.rs b/util/memory_cache/src/lib.rs index af70b0cff30eb59abdb5dccca97caf21a7960ea8..ff996142b925a30aa56a9a1587e18e2a7daf1306 100644 --- a/util/memory_cache/src/lib.rs +++ b/util/memory_cache/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/memorydb/Cargo.toml b/util/memorydb/Cargo.toml deleted file mode 100644 index 41c41bb628eb7acfa6e97adcd6c5c5cbbcdca5cf..0000000000000000000000000000000000000000 --- a/util/memorydb/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "memorydb" -version = "0.1.1" -authors = ["Parity Technologies "] -description = "in-memory implementation of hashdb" -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" } -plain_hasher = { path = "../plain_hasher" } -rlp = { version = "0.2.1", path = "../rlp" } diff --git a/util/memorydb/src/lib.rs b/util/memorydb/src/lib.rs deleted file mode 100644 index 12eb62e0574aec38f0f09b06e7bec5b20f28d599..0000000000000000000000000000000000000000 --- a/util/memorydb/src/lib.rs +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Reference-counted memory-based `HashDB` implementation. -extern crate heapsize; -extern crate ethereum_types; -extern crate hashdb; -extern crate keccak_hash as keccak; -extern crate plain_hasher; -extern crate rlp; -extern crate elastic_array; - -use std::mem; -use std::collections::HashMap; -use std::collections::hash_map::Entry; -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; -/// Reference-counted memory-based `HashDB` implementation. -/// -/// Use `new()` to create a new database. Insert items with `insert()`, remove items -/// with `remove()`, check for existence with `contains()` and lookup a hash to derive -/// the data with `get()`. Clear with `clear()` and purge the portions of the data -/// that have no references with `purge()`. -/// -/// # Example -/// ```rust -/// extern crate hashdb; -/// extern crate memorydb; -/// use hashdb::*; -/// use memorydb::*; -/// fn main() { -/// let mut m = MemoryDB::new(); -/// let d = "Hello world!".as_bytes(); -/// -/// let k = m.insert(d); -/// assert!(m.contains(&k)); -/// assert_eq!(m.get(&k).unwrap(), d); -/// -/// m.insert(d); -/// assert!(m.contains(&k)); -/// -/// m.remove(&k); -/// assert!(m.contains(&k)); -/// -/// m.remove(&k); -/// assert!(!m.contains(&k)); -/// -/// m.remove(&k); -/// assert!(!m.contains(&k)); -/// -/// m.insert(d); -/// assert!(!m.contains(&k)); - -/// m.insert(d); -/// assert!(m.contains(&k)); -/// assert_eq!(m.get(&k).unwrap(), d); -/// -/// m.remove(&k); -/// assert!(!m.contains(&k)); -/// } -/// ``` -#[derive(Default, Clone, PartialEq)] -pub struct MemoryDB { - data: H256FastMap<(DBValue, i32)>, -} - -impl MemoryDB { - /// Create a new instance of the memory DB. - pub fn new() -> MemoryDB { - MemoryDB { - data: H256FastMap::default(), - } - } - - /// Clear all data from the database. - /// - /// # Examples - /// ```rust - /// extern crate hashdb; - /// extern crate memorydb; - /// use hashdb::*; - /// use memorydb::*; - /// fn main() { - /// let mut m = MemoryDB::new(); - /// let hello_bytes = "Hello world!".as_bytes(); - /// let hash = m.insert(hello_bytes); - /// assert!(m.contains(&hash)); - /// m.clear(); - /// assert!(!m.contains(&hash)); - /// } - /// ``` - pub fn clear(&mut self) { - self.data.clear(); - } - - /// Purge all zero-referenced data from the database. - pub fn purge(&mut self) { - self.data.retain(|_, &mut (_, rc)| rc != 0); - } - - /// 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()) - } - - /// Grab the raw information associated with a key. Returns None if the key - /// doesn't exist. - /// - /// 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 { - return Some((DBValue::from_slice(&NULL_RLP), 1)); - } - self.data.get(key).cloned() - } - - /// Returns the size of allocated heap memory - pub fn mem_used(&self) -> usize { - self.data.heap_size_of_children() - } - - /// 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 { - return None; - } - match self.data.entry(key.clone()) { - Entry::Occupied(mut entry) => - if entry.get().1 == 1 { - Some(entry.remove().0) - } else { - entry.get_mut().1 -= 1; - None - }, - Entry::Vacant(entry) => { - entry.insert((DBValue::new(), -1)); - None - } - } - } - - /// Consolidate all the entries of `other` into `self`. - pub fn consolidate(&mut self, mut other: Self) { - for (key, (value, rc)) in other.drain() { - match self.data.entry(key) { - Entry::Occupied(mut entry) => { - if entry.get().1 < 0 { - entry.get_mut().0 = value; - } - - entry.get_mut().1 += rc; - } - Entry::Vacant(entry) => { - entry.insert((value, rc)); - } - } - } - } -} - -impl HashDB for MemoryDB { - fn get(&self, key: &H256) -> Option { - if key == &KECCAK_NULL_RLP { - return Some(DBValue::from_slice(&NULL_RLP)); - } - - match self.data.get(key) { - Some(&(ref d, rc)) if rc > 0 => Some(d.clone()), - _ => None - } - } - - fn keys(&self) -> HashMap { - self.data.iter() - .filter_map(|(k, v)| if v.1 != 0 { - Some((*k, v.1)) - } else { - None - }) - .collect() - } - - fn contains(&self, key: &H256) -> bool { - if key == &KECCAK_NULL_RLP { - return true; - } - - match self.data.get(key) { - Some(&(_, x)) if x > 0 => true, - _ => false - } - } - - fn insert(&mut self, value: &[u8]) -> H256 { - if value == &NULL_RLP { - return KECCAK_NULL_RLP.clone(); - } - let key = keccak(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 { - *old_value = DBValue::from_slice(value); - } - *rc += 1; - }, - Entry::Vacant(entry) => { - entry.insert((DBValue::from_slice(value), 1)); - }, - } - key - } - - fn emplace(&mut self, key: H256, value: DBValue) { - if &*value == &NULL_RLP { - return; - } - - 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 { - *old_value = value; - } - *rc += 1; - }, - Entry::Vacant(entry) => { - entry.insert((value, 1)); - }, - } - } - - fn remove(&mut self, key: &H256) { - if key == &KECCAK_NULL_RLP { - return; - } - - match self.data.entry(*key) { - Entry::Occupied(mut entry) => { - let &mut (_, ref mut rc) = entry.get_mut(); - *rc -= 1; - }, - Entry::Vacant(entry) => { - entry.insert((DBValue::new(), -1)); - }, - } - } -} - -#[cfg(test)] -mod tests { - use keccak::keccak; - use super::*; - - #[test] - fn memorydb_remove_and_purge() { - let hello_bytes = b"Hello world!"; - let hello_key = keccak(hello_bytes); - - let mut m = MemoryDB::new(); - m.remove(&hello_key); - assert_eq!(m.raw(&hello_key).unwrap().1, -1); - m.purge(); - assert_eq!(m.raw(&hello_key).unwrap().1, -1); - m.insert(hello_bytes); - assert_eq!(m.raw(&hello_key).unwrap().1, 0); - m.purge(); - assert_eq!(m.raw(&hello_key), None); - - 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); - m.insert(hello_bytes); - assert_eq!(m.raw(&hello_key).unwrap().1, 1); - assert_eq!(&*m.remove_and_purge(&hello_key).unwrap(), hello_bytes); - assert_eq!(m.raw(&hello_key), None); - assert!(m.remove_and_purge(&hello_key).is_none()); - } - - #[test] - fn consolidate() { - let mut main = MemoryDB::new(); - let mut other = MemoryDB::new(); - let remove_key = other.insert(b"doggo"); - main.remove(&remove_key); - - let insert_key = other.insert(b"arf"); - main.emplace(insert_key, DBValue::from_slice(b"arf")); - - let negative_remove_key = other.insert(b"negative"); - other.remove(&negative_remove_key); // ref cnt: 0 - other.remove(&negative_remove_key); // ref cnt: -1 - main.remove(&negative_remove_key); // ref cnt: -1 - - main.consolidate(other); - - let overlay = main.drain(); - - assert_eq!(overlay.get(&remove_key).unwrap(), &(DBValue::from_slice(b"doggo"), 0)); - assert_eq!(overlay.get(&insert_key).unwrap(), &(DBValue::from_slice(b"arf"), 2)); - assert_eq!(overlay.get(&negative_remove_key).unwrap(), &(DBValue::from_slice(b"negative"), -2)); - } -} diff --git a/util/migration-rocksdb/Cargo.toml b/util/migration-rocksdb/Cargo.toml index 3f0b8e75204aae7494c6fd871e6f7f03746178bc..39ff50cfbb7e3e5751d1d18972bd88415f03f9ca 100644 --- a/util/migration-rocksdb/Cargo.toml +++ b/util/migration-rocksdb/Cargo.toml @@ -6,9 +6,8 @@ authors = ["Parity Technologies "] [dependencies] log = "0.3" macros = { path = "../macros" } -kvdb = { path = "../kvdb" } -kvdb-rocksdb = { path = "../kvdb-rocksdb" } -error-chain = { version = "0.11", default-features = false } +kvdb = { git = "https://github.com/paritytech/parity-common" } +kvdb-rocksdb = { git = "https://github.com/paritytech/parity-common" } [dev-dependencies] tempdir = "0.3" diff --git a/util/migration-rocksdb/src/lib.rs b/util/migration-rocksdb/src/lib.rs index fbc9681b40e7249a2a5e6b25add3d556e012edf5..60b66ccf062a20cb72ebe5e7364d558e8caecdd2 100644 --- a/util/migration-rocksdb/src/lib.rs +++ b/util/migration-rocksdb/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -20,8 +20,6 @@ extern crate log; #[macro_use] extern crate macros; -#[macro_use] -extern crate error_chain; extern crate kvdb; extern crate kvdb_rocksdb; @@ -29,31 +27,13 @@ extern crate kvdb_rocksdb; use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use std::sync::Arc; -use std::{fs, io}; +use std::{fs, io, error}; use kvdb::DBTransaction; use kvdb_rocksdb::{CompactionProfile, Database, DatabaseConfig}; -error_chain! { - links { - Db(kvdb::Error, kvdb::ErrorKind); - } - - foreign_links { - Io(io::Error); - } - - errors { - CannotAddMigration { - description("Cannot add migration"), - display("Cannot add migration"), - } - - MigrationImpossible { - description("Migration impossible"), - display("Migration impossible"), - } - } +fn other_io_err(e: E) -> io::Error where E: Into> { + io::Error::new(io::ErrorKind::Other, e) } /// Migration config. @@ -92,7 +72,7 @@ impl Batch { } /// Insert a value into the batch, committing if necessary. - pub fn insert(&mut self, key: Vec, value: Vec, dest: &mut Database) -> Result<()> { + pub fn insert(&mut self, key: Vec, value: Vec, dest: &mut Database) -> io::Result<()> { self.inner.insert(key, value); if self.inner.len() == self.batch_size { self.commit(dest)?; @@ -101,7 +81,7 @@ impl Batch { } /// Commit all the items in the batch to the given database. - pub fn commit(&mut self, dest: &mut Database) -> Result<()> { + pub fn commit(&mut self, dest: &mut Database) -> io::Result<()> { if self.inner.is_empty() { return Ok(()) } let mut transaction = DBTransaction::new(); @@ -111,7 +91,7 @@ impl Batch { } self.inner.clear(); - dest.write(transaction).map_err(Into::into) + dest.write(transaction) } } @@ -127,7 +107,7 @@ pub trait Migration: 'static { /// Version of the database after the migration. fn version(&self) -> u32; /// Migrate a source to a destination. - fn migrate(&mut self, source: Arc, config: &Config, destination: &mut Database, col: Option) -> Result<()>; + fn migrate(&mut self, source: Arc, config: &Config, destination: &mut Database, col: Option) -> io::Result<()>; } /// A simple migration over key-value pairs of a single column. @@ -150,7 +130,7 @@ impl Migration for T { fn alters_existing(&self) -> bool { true } - fn migrate(&mut self, source: Arc, config: &Config, dest: &mut Database, col: Option) -> Result<()> { + fn migrate(&mut self, source: Arc, config: &Config, dest: &mut Database, col: Option) -> io::Result<()> { let migration_needed = col == SimpleMigration::migrated_column_index(self); let mut batch = Batch::new(config, col); @@ -188,7 +168,7 @@ impl Migration for ChangeColumns { fn columns(&self) -> Option { self.post_columns } fn version(&self) -> u32 { self.version } fn alters_existing(&self) -> bool { false } - fn migrate(&mut self, _: Arc, _: &Config, _: &mut Database, _: Option) -> Result<()> { + fn migrate(&mut self, _: Arc, _: &Config, _: &mut Database, _: Option) -> io::Result<()> { Ok(()) } } @@ -242,7 +222,7 @@ impl Manager { } /// Adds new migration rules. - pub fn add_migration(&mut self, migration: T) -> Result<()> where T: Migration { + pub fn add_migration(&mut self, migration: T) -> io::Result<()> where T: Migration { let is_new = match self.migrations.last() { Some(last) => migration.version() > last.version(), None => true, @@ -250,18 +230,18 @@ impl Manager { match is_new { true => Ok(self.migrations.push(Box::new(migration))), - false => Err(ErrorKind::CannotAddMigration.into()), + false => Err(other_io_err("Cannot add migration.")), } } /// Performs migration in order, starting with a source path, migrating between two temporary databases, /// and producing a path where the final migration lives. - pub fn execute(&mut self, old_path: &Path, version: u32) -> Result { + pub fn execute(&mut self, old_path: &Path, version: u32) -> io::Result { let config = self.config.clone(); let migrations = self.migrations_from(version); trace!(target: "migration", "Total migrations to execute for version {}: {}", version, migrations.len()); if migrations.is_empty() { - return Err(ErrorKind::MigrationImpossible.into()) + return Err(other_io_err("Migration impossible")); }; let columns = migrations.get(0).and_then(|m| m.pre_columns()); @@ -272,7 +252,6 @@ impl Manager { memory_budget: None, compaction: config.compaction_profile, columns: columns, - wal: true, }; let db_root = database_path(old_path); @@ -280,7 +259,7 @@ impl Manager { let mut temp_path = old_path.to_path_buf(); // start with the old db. - let old_path_str = old_path.to_str().ok_or(ErrorKind::MigrationImpossible)?; + let old_path_str = old_path.to_str().ok_or_else(|| other_io_err("Migration impossible."))?; let mut cur_db = Arc::new(Database::open(&db_config, old_path_str)?); for migration in migrations { @@ -294,7 +273,7 @@ impl Manager { temp_path = temp_idx.path(&db_root); // open the target temporary database. - let temp_path_str = temp_path.to_str().ok_or(ErrorKind::MigrationImpossible)?; + let temp_path_str = temp_path.to_str().ok_or_else(|| other_io_err("Migration impossible."))?; let mut new_db = Database::open(&db_config, temp_path_str)?; match current_columns { @@ -318,11 +297,11 @@ impl Manager { // we can do this in-place. let goal_columns = migration.columns().unwrap_or(0); while cur_db.num_columns() < goal_columns { - cur_db.add_column().map_err(kvdb::Error::from)?; + cur_db.add_column().map_err(other_io_err)?; } while cur_db.num_columns() > goal_columns { - cur_db.drop_column().map_err(kvdb::Error::from)?; + cur_db.drop_column().map_err(other_io_err)?; } } } diff --git a/util/migration-rocksdb/tests/tests.rs b/util/migration-rocksdb/tests/tests.rs index 85c48f12b67096bfde818498c71f5ae539615c53..0e22e6a6568f773c417901b1381c6bcd55acfd83 100644 --- a/util/migration-rocksdb/tests/tests.rs +++ b/util/migration-rocksdb/tests/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -25,11 +25,12 @@ extern crate kvdb_rocksdb; extern crate migration_rocksdb as migration; use std::collections::BTreeMap; +use std::io; use std::path::{Path, PathBuf}; use std::sync::Arc; use tempdir::TempDir; use kvdb_rocksdb::Database; -use migration::{Batch, Config, Error, SimpleMigration, Migration, Manager, ChangeColumns}; +use migration::{Batch, Config, SimpleMigration, Migration, Manager, ChangeColumns}; #[inline] fn db_path(path: &Path) -> PathBuf { @@ -112,14 +113,13 @@ impl Migration for AddsColumn { fn version(&self) -> u32 { 1 } - fn migrate(&mut self, source: Arc, config: &Config, dest: &mut Database, col: Option) -> Result<(), Error> { + fn migrate(&mut self, source: Arc, config: &Config, dest: &mut Database, col: Option) -> io::Result<()> { let mut batch = Batch::new(config, col); for (key, value) in source.iter(col).into_iter().flat_map(|inner| inner) { batch.insert(key.into_vec(), value.into_vec(), dest)?; } - if col == Some(1) { batch.insert(vec![1, 2, 3], vec![4, 5, 6], dest)?; } diff --git a/util/network-devp2p/Cargo.toml b/util/network-devp2p/Cargo.toml index 4a5d2d942ec8c6c133bea1e9cbc8f05886839942..99fdc16459196209db69a5a17c8691f8263d2a73 100644 --- a/util/network-devp2p/Cargo.toml +++ b/util/network-devp2p/Cargo.toml @@ -16,25 +16,25 @@ 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"] } -ethcore-bytes = { path = "../bytes" } -ethcore-crypto = { path = "../../ethcore/crypto" } +parity-bytes = { git = "https://github.com/paritytech/parity-common" } +parity-crypto = { git = "https://github.com/paritytech/parity-common" } ethcore-logger = { path ="../../logger" } ethcore-network = { path = "../network" } ethereum-types = "0.3" ethkey = { path = "../../ethkey" } -rlp = { path = "../rlp" } -path = { path = "../path" } +rlp = { git = "https://github.com/paritytech/parity-common" } +path = { git = "https://github.com/paritytech/parity-common" } ipnetwork = "0.12.6" -keccak-hash = { path = "../hash" } +keccak-hash = { git = "https://github.com/paritytech/parity-common" } snappy = { git = "https://github.com/paritytech/rust-snappy" } serde = "1.0" serde_json = "1.0" serde_derive = "1.0" -error-chain = { version = "0.11", default-features = false } +error-chain = { version = "0.12", default-features = false } [dev-dependencies] tempdir = "0.3" diff --git a/util/network-devp2p/src/connection.rs b/util/network-devp2p/src/connection.rs index 5dbf71fa01c2a585714f268b3e30599d3c46adc8..1ed395acba899ff200c988055b6d0de754e9e34a 100644 --- a/util/network-devp2p/src/connection.rs +++ b/util/network-devp2p/src/connection.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -23,7 +23,7 @@ use mio::{Token, Ready, PollOpt}; use mio::deprecated::{Handler, EventLoop, TryRead, TryWrite}; use mio::tcp::*; use ethereum_types::{H128, H256, H512}; -use ethcore_bytes::*; +use parity_bytes::*; use rlp::{Rlp, RlpStream}; use std::io::{self, Cursor, Read, Write}; use io::{IoContext, StreamToken}; @@ -502,7 +502,7 @@ mod tests { use std::sync::atomic::AtomicBool; use mio::{Ready}; - use ethcore_bytes::Bytes; + use parity_bytes::Bytes; use io::*; use super::*; diff --git a/util/network-devp2p/src/discovery.rs b/util/network-devp2p/src/discovery.rs index af43546a5f35d05cd5b380fd7e73d193ef64eb81..bc808c39827f83dec41448bc257fd7e62239cc2e 100644 --- a/util/network-devp2p/src/discovery.rs +++ b/util/network-devp2p/src/discovery.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,21 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethcore_bytes::Bytes; +use parity_bytes::Bytes; use std::net::SocketAddr; use std::collections::{HashSet, HashMap, VecDeque}; -use std::mem; +use std::collections::hash_map::Entry; use std::default::Default; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; -use mio::*; -use mio::deprecated::{Handler, EventLoop}; -use mio::udp::*; use hash::keccak; use ethereum_types::{H256, H520}; -use rlp::{Rlp, RlpStream, encode_list}; +use rlp::{Rlp, RlpStream}; use node_table::*; use network::{Error, ErrorKind}; -use io::{StreamToken, IoContext}; use ethkey::{Secret, KeyPair, sign, recover}; use network::IpFilter; @@ -39,7 +35,7 @@ const ADDRESS_BITS: usize = 8 * ADDRESS_BYTES_SIZE; // Denoted by n in [Kademl const DISCOVERY_MAX_STEPS: u16 = 8; // Max iterations of discovery. (discover) const BUCKET_SIZE: usize = 16; // Denoted by k in [Kademlia]. Number of nodes stored in each bucket. const ALPHA: usize = 3; // Denoted by \alpha in [Kademlia]. Number of concurrent FindNode requests. -const MAX_DATAGRAM_SIZE: usize = 1280; +pub const MAX_DATAGRAM_SIZE: usize = 1280; const PACKET_PING: u8 = 1; const PACKET_PONG: u8 = 2; @@ -47,7 +43,15 @@ const PACKET_FIND_NODE: u8 = 3; const PACKET_NEIGHBOURS: u8 = 4; const PING_TIMEOUT: Duration = Duration::from_millis(300); +const FIND_NODE_TIMEOUT: Duration = Duration::from_secs(2); +const EXPIRY_TIME: Duration = Duration::from_secs(60); const MAX_NODES_PING: usize = 32; // Max nodes to add/ping at once +const REQUEST_BACKOFF: [Duration; 4] = [ + Duration::from_secs(1), + Duration::from_secs(4), + Duration::from_secs(16), + Duration::from_secs(64) +]; #[derive(Clone, Debug)] pub struct NodeEntry { @@ -58,13 +62,35 @@ pub struct NodeEntry { pub struct BucketEntry { pub address: NodeEntry, pub id_hash: H256, - pub timeout: Option, + pub last_seen: Instant, + backoff_until: Instant, + fail_count: usize, +} + +impl BucketEntry { + fn new(address: NodeEntry) -> Self { + let now = Instant::now(); + BucketEntry { + id_hash: keccak(address.id), + address: address, + last_seen: now, + backoff_until: now, + fail_count: 0, + } + } } pub struct NodeBucket { nodes: VecDeque, //sorted by last active } +struct PendingRequest { + packet_id: u8, + sent_at: Instant, + packet_hash: H256, + response_count: usize, // Some requests (eg. FIND_NODE) have multi-packet responses +} + impl Default for NodeBucket { fn default() -> Self { NodeBucket::new() @@ -79,26 +105,28 @@ impl NodeBucket { } } -struct Datagramm { - payload: Bytes, - address: SocketAddr, +pub struct Datagram { + pub payload: Bytes, + pub address: SocketAddr, } -pub struct Discovery { +pub struct Discovery<'a> { id: NodeId, id_hash: H256, secret: Secret, public_endpoint: NodeEndpoint, - udp_socket: UdpSocket, - token: StreamToken, discovery_round: u16, discovery_id: NodeId, discovery_nodes: HashSet, node_buckets: Vec, - send_queue: VecDeque, + in_flight_requests: HashMap, + expiring_pings: VecDeque<(NodeId, Instant)>, + expiring_finds: VecDeque<(NodeId, Instant)>, + send_queue: VecDeque, check_timestamps: bool, adding_nodes: Vec, ip_filter: IpFilter, + request_backoff: &'a [Duration], } pub struct TableUpdates { @@ -106,100 +134,91 @@ pub struct TableUpdates { pub removed: HashSet, } -impl Discovery { - pub fn new(key: &KeyPair, listen: SocketAddr, public: NodeEndpoint, token: StreamToken, ip_filter: IpFilter) -> Discovery { - let socket = UdpSocket::bind(&listen).expect("Error binding UDP socket"); +impl<'a> Discovery<'a> { + pub fn new(key: &KeyPair, public: NodeEndpoint, ip_filter: IpFilter) -> Discovery<'static> { Discovery { id: key.public().clone(), id_hash: keccak(key.public()), secret: key.secret().clone(), public_endpoint: public, - token: token, discovery_round: 0, discovery_id: NodeId::new(), discovery_nodes: HashSet::new(), node_buckets: (0..ADDRESS_BITS).map(|_| NodeBucket::new()).collect(), - udp_socket: socket, + in_flight_requests: HashMap::new(), + expiring_pings: VecDeque::new(), + expiring_finds: VecDeque::new(), send_queue: VecDeque::new(), check_timestamps: true, adding_nodes: Vec::new(), ip_filter: ip_filter, + request_backoff: &REQUEST_BACKOFF, } } /// Add a new node to discovery table. Pings the node. pub fn add_node(&mut self, e: NodeEntry) { - if self.is_allowed(&e) { - let endpoint = e.endpoint.clone(); - self.update_node(e); - self.ping(&endpoint); + // If distance returns None, then we are trying to add ourself. + let id_hash = keccak(e.id); + if let Some(dist) = Discovery::distance(&self.id_hash, &id_hash) { + if self.node_buckets[dist].nodes.iter().any(|n| n.id_hash == id_hash) { + return; + } + self.try_ping(e); } } /// Add a list of nodes. Pings a few nodes each round pub fn add_node_list(&mut self, nodes: Vec) { - self.adding_nodes = nodes; - self.update_new_nodes(); + for node in nodes { + self.add_node(node); + } } /// Add a list of known nodes to the table. - pub fn init_node_list(&mut self, mut nodes: Vec) { - for n in nodes.drain(..) { + pub fn init_node_list(&mut self, nodes: Vec) { + for n in nodes { if self.is_allowed(&n) { self.update_node(n); } } } - fn update_node(&mut self, e: NodeEntry) { + fn update_node(&mut self, e: NodeEntry) -> Option { trace!(target: "discovery", "Inserting {:?}", &e); let id_hash = keccak(e.id); let dist = match Discovery::distance(&self.id_hash, &id_hash) { Some(dist) => dist, None => { - warn!(target: "discovery", "Attempted to update own entry: {:?}", e); - return; + debug!(target: "discovery", "Attempted to update own entry: {:?}", e); + return None; } }; + let mut added_map = HashMap::new(); let ping = { let bucket = &mut self.node_buckets[dist]; let updated = if let Some(node) = bucket.nodes.iter_mut().find(|n| n.address.id == e.id) { node.address = e.clone(); - node.timeout = None; + node.last_seen = Instant::now(); + node.backoff_until = Instant::now(); + node.fail_count = 0; true } else { false }; if !updated { - bucket.nodes.push_front(BucketEntry { address: e, timeout: None, id_hash: id_hash, }); - } + added_map.insert(e.id, e.clone()); + bucket.nodes.push_front(BucketEntry::new(e)); - if bucket.nodes.len() > BUCKET_SIZE { - //ping least active node - let last = bucket.nodes.back_mut().expect("Last item is always present when len() > 0"); - last.timeout = Some(Instant::now()); - Some(last.address.endpoint.clone()) + if bucket.nodes.len() > BUCKET_SIZE { + select_bucket_ping(bucket.nodes.iter()) + } else { None } } else { None } }; - if let Some(endpoint) = ping { - self.ping(&endpoint); - } - } - - /// Removes the timeout of a given NodeId if it can be found in one of the discovery buckets - fn clear_ping(&mut self, id: &NodeId) { - let dist = match Discovery::distance(&self.id_hash, &keccak(id)) { - Some(dist) => dist, - None => { - warn!(target: "discovery", "Received ping from self"); - return - } - }; - - let bucket = &mut self.node_buckets[dist]; - if let Some(node) = bucket.nodes.iter_mut().find(|n| &n.address.id == id) { - node.timeout = None; + if let Some(node) = ping { + self.try_ping(node); } + Some(TableUpdates { added: added_map, removed: HashSet::new() }) } /// Starts the discovery process at round 0 @@ -211,11 +230,11 @@ impl Discovery { } fn update_new_nodes(&mut self) { - let mut count = 0usize; - while !self.adding_nodes.is_empty() && count < MAX_NODES_PING { - let node = self.adding_nodes.pop().expect("pop is always Some if not empty; qed"); - self.add_node(node); - count += 1; + while self.in_flight_requests.len() < MAX_NODES_PING { + match self.adding_nodes.pop() { + Some(next) => self.try_ping(next), + None => break, + } } } @@ -229,13 +248,17 @@ impl Discovery { { let nearest = self.nearest_node_entries(&self.discovery_id).into_iter(); let nearest = nearest.filter(|x| !self.discovery_nodes.contains(&x.id)).take(ALPHA).collect::>(); + let target = self.discovery_id.clone(); for r in nearest { - let rlp = encode_list(&(&[self.discovery_id.clone()][..])); - self.send_packet(PACKET_FIND_NODE, &r.endpoint.udp_address(), &rlp) - .unwrap_or_else(|e| warn!("Error sending node discovery packet for {:?}: {:?}", &r.endpoint, e)); - self.discovery_nodes.insert(r.id.clone()); - tried_count += 1; - trace!(target: "discovery", "Sent FindNode to {:?}", &r.endpoint); + match self.send_find_node(&r, &target) { + Ok(()) => { + self.discovery_nodes.insert(r.id.clone()); + tried_count += 1; + }, + Err(e) => { + warn!(target: "discovery", "Error sending node discovery packet for {:?}: {:?}", &r.endpoint, e); + }, + }; } } @@ -261,46 +284,71 @@ impl Discovery { None // a and b are equal, so log distance is -inf } - fn ping(&mut self, node: &NodeEndpoint) { - let mut rlp = RlpStream::new_list(3); + fn try_ping(&mut self, node: NodeEntry) { + if !self.is_allowed(&node) || + self.in_flight_requests.contains_key(&node.id) || + self.adding_nodes.iter().any(|n| n.id == node.id) + { + return; + } + + if self.in_flight_requests.len() < MAX_NODES_PING { + self.ping(&node) + .unwrap_or_else(|e| { + warn!(target: "discovery", "Error sending Ping packet: {:?}", e); + }); + } else { + self.adding_nodes.push(node); + } + } + + fn ping(&mut self, node: &NodeEntry) -> Result<(), Error> { + let mut rlp = RlpStream::new_list(4); rlp.append(&PROTOCOL_VERSION); self.public_endpoint.to_rlp_list(&mut rlp); - node.to_rlp_list(&mut rlp); - trace!(target: "discovery", "Sent Ping to {:?}", &node); - self.send_packet(PACKET_PING, &node.udp_address(), &rlp.drain()) - .unwrap_or_else(|e| warn!("Error sending Ping packet: {:?}", e)) - } - - fn send_packet(&mut self, packet_id: u8, address: &SocketAddr, payload: &[u8]) -> Result<(), Error> { - let mut rlp = RlpStream::new(); - rlp.append_raw(&[packet_id], 1); - let source = Rlp::new(payload); - rlp.begin_list(source.item_count()? + 1); - for i in 0 .. source.item_count()? { - rlp.append_raw(source.at(i)?.as_raw(), 1); - } - let timestamp = 60 + SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default().as_secs() as u32; - rlp.append(×tamp); - - let bytes = rlp.drain(); - let hash = keccak(bytes.as_ref()); - let signature = match sign(&self.secret, &hash) { - Ok(s) => s, - Err(e) => { - warn!("Error signing UDP packet"); - return Err(Error::from(e)); - } + node.endpoint.to_rlp_list(&mut rlp); + append_expiration(&mut rlp); + let hash = self.send_packet(PACKET_PING, &node.endpoint.udp_address(), &rlp.drain())?; + + let request_info = PendingRequest { + packet_id: PACKET_PING, + sent_at: Instant::now(), + packet_hash: hash, + response_count: 0, }; - let mut packet = Bytes::with_capacity(bytes.len() + 32 + 65); - packet.extend(hash.iter()); - packet.extend(signature.iter()); - packet.extend(bytes.iter()); - let signed_hash = keccak(&packet[32..]); - packet[0..32].clone_from_slice(&signed_hash); - self.send_to(packet, address.clone()); + self.expiring_pings.push_back((node.id, request_info.sent_at)); + self.in_flight_requests.insert(node.id, request_info); + + trace!(target: "discovery", "Sent Ping to {:?}", &node.endpoint); + Ok(()) + } + + fn send_find_node(&mut self, node: &NodeEntry, target: &NodeId) -> Result<(), Error> { + let mut rlp = RlpStream::new_list(2); + rlp.append(target); + append_expiration(&mut rlp); + let hash = self.send_packet(PACKET_FIND_NODE, &node.endpoint.udp_address(), &rlp.drain())?; + + let request_info = PendingRequest { + packet_id: PACKET_FIND_NODE, + sent_at: Instant::now(), + packet_hash: hash, + response_count: 0, + }; + self.expiring_finds.push_back((node.id, request_info.sent_at)); + self.in_flight_requests.insert(node.id, request_info); + + trace!(target: "discovery", "Sent FindNode to {:?}", &node.endpoint); Ok(()) } + fn send_packet(&mut self, packet_id: u8, address: &SocketAddr, payload: &[u8]) -> Result { + let packet = assemble_packet(packet_id, payload, &self.secret)?; + let hash = H256::from(&packet[0..32]); + self.send_to(packet, address.clone()); + Ok(hash) + } + fn nearest_node_entries(&self, target: &NodeId) -> Vec { let target_hash = keccak(target); let target_distance = self.id_hash ^ target_hash; @@ -352,53 +400,12 @@ impl Discovery { ret } - pub fn writable(&mut self, io: &IoContext) where Message: Send + Sync + Clone { - while let Some(data) = self.send_queue.pop_front() { - match self.udp_socket.send_to(&data.payload, &data.address) { - Ok(Some(size)) if size == data.payload.len() => { - }, - Ok(Some(_)) => { - warn!("UDP sent incomplete datagramm"); - }, - Ok(None) => { - self.send_queue.push_front(data); - return; - } - Err(e) => { - debug!("UDP send error: {:?}, address: {:?}", e, &data.address); - return; - } - } - } - io.update_registration(self.token).unwrap_or_else(|e| debug!("Error updating discovery registration: {:?}", e)); - } - fn send_to(&mut self, payload: Bytes, address: SocketAddr) { - self.send_queue.push_back(Datagramm { payload: payload, address: address }); - } - - pub fn readable(&mut self, io: &IoContext) -> Option where Message: Send + Sync + Clone { - let mut buf: [u8; MAX_DATAGRAM_SIZE] = unsafe { mem::uninitialized() }; - let writable = !self.send_queue.is_empty(); - let res = match self.udp_socket.recv_from(&mut buf) { - Ok(Some((len, address))) => self.on_packet(&buf[0..len], address).unwrap_or_else(|e| { - debug!("Error processing UDP packet: {:?}", e); - None - }), - Ok(_) => None, - Err(e) => { - debug!("Error reading UPD socket: {:?}", e); - None - } - }; - let new_writable = !self.send_queue.is_empty(); - if writable != new_writable { - io.update_registration(self.token).unwrap_or_else(|e| debug!("Error updating discovery registration: {:?}", e)); - } - res + self.send_queue.push_back(Datagram { payload: payload, address: address }); } - fn on_packet(&mut self, packet: &[u8], from: SocketAddr) -> Result, Error> { + + pub fn on_packet(&mut self, packet: &[u8], from: SocketAddr) -> Result, Error> { // validate packet if packet.len() < 32 + 65 + 4 + 1 { return Err(ErrorKind::BadProtocol.into()); @@ -421,7 +428,7 @@ impl Discovery { PACKET_FIND_NODE => self.on_find_node(&rlp, &node_id, &from), PACKET_NEIGHBOURS => self.on_neighbours(&rlp, &node_id, &from), _ => { - debug!("Unknown UDP packet: {}", packet_id); + debug!(target: "discovery", "Unknown UDP packet: {}", packet_id); Ok(None) } } @@ -447,37 +454,57 @@ impl Discovery { let dest = NodeEndpoint::from_rlp(&rlp.at(2)?)?; let timestamp: u64 = rlp.val_at(3)?; self.check_timestamp(timestamp)?; - let mut added_map = HashMap::new(); + + let mut response = RlpStream::new_list(3); + dest.to_rlp_list(&mut response); + response.append(&echo_hash); + append_expiration(&mut response); + self.send_packet(PACKET_PONG, from, &response.drain())?; + let entry = NodeEntry { id: node.clone(), endpoint: source.clone() }; if !entry.endpoint.is_valid() { debug!(target: "discovery", "Got bad address: {:?}", entry); } else if !self.is_allowed(&entry) { debug!(target: "discovery", "Address not allowed: {:?}", entry); } else { - self.update_node(entry.clone()); - added_map.insert(node.clone(), entry); + self.add_node(entry.clone()); } - let mut response = RlpStream::new_list(2); - dest.to_rlp_list(&mut response); - response.append(&echo_hash); - self.send_packet(PACKET_PONG, from, &response.drain())?; - Ok(Some(TableUpdates { added: added_map, removed: HashSet::new() })) + Ok(None) } - fn on_pong(&mut self, rlp: &Rlp, node: &NodeId, from: &SocketAddr) -> Result, Error> { + fn on_pong(&mut self, rlp: &Rlp, node_id: &NodeId, from: &SocketAddr) -> Result, Error> { trace!(target: "discovery", "Got Pong from {:?}", &from); - // TODO: validate pong packet in rlp.val_at(1) let dest = NodeEndpoint::from_rlp(&rlp.at(0)?)?; + let echo_hash: H256 = rlp.val_at(1)?; let timestamp: u64 = rlp.val_at(2)?; self.check_timestamp(timestamp)?; - let mut entry = NodeEntry { id: node.clone(), endpoint: dest }; - if !entry.endpoint.is_valid() { - debug!(target: "discovery", "Bad address: {:?}", entry); - entry.endpoint.address = from.clone(); + let mut node = NodeEntry { id: node_id.clone(), endpoint: dest }; + if !node.endpoint.is_valid() { + debug!(target: "discovery", "Bad address: {:?}", node); + node.endpoint.address = from.clone(); + } + + let is_expected = match self.in_flight_requests.entry(*node_id) { + Entry::Occupied(entry) => { + let is_expected = { + let request = entry.get(); + request.packet_id == PACKET_PING && request.packet_hash == echo_hash + }; + if is_expected { + entry.remove(); + } + is_expected + }, + Entry::Vacant(_) => false + }; + + if is_expected { + Ok(self.update_node(node)) + } else { + debug!(target: "discovery", "Got unexpected Pong from {:?}", &from); + Ok(None) } - self.clear_ping(node); - Ok(None) } fn on_find_node(&mut self, rlp: &Rlp, _node: &NodeId, from: &SocketAddr) -> Result, Error> { @@ -501,22 +528,49 @@ impl Discovery { let limit = (MAX_DATAGRAM_SIZE - 109) / 90; let chunks = nearest.chunks(limit); let packets = chunks.map(|c| { - let mut rlp = RlpStream::new_list(1); + let mut rlp = RlpStream::new_list(2); rlp.begin_list(c.len()); for n in 0 .. c.len() { rlp.begin_list(4); c[n].endpoint.to_rlp(&mut rlp); rlp.append(&c[n].id); } + append_expiration(&mut rlp); rlp.out() }); packets.collect() } - fn on_neighbours(&mut self, rlp: &Rlp, _node: &NodeId, from: &SocketAddr) -> Result, Error> { - // TODO: validate packet - let mut added = HashMap::new(); - trace!(target: "discovery", "Got {} Neighbours from {:?}", rlp.at(0)?.item_count()?, &from); + fn on_neighbours(&mut self, rlp: &Rlp, node_id: &NodeId, from: &SocketAddr) -> Result, Error> { + let results_count = rlp.at(0)?.item_count()?; + + let is_expected = match self.in_flight_requests.entry(*node_id) { + Entry::Occupied(mut entry) => { + let result = { + let request = entry.get_mut(); + if request.packet_id == PACKET_FIND_NODE && + request.response_count + results_count <= BUCKET_SIZE + { + request.response_count += results_count; + true + } else { + false + } + }; + if entry.get().response_count == BUCKET_SIZE { + entry.remove(); + } + result + } + Entry::Vacant(_) => false, + }; + + if !is_expected { + debug!(target: "discovery", "Got unexpected Neighbors from {:?}", &from); + return Ok(None); + } + + trace!(target: "discovery", "Got {} Neighbours from {:?}", results_count, &from); for r in rlp.at(0)?.iter() { let endpoint = NodeEndpoint::from_rlp(&r)?; if !endpoint.is_valid() { @@ -532,35 +586,62 @@ impl Discovery { debug!(target: "discovery", "Address not allowed: {:?}", entry); continue; } - added.insert(node_id, entry.clone()); - self.ping(&entry.endpoint); - self.update_node(entry); + self.add_node(entry); } - Ok(Some(TableUpdates { added: added, removed: HashSet::new() })) + Ok(None) } - fn check_expired(&mut self, force: bool) -> HashSet { - let now = Instant::now(); + fn check_expired(&mut self, time: Instant) -> HashSet { let mut removed: HashSet = HashSet::new(); - for bucket in &mut self.node_buckets { - bucket.nodes.retain(|node| { - if let Some(timeout) = node.timeout { - if !force && now.duration_since(timeout) < PING_TIMEOUT { - true - } - else { - trace!(target: "discovery", "Removed expired node {:?}", &node.address); - removed.insert(node.address.id.clone()); - false - } - } else { true } - }); + while let Some((node_id, sent_at)) = self.expiring_pings.pop_front() { + if time.duration_since(sent_at) <= PING_TIMEOUT { + self.expiring_pings.push_front((node_id, sent_at)); + break; + } + self.expire_in_flight_request(node_id, sent_at, &mut removed); + } + while let Some((node_id, sent_at)) = self.expiring_finds.pop_front() { + if time.duration_since(sent_at) <= FIND_NODE_TIMEOUT { + self.expiring_finds.push_front((node_id, sent_at)); + break; + } + self.expire_in_flight_request(node_id, sent_at, &mut removed); } removed } + fn expire_in_flight_request(&mut self, node_id: NodeId, sent_at: Instant, removed: &mut HashSet) { + if let Entry::Occupied(entry) = self.in_flight_requests.entry(node_id) { + if entry.get().sent_at == sent_at { + entry.remove(); + + // Attempt to remove from bucket if in one. + let id_hash = keccak(&node_id); + let dist = Discovery::distance(&self.id_hash, &id_hash) + .expect("distance is None only if id hashes are equal; will never send request to self; qed"); + let bucket = &mut self.node_buckets[dist]; + if let Some(index) = bucket.nodes.iter().position(|n| n.id_hash == id_hash) { + if bucket.nodes[index].fail_count < self.request_backoff.len() { + let node = &mut bucket.nodes[index]; + node.backoff_until = Instant::now() + self.request_backoff[node.fail_count]; + node.fail_count += 1; + trace!( + target: "discovery", + "Requests to node {:?} timed out {} consecutive time(s)", + &node.address, node.fail_count + ); + } else { + removed.insert(node_id); + let node = bucket.nodes.remove(index).expect("index was located in if condition"); + debug!(target: "discovery", "Removed expired node {:?}", &node.address); + } + } + } + } + } + pub fn round(&mut self) -> Option { - let removed = self.check_expired(false); + let removed = self.check_expired(Instant::now()); self.discover(); if !removed.is_empty() { Some(TableUpdates { added: HashMap::new(), removed: removed }) @@ -571,26 +652,61 @@ impl Discovery { self.start(); } - pub fn register_socket(&self, event_loop: &mut EventLoop) -> Result<(), Error> { - event_loop.register(&self.udp_socket, Token(self.token), Ready::all(), PollOpt::edge()).expect("Error registering UDP socket"); - Ok(()) + pub fn any_sends_queued(&self) -> bool { + !self.send_queue.is_empty() } - pub fn update_registration(&self, event_loop: &mut EventLoop) -> Result<(), Error> { - let registration = if !self.send_queue.is_empty() { - Ready::readable() | Ready::writable() - } else { - Ready::readable() - }; - event_loop.reregister(&self.udp_socket, Token(self.token), registration, PollOpt::edge()).expect("Error reregistering UDP socket"); - Ok(()) + pub fn dequeue_send(&mut self) -> Option { + self.send_queue.pop_front() + } + + pub fn requeue_send(&mut self, datagram: Datagram) { + self.send_queue.push_front(datagram) } } +fn append_expiration(rlp: &mut RlpStream) { + let expiry = SystemTime::now() + EXPIRY_TIME; + let timestamp = expiry.duration_since(UNIX_EPOCH).unwrap_or_default().as_secs() as u32; + rlp.append(×tamp); +} + +fn assemble_packet(packet_id: u8, bytes: &[u8], secret: &Secret) -> Result { + let mut packet = Bytes::with_capacity(bytes.len() + 32 + 65 + 1); + packet.resize(32 + 65, 0); // Filled in below + packet.push(packet_id); + packet.extend_from_slice(bytes); + + let hash = keccak(&packet[(32 + 65)..]); + let signature = match sign(secret, &hash) { + Ok(s) => s, + Err(e) => { + warn!(target: "discovery", "Error signing UDP packet"); + return Err(Error::from(e)); + } + }; + packet[32..(32 + 65)].copy_from_slice(&signature[..]); + let signed_hash = keccak(&packet[32..]); + packet[0..32].copy_from_slice(&signed_hash); + Ok(packet) +} + +// Selects the next node in a bucket to ping. Chooses the eligible node least recently seen. +fn select_bucket_ping<'a, I>(nodes: I) -> Option +where + I: Iterator +{ + let now = Instant::now(); + nodes + .filter(|n| n.backoff_until < now) + .min_by_key(|n| n.last_seen) + .map(|n| n.address.clone()) +} + #[cfg(test)] mod tests { use super::*; - use std::net::{SocketAddr}; + use std::net::{IpAddr,Ipv4Addr}; use node_table::{Node, NodeId, NodeEndpoint}; use std::str::FromStr; @@ -614,52 +730,151 @@ mod tests { assert!(packets.last().unwrap().len() > 0); } + #[test] + fn ping_queue() { + let key = Random.generate().unwrap(); + let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40445").unwrap(), udp_port: 40445 }; + let mut discovery = Discovery::new(&key, ep.clone(), IpFilter::default()); + + for i in 1..(MAX_NODES_PING+1) { + discovery.add_node(NodeEntry { id: NodeId::random(), endpoint: ep.clone() }); + assert_eq!(discovery.in_flight_requests.len(), i); + assert_eq!(discovery.send_queue.len(), i); + assert_eq!(discovery.adding_nodes.len(), 0); + } + for i in 1..20 { + discovery.add_node(NodeEntry { id: NodeId::random(), endpoint: ep.clone() }); + assert_eq!(discovery.in_flight_requests.len(), MAX_NODES_PING); + assert_eq!(discovery.send_queue.len(), MAX_NODES_PING); + assert_eq!(discovery.adding_nodes.len(), i); + } + } + #[test] fn discovery() { - let key1 = Random.generate().unwrap(); - let key2 = Random.generate().unwrap(); - let ep1 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40444").unwrap(), udp_port: 40444 }; - let ep2 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40445").unwrap(), udp_port: 40445 }; - let mut discovery1 = Discovery::new(&key1, ep1.address.clone(), ep1.clone(), 0, IpFilter::default()); - let mut discovery2 = Discovery::new(&key2, ep2.address.clone(), ep2.clone(), 0, IpFilter::default()); - - let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7770").unwrap(); - let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7771").unwrap(); - discovery1.add_node(NodeEntry { id: node1.id.clone(), endpoint: node1.endpoint.clone() }); - discovery1.add_node(NodeEntry { id: node2.id.clone(), endpoint: node2.endpoint.clone() }); - - discovery2.add_node(NodeEntry { id: key1.public().clone(), endpoint: ep1.clone() }); - discovery2.refresh(); - - for _ in 0 .. 10 { - while !discovery1.send_queue.is_empty() { - let datagramm = discovery1.send_queue.pop_front().unwrap(); - if datagramm.address == ep2.address { - discovery2.on_packet(&datagramm.payload, ep1.address.clone()).ok(); - } - } - while !discovery2.send_queue.is_empty() { - let datagramm = discovery2.send_queue.pop_front().unwrap(); - if datagramm.address == ep1.address { - discovery1.on_packet(&datagramm.payload, ep2.address.clone()).ok(); + let mut discovery_handlers = (0..5).map(|i| { + let key = Random.generate().unwrap(); + let ep = NodeEndpoint { + address: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 41000 + i), + udp_port: 41000 + i, + }; + Discovery::new(&key, ep, IpFilter::default()) + }) + .collect::>(); + + // Sort inversely by XOR distance to the 0 hash. + discovery_handlers.sort_by(|a, b| b.id_hash.cmp(&a.id_hash)); + + // Initialize the routing table of each with the next one in order. + for i in 0 .. 5 { + let node = NodeEntry { + id: discovery_handlers[(i + 1) % 5].id, + endpoint: discovery_handlers[(i + 1) % 5].public_endpoint.clone(), + }; + discovery_handlers[i].update_node(node); + } + + // After 4 discovery rounds, the first one should have learned about the rest. + for _round in 0 .. 4 { + discovery_handlers[0].round(); + + let mut continue_loop = true; + while continue_loop { + continue_loop = false; + + // Process all queued messages. + for i in 0 .. 5 { + let src = discovery_handlers[i].public_endpoint.address.clone(); + while let Some(datagram) = discovery_handlers[i].dequeue_send() { + let dest = discovery_handlers.iter_mut() + .find(|disc| datagram.address == disc.public_endpoint.address) + .unwrap(); + dest.on_packet(&datagram.payload, src).ok(); + + continue_loop = true; + } } } - discovery2.round(); } - assert_eq!(discovery2.nearest_node_entries(&NodeId::new()).len(), 3) + + let results = discovery_handlers[0].nearest_node_entries(&NodeId::new()); + assert_eq!(results.len(), 4); } #[test] fn removes_expired() { let key = Random.generate().unwrap(); let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40446").unwrap(), udp_port: 40447 }; - let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0, IpFilter::default()); - for _ in 0..1200 { + let discovery = Discovery::new(&key, ep.clone(), IpFilter::default()); + + let mut discovery = Discovery { request_backoff: &[], ..discovery }; + + let total_bucket_nodes = |node_buckets: &Vec| -> usize { + node_buckets.iter().map(|bucket| bucket.nodes.len()).sum() + }; + + let node_entries = (0..1200) + .map(|_| NodeEntry { id: NodeId::random(), endpoint: ep.clone() }) + .collect::>(); + + discovery.init_node_list(node_entries.clone()); + assert_eq!(total_bucket_nodes(&discovery.node_buckets), 1200); + + // Requests have not expired yet. + let removed = discovery.check_expired(Instant::now()).len(); + assert_eq!(removed, 0); + + // Expiring pings to bucket nodes removes them from bucket. + let removed = discovery.check_expired(Instant::now() + PING_TIMEOUT).len(); + assert!(removed > 0); + assert_eq!(total_bucket_nodes(&discovery.node_buckets), 1200 - removed); + + for _ in 0..100 { discovery.add_node(NodeEntry { id: NodeId::random(), endpoint: ep.clone() }); } - assert!(discovery.nearest_node_entries(&NodeId::new()).len() <= 16); - let removed = discovery.check_expired(true).len(); + assert!(discovery.in_flight_requests.len() > 0); + + // Expire pings to nodes that are not in buckets. + let removed = discovery.check_expired(Instant::now() + PING_TIMEOUT).len(); + assert_eq!(removed, 0); + assert_eq!(discovery.in_flight_requests.len(), 0); + + let from = SocketAddr::from_str("99.99.99.99:40445").unwrap(); + + // FIND_NODE times out because it doesn't receive k results. + let key = Random.generate().unwrap(); + discovery.send_find_node(&node_entries[100], key.public()).unwrap(); + for payload in Discovery::prepare_neighbours_packets(&node_entries[101..116]) { + let packet = assemble_packet(PACKET_NEIGHBOURS, &payload, &key.secret()).unwrap(); + discovery.on_packet(&packet, from.clone()).unwrap(); + } + + let removed = discovery.check_expired(Instant::now() + FIND_NODE_TIMEOUT).len(); assert!(removed > 0); + + // FIND_NODE does not time out because it receives k results. + discovery.send_find_node(&node_entries[100], key.public()).unwrap(); + for payload in Discovery::prepare_neighbours_packets(&node_entries[101..117]) { + let packet = assemble_packet(PACKET_NEIGHBOURS, &payload, &key.secret()).unwrap(); + discovery.on_packet(&packet, from.clone()).unwrap(); + } + + let removed = discovery.check_expired(Instant::now() + FIND_NODE_TIMEOUT).len(); + assert_eq!(removed, 0); + + // Test bucket evictions with retries. + let request_backoff = [Duration::new(0, 0); 2]; + let mut discovery = Discovery { request_backoff: &request_backoff, ..discovery }; + + for _ in 0..2 { + discovery.ping(&node_entries[101]).unwrap(); + let removed = discovery.check_expired(Instant::now() + PING_TIMEOUT).len(); + assert_eq!(removed, 0); + } + + discovery.ping(&node_entries[101]).unwrap(); + let removed = discovery.check_expired(Instant::now() + PING_TIMEOUT).len(); + assert_eq!(removed, 1); } #[test] @@ -668,14 +883,11 @@ mod tests { let key = Random.generate().unwrap(); let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40447").unwrap(), udp_port: 40447 }; - let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0, IpFilter::default()); + let mut discovery = Discovery::new(&key, ep.clone(), IpFilter::default()); for _ in 0..(16 + 10) { - discovery.node_buckets[0].nodes.push_back(BucketEntry { - address: NodeEntry { id: NodeId::new(), endpoint: ep.clone() }, - timeout: None, - id_hash: keccak(NodeId::new()), - }); + let entry = BucketEntry::new(NodeEntry { id: NodeId::new(), endpoint: ep.clone() }); + discovery.node_buckets[0].nodes.push_back(entry); } let nearest = discovery.nearest_node_entries(&NodeId::new()); assert_eq!(nearest.len(), 16) @@ -728,9 +940,9 @@ mod tests { let key = Secret::from_str(secret_hex) .and_then(|secret| KeyPair::from_secret(secret)) .unwrap(); - let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0, IpFilter::default()); + let mut discovery = Discovery::new(&key, ep.clone(), IpFilter::default()); - node_entries.iter().for_each(|entry| discovery.update_node(entry.clone())); + discovery.init_node_list(node_entries.clone()); let expected_bucket_sizes = vec![ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -773,7 +985,7 @@ mod tests { fn packets() { let key = Random.generate().unwrap(); let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40449").unwrap(), udp_port: 40449 }; - let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0, IpFilter::default()); + let mut discovery = Discovery::new(&key, ep.clone(), IpFilter::default()); discovery.check_timestamps = false; let from = SocketAddr::from_str("99.99.99.99:40445").unwrap(); @@ -838,17 +1050,70 @@ mod tests { fn test_ping() { let key1 = Random.generate().unwrap(); let key2 = Random.generate().unwrap(); + let key3 = Random.generate().unwrap(); let ep1 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40344").unwrap(), udp_port: 40344 }; let ep2 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40345").unwrap(), udp_port: 40345 }; - let mut discovery1 = Discovery::new(&key1, ep1.address.clone(), ep1.clone(), 0, IpFilter::default()); - let mut discovery2 = Discovery::new(&key2, ep2.address.clone(), ep2.clone(), 0, IpFilter::default()); + let ep3 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40346").unwrap(), udp_port: 40345 }; + let mut discovery1 = Discovery::new(&key1, ep1.clone(), IpFilter::default()); + let mut discovery2 = Discovery::new(&key2, ep2.clone(), IpFilter::default()); + + discovery1.ping(&NodeEntry { id: discovery2.id, endpoint: ep2.clone() }).unwrap(); + let ping_data = discovery1.dequeue_send().unwrap(); + assert!(!discovery1.any_sends_queued()); + let data = &ping_data.payload[(32 + 65)..]; + assert_eq!(data[0], PACKET_PING); + let rlp = Rlp::new(&data[1..]); + assert_eq!(ep1, NodeEndpoint::from_rlp(&rlp.at(1).unwrap()).unwrap()); + assert_eq!(ep2, NodeEndpoint::from_rlp(&rlp.at(2).unwrap()).unwrap()); - discovery1.ping(&ep2); - let ping_data = discovery1.send_queue.pop_front().unwrap(); - discovery2.on_packet(&ping_data.payload, ep1.address.clone()).ok(); - let pong_data = discovery2.send_queue.pop_front().unwrap(); + if let Some(_) = discovery2.on_packet(&ping_data.payload, ep1.address.clone()).unwrap() { + panic!("Expected no changes to discovery2's table"); + } + let pong_data = discovery2.dequeue_send().unwrap(); let data = &pong_data.payload[(32 + 65)..]; + assert_eq!(data[0], PACKET_PONG); + let rlp = Rlp::new(&data[1..]); + assert_eq!(ping_data.payload[0..32], rlp.val_at::>(1).unwrap()[..]); + + // Create a pong packet with incorrect echo hash and assert that it is rejected. + let mut incorrect_pong_rlp = RlpStream::new_list(3); + ep1.to_rlp_list(&mut incorrect_pong_rlp); + incorrect_pong_rlp.append(&H256::default()); + append_expiration(&mut incorrect_pong_rlp); + let incorrect_pong_data = assemble_packet( + PACKET_PONG, &incorrect_pong_rlp.drain(), &discovery2.secret + ).unwrap(); + if let Some(_) = discovery1.on_packet(&incorrect_pong_data, ep2.address.clone()).unwrap() { + panic!("Expected no changes to discovery1's table because pong hash is incorrect"); + } + + // Delivery of valid pong response should add to routing table. + if let Some(table_updates) = discovery1.on_packet(&pong_data.payload, ep2.address.clone()).unwrap() { + assert_eq!(table_updates.added.len(), 1); + assert_eq!(table_updates.removed.len(), 0); + assert!(table_updates.added.contains_key(&discovery2.id)); + } else { + panic!("Expected discovery1 to be added to discovery1's table"); + } + + let ping_back = discovery2.dequeue_send().unwrap(); + assert!(!discovery2.any_sends_queued()); + let data = &ping_back.payload[(32 + 65)..]; + assert_eq!(data[0], PACKET_PING); let rlp = Rlp::new(&data[1..]); - assert_eq!(ping_data.payload[0..32], rlp.val_at::>(1).unwrap()[..]) + assert_eq!(ep2, NodeEndpoint::from_rlp(&rlp.at(1).unwrap()).unwrap()); + assert_eq!(ep1, NodeEndpoint::from_rlp(&rlp.at(2).unwrap()).unwrap()); + + // Deliver an unexpected PONG message to discover1. + let mut unexpected_pong_rlp = RlpStream::new_list(3); + ep3.to_rlp_list(&mut unexpected_pong_rlp); + unexpected_pong_rlp.append(&H256::default()); + append_expiration(&mut unexpected_pong_rlp); + let unexpected_pong = assemble_packet( + PACKET_PONG, &unexpected_pong_rlp.drain(), key3.secret() + ).unwrap(); + if let Some(_) = discovery1.on_packet(&unexpected_pong, ep3.address.clone()).unwrap() { + panic!("Expected no changes to discovery1's table for unexpected pong"); + } } } diff --git a/util/network-devp2p/src/handshake.rs b/util/network-devp2p/src/handshake.rs index 891dd7c2578e0790d37b7460f2d7e67e498c2570..4f54f0009fef6f983410def34a1693749af33e5e 100644 --- a/util/network-devp2p/src/handshake.rs +++ b/util/network-devp2p/src/handshake.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -19,14 +19,14 @@ use rand::random; use hash::write_keccak; use mio::tcp::*; use ethereum_types::{H256, H520}; -use ethcore_bytes::Bytes; +use parity_bytes::Bytes; use rlp::{Rlp, RlpStream}; use connection::{Connection}; use node_table::NodeId; use io::{IoContext, StreamToken}; use ethkey::{KeyPair, Public, Secret, recover, sign, Generator, Random}; use ethkey::crypto::{ecdh, ecies}; -use network::{Error, ErrorKind, HostInfo as HostInfoTrait}; +use network::{Error, ErrorKind}; use host::HostInfo; #[derive(PartialEq, Eq, Debug)] @@ -515,4 +515,3 @@ mod test { check_ack(&h, 57); } } - diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index f9180700fe3b73c136eac0431d2d86afdf129786..81e304f1ac18d8133b4c9ba64e614fc03cef37fb 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -30,6 +30,7 @@ use hash::keccak; use mio::*; use mio::deprecated::{EventLoop}; use mio::tcp::*; +use mio::udp::*; use ethereum_types::H256; use rlp::{RlpStream, Encodable}; @@ -39,9 +40,8 @@ use PROTOCOL_VERSION; use node_table::*; use network::{NetworkConfiguration, NetworkIoMessage, ProtocolId, PeerId, PacketId}; use network::{NonReservedPeerMode, NetworkContext as NetworkContextTrait}; -use network::HostInfo as HostInfoTrait; use network::{SessionInfo, Error, ErrorKind, DisconnectReason, NetworkProtocolHandler}; -use discovery::{Discovery, TableUpdates, NodeEntry}; +use discovery::{Discovery, TableUpdates, NodeEntry, MAX_DATAGRAM_SIZE}; use ip_utils::{map_external_address, select_public_address}; use path::restrict_permissions_owner; use parking_lot::{Mutex, RwLock}; @@ -49,7 +49,7 @@ use network::{ConnectionFilter, ConnectionDirection}; type Slab = ::slab::Slab; -const MAX_SESSIONS: usize = 1024 + MAX_HANDSHAKES; +const MAX_SESSIONS: usize = 2048 + MAX_HANDSHAKES; const MAX_HANDSHAKES: usize = 1024; const DEFAULT_PORT: u16 = 30303; @@ -223,10 +223,8 @@ impl HostInfo { pub(crate) fn secret(&self) -> &Secret { self.keys.secret() } -} -impl HostInfoTrait for HostInfo { - fn id(&self) -> &NodeId { + pub(crate) fn id(&self) -> &NodeId { self.keys.public() } } @@ -242,9 +240,10 @@ struct ProtocolTimer { /// Root IO handler. Manages protocol handlers, IO timers and network connections. pub struct Host { pub info: RwLock, + udp_socket: Mutex>, tcp_listener: Mutex, sessions: Arc>>, - discovery: Mutex>, + discovery: Mutex>>, nodes: RwLock, handlers: RwLock>>, timers: RwLock>, @@ -298,6 +297,7 @@ impl Host { local_endpoint: local_endpoint, }), discovery: Mutex::new(None), + udp_socket: Mutex::new(None), tcp_listener: Mutex::new(tcp_listener), sessions: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_SESSION, MAX_SESSIONS))), nodes: RwLock::new(NodeTable::new(path)), @@ -461,13 +461,16 @@ impl Host { let discovery = { let info = self.info.read(); if info.config.discovery_enabled && info.config.non_reserved_mode == NonReservedPeerMode::Accept { - let mut udp_addr = local_endpoint.address.clone(); - udp_addr.set_port(local_endpoint.udp_port); - Some(Discovery::new(&info.keys, udp_addr, public_endpoint, DISCOVERY, allow_ips)) + Some(Discovery::new(&info.keys, public_endpoint, allow_ips)) } else { None } }; if let Some(mut discovery) = discovery { + let mut udp_addr = local_endpoint.address; + udp_addr.set_port(local_endpoint.udp_port); + let socket = UdpSocket::bind(&udp_addr).expect("Error binding UDP socket"); + *self.udp_socket.lock() = Some(socket); + discovery.init_node_list(self.nodes.read().entries()); discovery.add_node_list(self.nodes.read().entries()); *self.discovery.lock() = Some(discovery); @@ -667,7 +670,7 @@ impl Host { } } - fn connection_closed(&self, token: TimerToken, io: &IoContext) { + fn connection_closed(&self, token: StreamToken, io: &IoContext) { trace!(target: "network", "Connection closed: {}", token); self.kill_connection(token, io, true); } @@ -822,6 +825,67 @@ impl Host { } } + fn discovery_readable(&self, io: &IoContext) { + let node_changes = match (self.udp_socket.lock().as_ref(), self.discovery.lock().as_mut()) { + (Some(udp_socket), Some(discovery)) => { + let mut buf = [0u8; MAX_DATAGRAM_SIZE]; + let writable = discovery.any_sends_queued(); + let res = match udp_socket.recv_from(&mut buf) { + Ok(Some((len, address))) => discovery.on_packet(&buf[0..len], address).unwrap_or_else(|e| { + debug!(target: "network", "Error processing UDP packet: {:?}", e); + None + }), + Ok(_) => None, + Err(e) => { + debug!(target: "network", "Error reading UPD socket: {:?}", e); + None + } + }; + let new_writable = discovery.any_sends_queued(); + if writable != new_writable { + io.update_registration(DISCOVERY) + .unwrap_or_else(|e| { + debug!(target: "network" ,"Error updating discovery registration: {:?}", e) + }); + } + res + }, + _ => None, + }; + if let Some(node_changes) = node_changes { + self.update_nodes(io, node_changes); + } + } + + fn discovery_writable(&self, io: &IoContext) { + match (self.udp_socket.lock().as_ref(), self.discovery.lock().as_mut()) { + (Some(udp_socket), Some(discovery)) => { + while let Some(data) = discovery.dequeue_send() { + match udp_socket.send_to(&data.payload, &data.address) { + Ok(Some(size)) if size == data.payload.len() => { + }, + Ok(Some(_)) => { + warn!(target: "network", "UDP sent incomplete datagram"); + }, + Ok(None) => { + discovery.requeue_send(data); + return; + } + Err(e) => { + debug!(target: "network", "UDP send error: {:?}, address: {:?}", e, &data.address); + return; + } + } + } + io.update_registration(DISCOVERY) + .unwrap_or_else(|e| { + debug!(target: "network", "Error updating discovery registration: {:?}", e) + }); + }, + _ => (), + } + } + fn connection_timeout(&self, token: StreamToken, io: &IoContext) { trace!(target: "network", "Connection timeout: {}", token); self.kill_connection(token, io, true) @@ -923,12 +987,7 @@ impl IoHandler for Host { } match stream { FIRST_SESSION ... LAST_SESSION => self.session_readable(stream, io), - DISCOVERY => { - let node_changes = { self.discovery.lock().as_mut().map_or(None, |d| d.readable(io)) }; - if let Some(node_changes) = node_changes { - self.update_nodes(io, node_changes); - } - }, + DISCOVERY => self.discovery_readable(io), TCP_ACCEPT => self.accept(io), _ => panic!("Received unknown readable token"), } @@ -940,9 +999,7 @@ impl IoHandler for Host { } match stream { FIRST_SESSION ... LAST_SESSION => self.session_writable(stream, io), - DISCOVERY => { - self.discovery.lock().as_mut().map(|d| d.writable(io)); - } + DISCOVERY => self.discovery_writable(io), _ => panic!("Received unknown writable token"), } } @@ -997,7 +1054,6 @@ impl IoHandler for Host { let reserved = self.reserved_nodes.read(); h.initialize( &NetworkContext::new(io, *protocol, None, self.sessions.clone(), &reserved), - &*self.info.read(), ); self.handlers.write().insert(*protocol, h); let mut info = self.info.write(); @@ -1059,7 +1115,13 @@ impl IoHandler for Host { session.lock().register_socket(reg, event_loop).expect("Error registering socket"); } } - DISCOVERY => self.discovery.lock().as_ref().and_then(|d| d.register_socket(event_loop).ok()).expect("Error registering discovery socket"), + DISCOVERY => match self.udp_socket.lock().as_ref() { + Some(udp_socket) => { + event_loop.register(udp_socket, reg, Ready::all(), PollOpt::edge()) + .expect("Error registering UDP socket"); + }, + _ => panic!("Error registering discovery socket"), + } TCP_ACCEPT => event_loop.register(&*self.tcp_listener.lock(), Token(TCP_ACCEPT), Ready::all(), PollOpt::edge()).expect("Error registering stream"), _ => warn!("Unexpected stream registration") } @@ -1090,7 +1152,18 @@ impl IoHandler for Host { connection.lock().update_socket(reg, event_loop).expect("Error updating socket"); } } - DISCOVERY => self.discovery.lock().as_ref().and_then(|d| d.update_registration(event_loop).ok()).expect("Error reregistering discovery socket"), + DISCOVERY => match (self.udp_socket.lock().as_ref(), self.discovery.lock().as_ref()) { + (Some(udp_socket), Some(discovery)) => { + let registration = if discovery.any_sends_queued() { + Ready::readable() | Ready::writable() + } else { + Ready::readable() + }; + event_loop.reregister(udp_socket, reg, registration, PollOpt::edge()) + .expect("Error reregistering UDP socket"); + }, + _ => panic!("Error reregistering discovery socket"), + } TCP_ACCEPT => event_loop.reregister(&*self.tcp_listener.lock(), Token(TCP_ACCEPT), Ready::all(), PollOpt::edge()).expect("Error reregistering stream"), _ => warn!("Unexpected stream update") } @@ -1158,7 +1231,6 @@ fn key_save_load() { assert_eq!(key, r.unwrap()); } - #[test] fn host_client_url() { let mut config = NetworkConfiguration::new_local(); diff --git a/util/network-devp2p/src/ip_utils.rs b/util/network-devp2p/src/ip_utils.rs index 3d7d33a0661c7a4cc4233c5742fff61751a26783..cde0c8c6bb07b96fea2545dd29e5d6626c2006e1 100644 --- a/util/network-devp2p/src/ip_utils.rs +++ b/util/network-devp2p/src/ip_utils.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -20,8 +20,8 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV use std::io; use igd::{PortMappingProtocol, search_gateway_from_timeout}; use std::time::Duration; -use node_table::{NodeEndpoint}; -use ipnetwork::{IpNetwork}; +use node_table::NodeEndpoint; +use ipnetwork::IpNetwork; /// Socket address extension for rustc beta. To be replaces with now unstable API pub trait SocketAddrExt { @@ -225,28 +225,17 @@ mod getinterfaces { let sa: *const sockaddr_in = sa as *const sockaddr_in; let sa = unsafe { &*sa }; let (addr, port) = (sa.sin_addr.s_addr, sa.sin_port); - (IpAddr::V4(Ipv4Addr::new( - (addr & 0x0000_00FF) as u8, - ((addr & 0x0000_FF00) >> 8) as u8, - ((addr & 0x00FF_0000) >> 16) as u8, - ((addr & 0xFF00_0000) >> 24) as u8)), - port) + // convert u32 to an `Ipv4 address`, but the u32 must be converted to `host-order` + // that's why `from_be` is used! + (IpAddr::V4(Ipv4Addr::from(::from_be(addr))), port) }, AF_INET6 => { let sa: *const sockaddr_in6 = sa as *const sockaddr_in6; let sa = & unsafe { *sa }; let (addr, port) = (sa.sin6_addr.s6_addr, sa.sin6_port); - let addr: [u16; 8] = unsafe { mem::transmute(addr) }; - (IpAddr::V6(Ipv6Addr::new( - addr[0], - addr[1], - addr[2], - addr[3], - addr[4], - addr[5], - addr[6], - addr[7])), - port) + let ip_addr = Ipv6Addr::from(addr); + debug_assert!(addr == ip_addr.octets()); + (IpAddr::V6(ip_addr), port) }, _ => return None, }; @@ -533,5 +522,3 @@ fn ipv6_properties() { check("::", true, false, true); check("::1", false, true, false); } - - diff --git a/util/network-devp2p/src/lib.rs b/util/network-devp2p/src/lib.rs index 244997a6545ad881dafb407aba5c7455d2fc87bb..0df17c070af135f5f194c6706f36dfba1278e205 100644 --- a/util/network-devp2p/src/lib.rs +++ b/util/network-devp2p/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -29,7 +29,7 @@ //! struct MyHandler; //! //! impl NetworkProtocolHandler for MyHandler { -//! fn initialize(&self, io: &NetworkContext, _host_info: &HostInfo) { +//! fn initialize(&self, io: &NetworkContext) { //! io.register_timer(0, Duration::from_secs(1)); //! } //! @@ -61,8 +61,8 @@ #![allow(deprecated)] extern crate ethcore_io as io; -extern crate ethcore_bytes; -extern crate ethcore_crypto as crypto; +extern crate parity_bytes; +extern crate parity_crypto as crypto; extern crate ethereum_types; extern crate parking_lot; extern crate mio; diff --git a/util/network-devp2p/src/node_table.rs b/util/network-devp2p/src/node_table.rs index d5d0207ecd68addab7e39eef3bb1b372b32d2379..2640cec796744c6542916b9475d043edf7a2cb64 100644 --- a/util/network-devp2p/src/node_table.rs +++ b/util/network-devp2p/src/node_table.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -33,7 +33,7 @@ use rand::{self, Rng}; /// Node public key pub type NodeId = H512; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] /// Node address info pub struct NodeEndpoint { /// IP(V4 or V6) address diff --git a/util/network-devp2p/src/service.rs b/util/network-devp2p/src/service.rs index f90c6606714e00fa0f871f7c106d497b9e141ce3..d7182f46180e6685f40393aadd38121f8693459b 100644 --- a/util/network-devp2p/src/service.rs +++ b/util/network-devp2p/src/service.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/network-devp2p/src/session.rs b/util/network-devp2p/src/session.rs index cd8ef56bd4a849338ec43d1f996d5c946df4a424..a405ad469ddb2b2b1da2ce738016493ef97748cc 100644 --- a/util/network-devp2p/src/session.rs +++ b/util/network-devp2p/src/session.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -28,7 +28,7 @@ use connection::{EncryptedConnection, Packet, Connection, MAX_PAYLOAD_SIZE}; use handshake::Handshake; use io::{IoContext, StreamToken}; use network::{Error, ErrorKind, DisconnectReason, SessionInfo, ProtocolId, PeerCapabilityInfo}; -use network::{SessionCapabilityInfo, HostInfo as HostInfoTrait}; +use network::SessionCapabilityInfo; use host::*; use node_table::NodeId; use snappy; @@ -515,4 +515,3 @@ impl Session { Ok(()) } } - diff --git a/util/network-devp2p/tests/tests.rs b/util/network-devp2p/tests/tests.rs index a1d178d65449771cfeecca0ea4f5ff961d663ba8..091f2509ac7fda7378ec7814f4354dd11e4b9b0b 100644 --- a/util/network-devp2p/tests/tests.rs +++ b/util/network-devp2p/tests/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ // along with Parity. If not, see . extern crate parking_lot; -extern crate ethcore_bytes; +extern crate parity_bytes; extern crate ethcore_io as io; extern crate ethcore_logger; extern crate ethcore_network; @@ -27,7 +27,7 @@ use std::sync::Arc; use std::thread; use std::time::*; use parking_lot::Mutex; -use ethcore_bytes::Bytes; +use parity_bytes::Bytes; use ethcore_network::*; use ethcore_network_devp2p::NetworkService; use ethkey::{Random, Generator}; @@ -70,7 +70,7 @@ impl TestProtocol { } impl NetworkProtocolHandler for TestProtocol { - fn initialize(&self, io: &NetworkContext, _host_info: &HostInfo) { + fn initialize(&self, io: &NetworkContext) { io.register_timer(0, Duration::from_millis(10)).unwrap(); } @@ -99,7 +99,6 @@ impl NetworkProtocolHandler for TestProtocol { } } - #[test] fn net_service() { let service = NetworkService::new(NetworkConfiguration::new_local(), None).expect("Error creating network service"); diff --git a/util/network/Cargo.toml b/util/network/Cargo.toml index 4ae699098ddd3b77c492d221fc001e36e1b6931d..53eb58a37ad4d8ce5c938cbb683b17ff4a90f712 100644 --- a/util/network/Cargo.toml +++ b/util/network/Cargo.toml @@ -7,13 +7,13 @@ version = "1.12.0" authors = ["Parity Technologies "] [dependencies] -error-chain = { version = "0.11", default-features = false } -ethcore-crypto = { path = "../../ethcore/crypto" } +error-chain = { version = "0.12", default-features = false } +parity-crypto = { git = "https://github.com/paritytech/parity-common" } ethcore-io = { path = "../io" } ethereum-types = "0.3" ethkey = { path = "../../ethkey" } ipnetwork = "0.12.6" -rlp = { path = "../rlp" } +rlp = { git = "https://github.com/paritytech/parity-common" } libc = "0.2" snappy = { git = "https://github.com/paritytech/rust-snappy" } diff --git a/util/network/src/connection_filter.rs b/util/network/src/connection_filter.rs index 5afe5865b7313643b56b8f4d438d887c57a1eeb8..e146aee4c7c6aed553674c3c5ae96c51ba7e0302 100644 --- a/util/network/src/connection_filter.rs +++ b/util/network/src/connection_filter.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/network/src/error.rs b/util/network/src/error.rs index 50bd01e9bad9140c09e7793516cf6c0f52f90da6..4233b9e058b24d727dbeb0b43518b14cd310cde5 100644 --- a/util/network/src/error.rs +++ b/util/network/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs index 87d3ed9b0e5f0b327b35608980a576e291b3b5c3..c31ace41093295a4f8b768ef113279e83e8e2f27 100644 --- a/util/network/src/lib.rs +++ b/util/network/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -16,7 +16,7 @@ #![recursion_limit="128"] -extern crate ethcore_crypto as crypto; +extern crate parity_crypto as crypto; extern crate ethcore_io as io; extern crate ethereum_types; extern crate ethkey; @@ -333,17 +333,12 @@ impl<'a, T> NetworkContext for &'a T where T: ?Sized + NetworkContext { } } -pub trait HostInfo { - /// Returns public key - fn id(&self) -> &NodeId; -} - /// Network IO protocol handler. This needs to be implemented for each new subprotocol. /// All the handler function are called from within IO event loop. /// `Message` is the type for message data. pub trait NetworkProtocolHandler: Sync + Send { /// Initialize the handler - fn initialize(&self, _io: &NetworkContext, _host_info: &HostInfo) {} + fn initialize(&self, _io: &NetworkContext) {} /// Called when new network packet received. fn read(&self, io: &NetworkContext, peer: &PeerId, packet_id: u8, data: &[u8]); /// Called when new peer is connected. Only called when peer supports the same protocol. diff --git a/util/panic_hook/src/lib.rs b/util/panic_hook/src/lib.rs index 1136e9e362378fe97568b2727c1ad80f1f6f1d42..cc7ed7dedac7e5f533665f3611ce9188357c31ef 100644 --- a/util/panic_hook/src/lib.rs +++ b/util/panic_hook/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -8,7 +8,7 @@ // 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 +// 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 @@ -21,17 +21,26 @@ extern crate backtrace; use std::io::{self, Write}; use std::panic::{self, PanicInfo}; use std::thread; +use std::process; use backtrace::Backtrace; /// Set the panic hook -pub fn set() { - panic::set_hook(Box::new(panic_hook)); +pub fn set_abort() { + set_with(|| process::abort()); +} + +/// Set the panic hook with a closure to be called afterwards. +pub fn set_with(f: F) { + panic::set_hook(Box::new(move |info| { + panic_hook(info); + f(); + })); } static ABOUT_PANIC: &str = " This is a bug. Please report it at: - https://github.com/paritytech/parity/issues/new + https://github.com/paritytech/parity-ethereum/issues/new "; fn panic_hook(info: &PanicInfo) { diff --git a/util/path/Cargo.toml b/util/path/Cargo.toml deleted file mode 100644 index 7df3917b140cd0c4db8879eac22fa6d17bcbc1c6..0000000000000000000000000000000000000000 --- a/util/path/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "path" -version = "0.1.0" -authors = ["debris "] - -[dependencies] diff --git a/util/path/src/lib.rs b/util/path/src/lib.rs deleted file mode 100644 index 761b51152219bedaa5f2ba77f8bd3dc8a4cafd18..0000000000000000000000000000000000000000 --- a/util/path/src/lib.rs +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Path utilities -use std::path::Path; -use std::path::PathBuf; - -#[cfg(target_os = "macos")] -/// 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"); - home.push("Library"); - home.push(name); - home -} - -#[cfg(windows)] -/// 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"); - home.push("AppData"); - home.push("Roaming"); - home.push(name); - home -} - -#[cfg(not(any(target_os = "macos", windows)))] -/// 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"); - home.push(format!(".{}", name.to_lowercase())); - home -} - -/// Get the specific folder inside a config path. -pub fn config_path_with(name: &str, then: &str) -> PathBuf { - let mut path = config_path(name); - path.push(then); - path -} - -/// Default ethereum paths -pub mod ethereum { - use std::path::PathBuf; - - /// Default path for ethereum installation on Mac Os - pub fn default() -> PathBuf { super::config_path("Ethereum") } - - /// Default path for ethereum installation (testnet) - pub fn test() -> PathBuf { - let mut path = default(); - path.push("testnet"); - path - } - - /// Get the specific folder inside default ethereum installation - pub fn with_default(s: &str) -> PathBuf { - let mut path = default(); - path.push(s); - path - } - - /// Get the specific folder inside default ethereum installation configured for testnet - pub fn with_testnet(s: &str) -> PathBuf { - let mut path = default(); - path.push("testnet"); - path.push(s); - path - } -} - -/// Restricts the permissions of given path only to the owner. -#[cfg(unix)] -pub fn restrict_permissions_owner(file_path: &Path, write: bool, executable: bool) -> Result<(), String> { - let perms = ::std::os::unix::fs::PermissionsExt::from_mode(0o400 + write as u32 * 0o200 + executable as u32 * 0o100); - ::std::fs::set_permissions(file_path, perms).map_err(|e| format!("{:?}", e)) -} - -/// Restricts the permissions of given path only to the owner. -#[cfg(not(unix))] -pub fn restrict_permissions_owner(_file_path: &Path, _write: bool, _executable: bool) -> Result<(), String> { - //TODO: implement me - Ok(()) -} - diff --git a/util/patricia-trie-ethereum/Cargo.toml b/util/patricia-trie-ethereum/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..90ca7e4754f96543fbf7ecf5d74f756f7035b367 --- /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 = { git = "https://github.com/paritytech/parity-common" } +keccak-hasher = { path = "../keccak-hasher" } +hashdb = { git = "https://github.com/paritytech/parity-common" } +rlp = { git = "https://github.com/paritytech/parity-common" } +parity-bytes = { git = "https://github.com/paritytech/parity-common" } +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 0000000000000000000000000000000000000000..ac2943fc6218cf1bbf88e2bf7f67f4ea1dbea996 --- /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 parity_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 0000000000000000000000000000000000000000..414a129efe8eea6fcd6e986e621cd315e8e63a1d --- /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 deleted file mode 100644 index 48b06b214637a73124bd7a26c3c12ffec64445b9..0000000000000000000000000000000000000000 --- a/util/patricia_trie/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "patricia-trie" -version = "0.1.0" -authors = ["Parity Technologies "] -description = "Merkle-Patricia Trie (Ethereum Style)" -license = "GPL-3.0" - -[dependencies] -elastic-array = "0.10" -log = "0.3" -rand = "0.4" -ethcore-bytes = { version = "0.1.0", path = "../bytes" } -ethereum-types = "0.3" -keccak-hash = { version = "0.1.0", path = "../hash" } -hashdb = { version = "0.1.1", path = "../hashdb" } -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" } diff --git a/util/patricia_trie/benches/trie.rs b/util/patricia_trie/benches/trie.rs deleted file mode 100644 index f26febdb59592fbe2ad6dfd03f335adb08d00d0e..0000000000000000000000000000000000000000 --- a/util/patricia_trie/benches/trie.rs +++ /dev/null @@ -1,209 +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 . - -#![feature(test)] - -extern crate test; -extern crate ethcore_bytes; -extern crate ethereum_types; -extern crate memorydb; -extern crate patricia_trie as trie; -extern crate keccak_hash; -extern crate trie_standardmap; - -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_standardmap::{Alphabet, ValueMode, StandardMap}; - -fn random_word(alphabet: &[u8], min_count: usize, diff_count: usize, seed: &mut H256) -> Vec { - assert!(min_count + diff_count <= 32); - *seed = keccak(&seed); - let r = min_count + (seed[31] as usize % (diff_count + 1)); - let mut ret: Vec = Vec::with_capacity(r); - for i in 0..r { - ret.push(alphabet[seed[i] as usize % alphabet.len()]); - } - ret -} - -fn random_bytes(min_count: usize, diff_count: usize, seed: &mut H256) -> Vec { - assert!(min_count + diff_count <= 32); - *seed = keccak(&seed); - let r = min_count + (seed[31] as usize % (diff_count + 1)); - seed[0..r].to_vec() -} - -fn random_value(seed: &mut H256) -> Bytes { - *seed = keccak(&seed); - match seed[0] % 2 { - 1 => vec![seed[31];1], - _ => seed.to_vec(), - } -} - -#[bench] -fn trie_insertions_32_mir_1k(b: &mut Bencher) { - let st = StandardMap { - alphabet: Alphabet::All, - min_key: 32, - journal_key: 0, - value_mode: ValueMode::Mirror, - count: 1000, - }; - let d = st.make(); - b.iter(&mut ||{ - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - for i in d.iter() { - t.insert(&i.0, &i.1).unwrap(); - } - }); -} -#[bench] -fn trie_iter(b: &mut Bencher) { - let st = StandardMap { - alphabet: Alphabet::All, - min_key: 32, - journal_key: 0, - value_mode: ValueMode::Mirror, - count: 1000, - }; - let d = st.make(); - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - { - let mut t = TrieDBMut::new(&mut memdb, &mut root); - for i in d.iter() { - t.insert(&i.0, &i.1).unwrap(); - } - } - - b.iter(&mut ||{ - let t = TrieDB::new(&memdb, &root).unwrap(); - for n in t.iter().unwrap() { - black_box(n).unwrap(); - } - }); -} - -#[bench] -fn trie_insertions_32_ran_1k(b: &mut Bencher) { - let st = StandardMap { - alphabet: Alphabet::All, - min_key: 32, - journal_key: 0, - value_mode: ValueMode::Random, - count: 1000, - }; - let d = st.make(); - let mut r = H256::new(); - b.iter(&mut ||{ - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - for i in d.iter() { - t.insert(&i.0, &i.1).unwrap(); - } - r = t.root().clone(); - }); -} - -#[bench] -fn trie_insertions_six_high(b: &mut Bencher) { - let mut d: Vec<(Bytes, Bytes)> = Vec::new(); - let mut seed = H256::new(); - for _ in 0..1000 { - let k = random_bytes(6, 0, &mut seed); - let v = random_value(&mut seed); - d.push((k, v)) - } - - b.iter(||{ - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - for i in d.iter() { - t.insert(&i.0, &i.1).unwrap(); - } - }) -} - -#[bench] -fn trie_insertions_six_mid(b: &mut Bencher) { - let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; - let mut d: Vec<(Bytes, Bytes)> = Vec::new(); - let mut seed = H256::new(); - for _ in 0..1000 { - let k = random_word(alphabet, 6, 0, &mut seed); - let v = random_value(&mut seed); - d.push((k, v)) - } - b.iter(||{ - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - for i in d.iter() { - t.insert(&i.0, &i.1).unwrap(); - } - }) -} - -#[bench] -fn trie_insertions_random_mid(b: &mut Bencher) { - let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; - let mut d: Vec<(Bytes, Bytes)> = Vec::new(); - let mut seed = H256::new(); - for _ in 0..1000 { - let k = random_word(alphabet, 1, 5, &mut seed); - let v = random_value(&mut seed); - d.push((k, v)) - } - - b.iter(||{ - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - for i in d.iter() { - t.insert(&i.0, &i.1).unwrap(); - } - }) -} - -#[bench] -fn trie_insertions_six_low(b: &mut Bencher) { - let alphabet = b"abcdef"; - let mut d: Vec<(Bytes, Bytes)> = Vec::new(); - let mut seed = H256::new(); - for _ in 0..1000 { - let k = random_word(alphabet, 6, 0, &mut seed); - let v = random_value(&mut seed); - d.push((k, v)) - } - - b.iter(||{ - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - for i in d.iter() { - t.insert(&i.0, &i.1).unwrap(); - } - }) -} diff --git a/util/patricia_trie/src/fatdb.rs b/util/patricia_trie/src/fatdb.rs deleted file mode 100644 index d428ff8116b18bbaf83f9c01a67d09969b7ab4f1..0000000000000000000000000000000000000000 --- a/util/patricia_trie/src/fatdb.rs +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2015-2017 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 . - -use ethereum_types::H256; -use keccak::keccak; -use hashdb::HashDB; -use super::{TrieDB, Trie, TrieDBIterator, TrieItem, TrieIterator, Query}; - -/// 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>, -} - -impl<'db> FatDB<'db> { - /// 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) - } - - /// Get the backing database. - 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() - } - - fn contains(&self, key: &[u8]) -> super::Result { - self.raw.contains(&keccak(key)) - } - - fn get_with<'a, 'key, Q: Query>(&'a self, key: &'key [u8], query: Q) -> super::Result> - where 'a: 'key - { - self.raw.get_with(&keccak(key), query) - } -} - -/// Itarator over inserted pairs of key values. -pub struct FatDBIterator<'db> { - trie_iterator: TrieDBIterator<'db>, - trie: &'db TrieDB<'db>, -} - -impl<'db> FatDBIterator<'db> { - /// Creates new iterator. - pub fn new(trie: &'db TrieDB) -> super::Result { - Ok(FatDBIterator { - trie_iterator: TrieDBIterator::new(trie)?, - trie: trie, - }) - } -} - -impl<'db> TrieIterator for FatDBIterator<'db> { - fn seek(&mut self, key: &[u8]) -> super::Result<()> { - self.trie_iterator.seek(&keccak(key)) - } -} - -impl<'db> Iterator for FatDBIterator<'db> { - type Item = TrieItem<'db>; - - fn next(&mut self) -> Option { - self.trie_iterator.next() - .map(|res| - res.map(|(hash, value)| { - let aux_hash = keccak(hash); - (self.trie.db().get(&aux_hash).expect("Missing fatdb hash").into_vec(), value) - }) - ) - } -} - -#[test] -fn fatdb_to_trie() { - 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(); - } - 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 deleted file mode 100644 index 4b7f2de0632acc049528c309834ae848da66d814..0000000000000000000000000000000000000000 --- a/util/patricia_trie/src/fatdbmut.rs +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2015-2017 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 . - -use ethereum_types::H256; -use keccak::keccak; -use hashdb::{HashDB, DBValue}; -use super::{TrieDBMut, TrieMut}; - -/// 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>, -} - -impl<'db> FatDBMut<'db> { - /// 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 { - 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 { - Ok(FatDBMut { raw: TrieDBMut::from_existing(db, root)? }) - } - - /// Get the backing database. - pub fn db(&self) -> &HashDB { - self.raw.db() - } - - /// Get the backing database. - 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() - } - - fn is_empty(&self) -> bool { - self.raw.is_empty() - } - - fn contains(&self, key: &[u8]) -> super::Result { - self.raw.contains(&keccak(key)) - } - - fn get<'a, 'key>(&'a self, key: &'key [u8]) -> super::Result> - where 'a: 'key - { - self.raw.get(&keccak(key)) - } - - fn insert(&mut self, key: &[u8], value: &[u8]) -> super::Result> { - let hash = keccak(key); - let out = self.raw.insert(&hash, 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)); - } - Ok(out) - } - - fn remove(&mut self, key: &[u8]) -> super::Result> { - let hash = keccak(key); - let out = self.raw.remove(&hash)?; - - // don't remove if it already exists. - if out.is_some() { - self.raw.db_mut().remove(&Self::to_aux_key(&hash)); - } - - Ok(out) - } -} - -#[test] -fn fatdb_to_trie() { - 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(); - } - 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/lib.rs b/util/patricia_trie/src/lib.rs deleted file mode 100644 index d1563becff08c22315f7c21f17ed8a5f87902404..0000000000000000000000000000000000000000 --- a/util/patricia_trie/src/lib.rs +++ /dev/null @@ -1,309 +0,0 @@ -// Copyright 2015-2017 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 . - -//! 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; - -#[cfg(test)] -extern crate trie_standardmap as standardmap; - -#[macro_use] -extern crate log; - -use std::{fmt, error}; -use ethereum_types::H256; -use keccak::KECCAK_NULL_RLP; -use hashdb::{HashDB, DBValue}; - -pub mod node; -pub mod triedb; -pub mod triedbmut; -pub mod sectriedb; -pub mod sectriedbmut; -pub mod recorder; - -mod fatdb; -mod fatdbmut; -mod lookup; -mod nibbleslice; -mod nibblevec; - -pub use self::triedbmut::TrieDBMut; -pub use self::triedb::{TrieDB, TrieDBIterator}; -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; - -/// Trie Errors. -/// -/// These borrow the data within them to avoid excessive copying on every -/// trie operation. -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum TrieError { - /// Attempted to create a trie with a state root not in the DB. - InvalidStateRoot(H256), - /// Trie item not found in the database, - IncompleteDatabase(H256), - /// Corrupt Trie item - DecoderError(rlp::DecoderError), -} - -impl fmt::Display for TrieError { - 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), - } - } -} - -impl error::Error for TrieError { - fn description(&self) -> &str { - match *self { - TrieError::InvalidStateRoot(_) => "Invalid state root", - TrieError::IncompleteDatabase(_) => "Incomplete database", - TrieError::DecoderError(ref e) => e.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 `H256`s on successful queries. -pub type Result = ::std::result::Result>; - -/// Trie-Item type. -pub type TrieItem<'a> = Result<(Vec, DBValue)>; - -/// 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 { - /// Output item. - type Item; - - /// Decode a byte-slice into the desired item. - fn decode(self, &[u8]) -> Self::Item; - - /// Record that a node has been passed through. - fn record(&mut self, &H256, &[u8], u32) { } -} - -impl<'a> 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) { - (&mut **self).record(hash, data, depth); - } -} - -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 { - type Item = T; - - fn decode(self, value: &[u8]) -> T { (self.1)(value) } - fn record(&mut self, hash: &H256, 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 { - /// Return the root of the trie. - fn root(&self) -> &H256; - - /// Is the trie empty? - fn is_empty(&self) -> bool { *self.root() == KECCAK_NULL_RLP } - - /// Does the trie contain a given key? - 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 { - 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; - - /// Returns a depth-first iterator over the elements of trie. - fn iter<'a>(&'a self) -> Result + 'a>>; -} - -/// A key-value datastore implemented as a database-backed modified Merkle tree. -pub trait TrieMut { - /// Return the root of the trie. - fn root(&mut self) -> &H256; - - /// Is the trie empty? - fn is_empty(&self) -> bool; - - /// Does the trie contain a given key? - 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; - - /// 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>; - - /// 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>; -} - -/// A trie iterator that also supports random access. -pub trait TrieIterator : Iterator { - /// Position the iterator on the first element with key > `key` - fn seek(&mut self, key: &[u8]) -> Result<()>; -} - -/// Trie types -#[derive(Debug, PartialEq, Clone)] -pub enum TrieSpec { - /// Generic trie. - Generic, - /// Secure trie. - Secure, - /// Secure trie with fat database. - Fat, -} - -impl Default for TrieSpec { - fn default() -> TrieSpec { - TrieSpec::Secure - } -} - -/// Trie factory. -#[derive(Default, Clone)] -pub struct TrieFactory { - spec: TrieSpec, -} - -/// All different kinds of tries. -/// This is used to prevent a heap allocation for every created trie. -pub enum TrieKinds<'db> { - /// A generic trie db. - Generic(TrieDB<'db>), - /// A secure trie db. - Secure(SecTrieDB<'db>), - /// A fat trie db. - Fat(FatDB<'db>), -} - -// wrapper macro for making the match easier to deal with. -macro_rules! wrapper { - ($me: ident, $f_name: ident, $($param: ident),*) => { - match *$me { - TrieKinds::Generic(ref t) => t.$f_name($($param),*), - TrieKinds::Secure(ref t) => t.$f_name($($param),*), - TrieKinds::Fat(ref t) => t.$f_name($($param),*), - } - } -} - -impl<'db> Trie for TrieKinds<'db> { - fn root(&self) -> &H256 { - wrapper!(self, root,) - } - - fn is_empty(&self) -> bool { - wrapper!(self, is_empty,) - } - - 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> - where 'a: 'key - { - wrapper!(self, get_with, key, query) - } - - fn iter<'a>(&'a self) -> Result + 'a>> { - wrapper!(self, iter,) - } -} - -impl TrieFactory { - /// Creates new factory. - pub fn new(spec: TrieSpec) -> Self { - TrieFactory { - spec: spec, - } - } - - /// Create new immutable instance of Trie. - pub fn readonly<'db>(&self, db: &'db HashDB, root: &'db H256) -> Result> { - match self.spec { - TrieSpec::Generic => Ok(TrieKinds::Generic(TrieDB::new(db, root)?)), - TrieSpec::Secure => Ok(TrieKinds::Secure(SecTrieDB::new(db, root)?)), - TrieSpec::Fat => Ok(TrieKinds::Fat(FatDB::new(db, root)?)), - } - } - - /// Create new mutable instance of Trie. - pub fn create<'db>(&self, db: &'db mut HashDB, root: &'db mut H256) -> Box { - 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)), - } - } - - /// 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> { - 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)?)), - } - } - - /// Returns true iff the trie DB is a fat DB (allows enumeration of keys). - pub fn is_fat(&self) -> bool { self.spec == TrieSpec::Fat } -} diff --git a/util/patricia_trie/src/lookup.rs b/util/patricia_trie/src/lookup.rs deleted file mode 100644 index 2d63f7d00e161d6baed65ae2498cf69c29c31b71..0000000000000000000000000000000000000000 --- a/util/patricia_trie/src/lookup.rs +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Trie lookup via HashDB. - -use hashdb::HashDB; -use nibbleslice::NibbleSlice; -use ethereum_types::H256; - -use super::{TrieError, Query}; -use super::node::Node; - -/// Trie lookup helper object. -pub struct Lookup<'a, Q: Query> { - /// database to query from. - pub db: &'a HashDB, - /// Query object to record nodes and transform data. - pub query: Q, - /// Hash to start at - pub hash: H256, -} - -impl<'a, Q: Query> Lookup<'a, Q> { - /// 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> { - let mut hash = self.hash; - - // this loop iterates through non-inline nodes. - for depth in 0.. { - let node_data = match self.db.get(&hash) { - Some(value) => value, - None => return Err(Box::new(match depth { - 0 => TrieError::InvalidStateRoot(hash), - _ => TrieError::IncompleteDatabase(hash), - })), - }; - - self.query.record(&hash, &node_data, depth); - - // this loop iterates through all inline children (usually max 1) - // without incrementing the depth. - let mut node_data = &node_data[..]; - loop { - match Node::decoded(node_data)? { - Node::Leaf(slice, value) => { - return Ok(match slice == key { - true => Some(self.query.decode(value)), - false => None, - }) - } - Node::Extension(slice, item) => { - if key.starts_with(&slice) { - node_data = item; - key = key.mid(slice.len()); - } else { - return Ok(None) - } - } - Node::Branch(children, value) => match key.is_empty() { - true => return Ok(value.map(move |val| self.query.decode(val))), - false => { - node_data = children[key.at(0) as usize]; - key = key.mid(1); - } - }, - _ => return Ok(None), - } - - // check if new node data is inline or hash. - if let Some(h) = Node::try_decode_hash(&node_data) { - hash = h; - break - } - } - } - Ok(None) - } -} diff --git a/util/patricia_trie/src/nibbleslice.rs b/util/patricia_trie/src/nibbleslice.rs deleted file mode 100644 index c2dd6611e21326842651241a73d33bf3740f9ef7..0000000000000000000000000000000000000000 --- a/util/patricia_trie/src/nibbleslice.rs +++ /dev/null @@ -1,303 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Nibble-orientated view onto byte-slice, allowing nibble-precision offsets. - -use std::cmp::*; -use std::fmt; -use elastic_array::ElasticArray36; - -/// Nibble-orientated view onto byte-slice, allowing nibble-precision offsets. -/// -/// This is an immutable struct. No operations actually change it. -/// -/// # Example -/// ```snippet -/// use patricia_trie::nibbleslice::NibbleSlice; -/// fn main() { -/// let d1 = &[0x01u8, 0x23, 0x45]; -/// let d2 = &[0x34u8, 0x50, 0x12]; -/// let d3 = &[0x00u8, 0x12]; -/// let n1 = NibbleSlice::new(d1); // 0,1,2,3,4,5 -/// let n2 = NibbleSlice::new(d2); // 3,4,5,0,1,2 -/// let n3 = NibbleSlice::new_offset(d3, 1); // 0,1,2 -/// assert!(n1 > n3); // 0,1,2,... > 0,1,2 -/// assert!(n1 < n2); // 0,... < 3,... -/// assert!(n2.mid(3) == n3); // 0,1,2 == 0,1,2 -/// assert!(n1.starts_with(&n3)); -/// assert_eq!(n1.common_prefix(&n3), 3); -/// assert_eq!(n2.mid(3).common_prefix(&n1), 3); -/// } -/// ``` -#[derive(Copy, Clone, Eq, Ord)] -pub struct NibbleSlice<'a> { - data: &'a [u8], - offset: usize, - data_encode_suffix: &'a [u8], - offset_encode_suffix: usize, -} - -/// Iterator type for a nibble slice. -pub struct NibbleSliceIterator<'a> { - p: &'a NibbleSlice<'a>, - i: usize, -} - -impl<'a> Iterator for NibbleSliceIterator<'a> { - type Item = u8; - fn next(&mut self) -> Option { - self.i += 1; - match self.i <= self.p.len() { - true => Some(self.p.at(self.i - 1)), - false => None, - } - } -} - -impl<'a, 'view> NibbleSlice<'a> where 'a: 'view { - /// Create a new nibble slice with the given byte-slice. - pub fn new(data: &'a [u8]) -> Self { NibbleSlice::new_offset(data, 0) } - - /// Create a new nibble slice with the given byte-slice with a nibble offset. - pub fn new_offset(data: &'a [u8], offset: usize) -> Self { NibbleSlice{data: data, offset: offset, data_encode_suffix: &b""[..], offset_encode_suffix: 0} } - - /// Create a composed nibble slice; one followed by the other. - pub fn new_composed(a: &'a NibbleSlice, b: &'a NibbleSlice) -> Self { NibbleSlice{data: a.data, offset: a.offset, data_encode_suffix: b.data, offset_encode_suffix: b.offset} } - - /*pub fn new_composed_bytes_offset(a: &NibbleSlice, b: &NibbleSlice) -> (Bytes, usize) { - let r: Vec::with_capacity((a.len() + b.len() + 1) / 2); - let mut i = (a.len() + b.len()) % 2; - while i < a.len() { - match i % 2 { - 0 => , - 1 => , - } - i += 1; - } - while i < a.len() + b.len() { - i += 1; - } - (r, a.len() + b.len()) - }*/ - - /// Get an iterator for the series of nibbles. - pub fn iter(&'a self) -> NibbleSliceIterator<'a> { - NibbleSliceIterator { p: self, i: 0 } - } - - /// Create a new nibble slice from the given HPE encoded data (e.g. output of `encoded()`). - pub fn from_encoded(data: &'a [u8]) -> (NibbleSlice, bool) { - (Self::new_offset(data, if data[0] & 16 == 16 {1} else {2}), data[0] & 32 == 32) - } - - /// Is this an empty slice? - pub fn is_empty(&self) -> bool { self.len() == 0 } - - /// Get the length (in nibbles, naturally) of this slice. - 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`. - pub fn at(&self, i: usize) -> u8 { - let l = self.data.len() * 2 - self.offset; - if i < l { - if (self.offset + i) & 1 == 1 { - self.data[(self.offset + i) / 2] & 15u8 - } - else { - self.data[(self.offset + i) / 2] >> 4 - } - } - else { - let i = i - l; - if (self.offset_encode_suffix + i) & 1 == 1 { - self.data_encode_suffix[(self.offset_encode_suffix + i) / 2] & 15u8 - } - else { - self.data_encode_suffix[(self.offset_encode_suffix + i) / 2] >> 4 - } - } - } - - /// Return object which represents a view on to this slice (further) offset by `i` nibbles. - pub fn mid(&'view self, i: usize) -> NibbleSlice<'a> { NibbleSlice{ data: self.data, offset: self.offset + i, data_encode_suffix: &b""[..], offset_encode_suffix: 0 } } - - /// Do we start with the same nibbles as the whole of `them`? - pub fn starts_with(&self, them: &Self) -> bool { self.common_prefix(them) == them.len() } - - /// How many of the same nibbles at the beginning do we match with `them`? - pub fn common_prefix(&self, them: &Self) -> usize { - let s = min(self.len(), them.len()); - let mut i = 0usize; - while i < s { - if self.at(i) != them.at(i) { break; } - i += 1; - } - i - } - - /// Encode while nibble slice in prefixed hex notation, noting whether it `is_leaf`. - pub fn encoded(&self, is_leaf: bool) -> ElasticArray36 { - let l = self.len(); - let mut r = ElasticArray36::new(); - let mut i = l % 2; - r.push(if i == 1 {0x10 + self.at(0)} else {0} + if is_leaf {0x20} else {0}); - while i < l { - r.push(self.at(i) * 16 + self.at(i + 1)); - i += 2; - } - r - } - - /// Encode only the leftmost `n` bytes of the nibble slice in prefixed hex notation, - /// noting whether it `is_leaf`. - pub fn encoded_leftmost(&self, n: usize, is_leaf: bool) -> ElasticArray36 { - let l = min(self.len(), n); - let mut r = ElasticArray36::new(); - let mut i = l % 2; - r.push(if i == 1 {0x10 + self.at(0)} else {0} + if is_leaf {0x20} else {0}); - while i < l { - r.push(self.at(i) * 16 + self.at(i + 1)); - i += 2; - } - r - } -} - -impl<'a> PartialEq for NibbleSlice<'a> { - fn eq(&self, them: &Self) -> bool { - self.len() == them.len() && self.starts_with(them) - } -} - -impl<'a> PartialOrd for NibbleSlice<'a> { - fn partial_cmp(&self, them: &Self) -> Option { - let s = min(self.len(), them.len()); - let mut i = 0usize; - while i < s { - match self.at(i).partial_cmp(&them.at(i)).unwrap() { - Ordering::Less => return Some(Ordering::Less), - Ordering::Greater => return Some(Ordering::Greater), - _ => i += 1, - } - } - self.len().partial_cmp(&them.len()) - } -} - -impl<'a> fmt::Debug for NibbleSlice<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for i in 0..self.len() { - match i { - 0 => write!(f, "{:01x}", self.at(i))?, - _ => write!(f, "'{:01x}", self.at(i))?, - } - } - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::NibbleSlice; - use elastic_array::ElasticArray36; - static D: &'static [u8;3] = &[0x01u8, 0x23, 0x45]; - - #[test] - fn basics() { - let n = NibbleSlice::new(D); - assert_eq!(n.len(), 6); - assert!(!n.is_empty()); - - let n = NibbleSlice::new_offset(D, 6); - assert!(n.is_empty()); - - let n = NibbleSlice::new_offset(D, 3); - assert_eq!(n.len(), 3); - for i in 0..3 { - assert_eq!(n.at(i), i as u8 + 3); - } - } - - #[test] - fn iterator() { - let n = NibbleSlice::new(D); - let mut nibbles: Vec = vec![]; - nibbles.extend(n.iter()); - assert_eq!(nibbles, (0u8..6).collect::>()) - } - - #[test] - fn mid() { - let n = NibbleSlice::new(D); - let m = n.mid(2); - for i in 0..4 { - assert_eq!(m.at(i), i as u8 + 2); - } - let m = n.mid(3); - for i in 0..3 { - assert_eq!(m.at(i), i as u8 + 3); - } - } - - #[test] - fn encoded() { - let n = NibbleSlice::new(D); - assert_eq!(n.encoded(false), ElasticArray36::from_slice(&[0x00, 0x01, 0x23, 0x45])); - assert_eq!(n.encoded(true), ElasticArray36::from_slice(&[0x20, 0x01, 0x23, 0x45])); - assert_eq!(n.mid(1).encoded(false), ElasticArray36::from_slice(&[0x11, 0x23, 0x45])); - assert_eq!(n.mid(1).encoded(true), ElasticArray36::from_slice(&[0x31, 0x23, 0x45])); - } - - #[test] - fn from_encoded() { - let n = NibbleSlice::new(D); - assert_eq!((n, false), NibbleSlice::from_encoded(&[0x00, 0x01, 0x23, 0x45])); - assert_eq!((n, true), NibbleSlice::from_encoded(&[0x20, 0x01, 0x23, 0x45])); - assert_eq!((n.mid(1), false), NibbleSlice::from_encoded(&[0x11, 0x23, 0x45])); - assert_eq!((n.mid(1), true), NibbleSlice::from_encoded(&[0x31, 0x23, 0x45])); - } - - #[test] - fn shared() { - let n = NibbleSlice::new(D); - - let other = &[0x01u8, 0x23, 0x01, 0x23, 0x45, 0x67]; - let m = NibbleSlice::new(other); - - assert_eq!(n.common_prefix(&m), 4); - assert_eq!(m.common_prefix(&n), 4); - assert_eq!(n.mid(1).common_prefix(&m.mid(1)), 3); - assert_eq!(n.mid(1).common_prefix(&m.mid(2)), 0); - assert_eq!(n.common_prefix(&m.mid(4)), 6); - assert!(!n.starts_with(&m.mid(4))); - assert!(m.mid(4).starts_with(&n)); - } - - #[test] - fn compare() { - let other = &[0x01u8, 0x23, 0x01, 0x23, 0x45]; - let n = NibbleSlice::new(D); - let m = NibbleSlice::new(other); - - assert!(n != m); - assert!(n > m); - assert!(m < n); - - assert!(n == m.mid(4)); - assert!(n >= m.mid(4)); - assert!(n <= m.mid(4)); - } -} diff --git a/util/patricia_trie/src/nibblevec.rs b/util/patricia_trie/src/nibblevec.rs deleted file mode 100644 index fbe97496ae84881846d1e79ecbc1aed83f9ca210..0000000000000000000000000000000000000000 --- a/util/patricia_trie/src/nibblevec.rs +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2015-2017 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 . - -//! An owning, nibble-oriented byte vector. -use elastic_array::ElasticArray36; -use nibbleslice::NibbleSlice; - -/// Owning, nibble-oriented byte vector. Counterpart to `NibbleSlice`. -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct NibbleVec { - inner: ElasticArray36, - len: usize, -} - -impl Default for NibbleVec { - fn default() -> Self { - NibbleVec::new() - } -} - -impl NibbleVec { - /// Make a new `NibbleVec` - pub fn new() -> Self { - NibbleVec { - inner: ElasticArray36::new(), - len: 0 - } - } - - /// Length of the `NibbleVec` - 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. - pub fn at(&self, idx: usize) -> u8 { - if idx % 2 == 0 { - self.inner[idx / 2] >> 4 - } else { - self.inner[idx / 2] & 0x0F - } - } - - /// Push a nibble onto the `NibbleVec`. Ignores the high 4 bits. - pub fn push(&mut self, nibble: u8) { - let nibble = nibble & 0x0F; - - if self.len % 2 == 0 { - self.inner.push(nibble << 4); - } else { - *self.inner.last_mut().expect("len != 0 since len % 2 != 0; inner has a last element; qed") |= nibble; - } - - self.len += 1; - } - - /// Try to pop a nibble off the `NibbleVec`. Fails if len == 0. - pub fn pop(&mut self) -> Option { - if self.is_empty() { - return None; - } - - let byte = self.inner.pop().expect("len != 0; inner has last elem; qed"); - let nibble = if self.len % 2 == 0 { - self.inner.push(byte & 0xF0); - byte & 0x0F - } else { - byte >> 4 - }; - - self.len -= 1; - Some(nibble) - } - - /// Try to treat this `NibbleVec` as a `NibbleSlice`. Works only if len is even. - pub fn as_nibbleslice(&self) -> Option { - if self.len % 2 == 0 { - Some(NibbleSlice::new(self.inner())) - } else { - None - } - } - - /// Get the underlying byte slice. - pub fn inner(&self) -> &[u8] { - &self.inner[..] - } -} - -impl<'a> From> for NibbleVec { - fn from(s: NibbleSlice<'a>) -> Self { - let mut v = NibbleVec::new(); - for i in 0..s.len() { - v.push(s.at(i)); - } - v - } -} - -#[cfg(test)] -mod tests { - use super::NibbleVec; - - #[test] - fn push_pop() { - let mut v = NibbleVec::new(); - - for i in 0..16 { - v.push(i); - assert_eq!(v.len() - 1, i as usize); - assert_eq!(v.at(i as usize), i); - } - - for i in (0..16).rev() { - assert_eq!(v.pop(), Some(i)); - assert_eq!(v.len(), i as usize); - } - } - - #[test] - fn nibbleslice_conv() { - let mut v = NibbleVec::new(); - for i in 0..10 { - v.push(i); - } - - let v2: NibbleVec = v.as_nibbleslice().unwrap().into(); - assert_eq!(v, v2); - } -} diff --git a/util/patricia_trie/src/node.rs b/util/patricia_trie/src/node.rs deleted file mode 100644 index 0b99acded34b93368d29b04974a023b2151b24da..0000000000000000000000000000000000000000 --- a/util/patricia_trie/src/node.rs +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2015-2017 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 . - -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. -pub type NodeKey = ElasticArray36; - -/// Type of node in the trie and essential information thereof. -#[derive(Eq, PartialEq, Debug, Clone)] -pub enum Node<'a> { - /// Null trie node; could be an empty root or an empty branch entry. - Empty, - /// Leaf node; has key slice and value. Value may not be empty. - Leaf(NibbleSlice<'a>, &'a [u8]), - /// 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 - } - } -} - -/// An owning node type. Useful for trie iterators. -#[derive(Debug, PartialEq, Eq)] -pub enum OwnedNode { - /// Empty trie node. - Empty, - /// Leaf node: partial key and value. - Leaf(NibbleVec, DBValue), - /// Extension node: partial key and child node. - Extension(NibbleVec, DBValue), - /// Branch node: 16 children and an optional value. - Branch([NodeKey; 16], Option), -} - -impl<'a> From> for OwnedNode { - fn from(node: Node<'a>) -> Self { - match node { - Node::Empty => OwnedNode::Empty, - Node::Leaf(k, v) => OwnedNode::Leaf(k.into(), DBValue::from_slice(v)), - Node::Extension(k, child) => OwnedNode::Extension(k.into(), DBValue::from_slice(child)), - Node::Branch(c, val) => { - let children = [ - NodeKey::from_slice(c[0]), NodeKey::from_slice(c[1]), NodeKey::from_slice(c[2]), NodeKey::from_slice(c[3]), - NodeKey::from_slice(c[4]), NodeKey::from_slice(c[5]), NodeKey::from_slice(c[6]), NodeKey::from_slice(c[7]), - NodeKey::from_slice(c[8]), NodeKey::from_slice(c[9]), NodeKey::from_slice(c[10]), NodeKey::from_slice(c[11]), - NodeKey::from_slice(c[12]), NodeKey::from_slice(c[13]), NodeKey::from_slice(c[14]), NodeKey::from_slice(c[15]), - ]; - - OwnedNode::Branch(children, val.map(DBValue::from_slice)) - } - } - } -} diff --git a/util/patricia_trie/src/recorder.rs b/util/patricia_trie/src/recorder.rs deleted file mode 100644 index 35a515b704d52951a3636ad2c02f4a0e901230d9..0000000000000000000000000000000000000000 --- a/util/patricia_trie/src/recorder.rs +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2015-2017 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 . - -//! 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 { - /// The depth of this node. - pub depth: u32, - - /// The raw data of the node. - pub data: Bytes, - - /// The hash of the data. - pub hash: H256, -} - -/// Records trie nodes as they pass it. -#[derive(Debug)] -pub struct Recorder { - nodes: Vec, - min_depth: u32, -} - -impl Default for Recorder { - fn default() -> Self { - Recorder::new() - } -} - -impl Recorder { - /// Create a new `Recorder` which records all given nodes. - #[inline] - pub fn new() -> Self { - Recorder::with_depth(0) - } - - /// Create a `Recorder` which only records nodes beyond a given depth. - pub fn with_depth(depth: u32) -> Self { - Recorder { - nodes: Vec::new(), - min_depth: depth, - } - } - - /// 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); - - if depth >= self.min_depth { - self.nodes.push(Record { - depth: depth, - data: data.into(), - hash: *hash, - }) - } - } - - /// Drain all visited records. - pub fn drain(&mut self) -> Vec { - ::std::mem::replace(&mut self.nodes, Vec::new()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ethereum_types::H256; - - #[test] - fn basic_recorder() { - let mut basic = Recorder::new(); - - let node1 = vec![1, 2, 3, 4]; - let node2 = vec![4, 5, 6, 7, 8, 9, 10]; - - let (hash1, hash2) = (keccak(&node1), keccak(&node2)); - basic.record(&hash1, &node1, 0); - basic.record(&hash2, &node2, 456); - - let record1 = Record { - data: node1, - hash: hash1, - depth: 0, - }; - - let record2 = Record { - data: node2, - hash: hash2, - depth: 456 - }; - - assert_eq!(basic.drain(), vec![record1, record2]); - } - - #[test] - fn basic_recorder_min_depth() { - let mut basic = Recorder::with_depth(400); - - let node1 = vec![1, 2, 3, 4]; - let node2 = vec![4, 5, 6, 7, 8, 9, 10]; - - let hash1 = keccak(&node1); - let hash2 = keccak(&node2); - basic.record(&hash1, &node1, 0); - basic.record(&hash2, &node2, 456); - - let records = basic.drain(); - - assert_eq!(records.len(), 1); - - assert_eq!(records[0].clone(), Record { - data: node2, - hash: hash2, - depth: 456, - }); - } - - #[test] - fn trie_record() { - use super::super::{TrieDB, TrieDBMut, Trie, TrieMut}; - use memorydb::MemoryDB; - - let mut db = MemoryDB::new(); - - let mut root = H256::default(); - - { - let mut x = TrieDBMut::new(&mut db, &mut root); - - x.insert(b"dog", b"cat").unwrap(); - x.insert(b"lunch", b"time").unwrap(); - x.insert(b"notdog", b"notcat").unwrap(); - x.insert(b"hotdog", b"hotcat").unwrap(); - x.insert(b"letter", b"confusion").unwrap(); - x.insert(b"insert", b"remove").unwrap(); - x.insert(b"pirate", b"aargh!").unwrap(); - x.insert(b"yo ho ho", b"and a bottle of rum").unwrap(); - } - - let trie = TrieDB::new(&db, &root).unwrap(); - let mut recorder = Recorder::new(); - - trie.get_with(b"pirate", &mut recorder).unwrap().unwrap(); - - let nodes: Vec<_> = recorder.drain().into_iter().map(|r| r.data).collect(); - assert_eq!(nodes, vec![ - vec![ - 248, 81, 128, 128, 128, 128, 128, 128, 160, 50, 19, 71, 57, 213, 63, 125, 149, - 92, 119, 88, 96, 80, 126, 59, 11, 160, 142, 98, 229, 237, 200, 231, 224, 79, 118, - 215, 93, 144, 246, 179, 176, 160, 118, 211, 171, 199, 172, 136, 136, 240, 221, 59, - 110, 82, 86, 54, 23, 95, 48, 108, 71, 125, 59, 51, 253, 210, 18, 116, 79, 0, 236, - 102, 142, 48, 128, 128, 128, 128, 128, 128, 128, 128, 128 - ], - vec![ - 248, 60, 206, 134, 32, 105, 114, 97, 116, 101, 134, 97, 97, 114, 103, 104, 33, - 128, 128, 128, 128, 128, 128, 128, 128, 221, 136, 32, 111, 32, 104, 111, 32, 104, - 111, 147, 97, 110, 100, 32, 97, 32, 98, 111, 116, 116, 108, 101, 32, 111, 102, - 32, 114, 117, 109, 128, 128, 128, 128, 128, 128, 128 - ] - ]); - - trie.get_with(b"letter", &mut recorder).unwrap().unwrap(); - - let nodes: Vec<_> = recorder.drain().into_iter().map(|r| r.data).collect(); - assert_eq!(nodes, vec![ - vec![ - 248, 81, 128, 128, 128, 128, 128, 128, 160, 50, 19, 71, 57, 213, 63, 125, 149, - 92, 119, 88, 96, 80, 126, 59, 11, 160, 142, 98, 229, 237, 200, 231, 224, 79, 118, - 215, 93, 144, 246, 179, 176, 160, 118, 211, 171, 199, 172, 136, 136, 240, 221, - 59, 110, 82, 86, 54, 23, 95, 48, 108, 71, 125, 59, 51, 253, 210, 18, 116, 79, - 0, 236, 102, 142, 48, 128, 128, 128, 128, 128, 128, 128, 128, 128 - ], - vec![ - 248, 99, 128, 128, 128, 128, 200, 131, 32, 111, 103, 131, 99, 97, 116, 128, 128, - 128, 206, 134, 32, 111, 116, 100, 111, 103, 134, 104, 111, 116, 99, 97, 116, 206, - 134, 32, 110, 115, 101, 114, 116, 134, 114, 101, 109, 111, 118, 101, 128, 128, - 160, 202, 250, 252, 153, 229, 63, 255, 13, 100, 197, 80, 120, 190, 186, 92, 5, - 255, 135, 245, 205, 180, 213, 161, 8, 47, 107, 13, 105, 218, 1, 9, 5, 128, - 206, 134, 32, 111, 116, 100, 111, 103, 134, 110, 111, 116, 99, 97, 116, 128, 128 - ], - vec![ - 235, 128, 128, 128, 128, 128, 128, 208, 133, 53, 116, 116, 101, 114, 137, 99, - 111, 110, 102, 117, 115, 105, 111, 110, 202, 132, 53, 110, 99, 104, 132, 116, - 105, 109, 101, 128, 128, 128, 128, 128, 128, 128, 128, 128 - ] - ]); - } -} diff --git a/util/patricia_trie/src/sectriedb.rs b/util/patricia_trie/src/sectriedb.rs deleted file mode 100644 index a9176d022ab357fdd496ebacf4e84e29e2689db6..0000000000000000000000000000000000000000 --- a/util/patricia_trie/src/sectriedb.rs +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2015-2017 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 . - -use ethereum_types::H256; -use keccak::keccak; -use hashdb::HashDB; -use super::triedb::TrieDB; -use super::{Trie, TrieItem, TrieIterator, Query}; - -/// 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> -} - -impl<'db> SecTrieDB<'db> { - /// 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 { - Ok(SecTrieDB { raw: TrieDB::new(db, root)? }) - } - - /// Get a reference to the underlying raw `TrieDB` struct. - 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> { - &mut self.raw - } -} - -impl<'db> Trie for SecTrieDB<'db> { - fn iter<'a>(&'a self) -> super::Result + 'a>> { - TrieDB::iter(&self.raw) - } - - fn root(&self) -> &H256 { self.raw.root() } - - fn contains(&self, key: &[u8]) -> super::Result { - self.raw.contains(&keccak(key)) - } - - fn get_with<'a, 'key, Q: Query>(&'a self, key: &'key [u8], query: Q) -> super::Result> - where 'a: 'key - { - self.raw.get_with(&keccak(key), query) - } -} - -#[test] -fn trie_to_sectrie() { - use memorydb::MemoryDB; - use hashdb::DBValue; - use super::triedbmut::TrieDBMut; - use super::TrieMut; - - 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(); - } - let t = SecTrieDB::new(&memdb, &root).unwrap(); - assert_eq!(t.get(&[0x01u8, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x01u8, 0x23])); -} diff --git a/util/patricia_trie/src/sectriedbmut.rs b/util/patricia_trie/src/sectriedbmut.rs deleted file mode 100644 index b0436b271f6490d0939295d2c15510bd507dfcda..0000000000000000000000000000000000000000 --- a/util/patricia_trie/src/sectriedbmut.rs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2015-2017 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 . - -use ethereum_types::H256; -use keccak::keccak; -use hashdb::{HashDB, DBValue}; -use super::triedbmut::TrieDBMut; -use super::TrieMut; - -/// 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> -} - -impl<'db> SecTrieDBMut<'db> { - /// 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 { - 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 { - Ok(SecTrieDBMut { raw: TrieDBMut::from_existing(db, root)? }) - } - - /// Get the backing database. - pub fn db(&self) -> &HashDB { self.raw.db() } - - /// Get the backing database. - pub fn db_mut(&mut self) -> &mut HashDB { self.raw.db_mut() } -} - -impl<'db> TrieMut for SecTrieDBMut<'db> { - fn root(&mut self) -> &H256 { - self.raw.root() - } - - fn is_empty(&self) -> bool { - self.raw.is_empty() - } - - fn contains(&self, key: &[u8]) -> super::Result { - self.raw.contains(&keccak(key)) - } - - fn get<'a, 'key>(&'a self, key: &'key [u8]) -> super::Result> - where 'a: 'key - { - self.raw.get(&keccak(key)) - } - - fn insert(&mut self, key: &[u8], value: &[u8]) -> super::Result> { - self.raw.insert(&keccak(key), value) - } - - fn remove(&mut self, key: &[u8]) -> super::Result> { - self.raw.remove(&keccak(key)) - } -} - -#[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(); - } - 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 deleted file mode 100644 index c18e4fce96713274eef25248423fabef179d79ee..0000000000000000000000000000000000000000 --- a/util/patricia_trie/src/triedb.rs +++ /dev/null @@ -1,620 +0,0 @@ -// Copyright 2015-2017 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 . - -use std::fmt; -use hashdb::*; -use nibbleslice::NibbleSlice; -use super::node::{Node, OwnedNode}; -use super::lookup::Lookup; -use super::{Trie, TrieItem, TrieError, TrieIterator, Query}; -use ethereum_types::H256; -use bytes::Bytes; - -/// A `Trie` implementation using a generic `HashDB` backing database. -/// -/// 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. -/// -/// # Example -/// ``` -/// extern crate patricia_trie as trie; -/// extern crate hashdb; -/// extern crate memorydb; -/// extern crate ethereum_types; -/// -/// use trie::*; -/// use hashdb::*; -/// use memorydb::*; -/// use ethereum_types::H256; -/// -/// fn main() { -/// 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(); -/// assert!(t.contains(b"foo").unwrap()); -/// assert_eq!(t.get(b"foo").unwrap().unwrap(), DBValue::from_slice(b"bar")); -/// } -/// ``` -pub struct TrieDB<'db> { - db: &'db HashDB, - root: &'db H256, - /// The number of hashes performed so far in operations on this trie. - hash_count: usize, -} - -impl<'db> TrieDB<'db> { - /// 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 { - if !db.contains(root) { - Err(Box::new(TrieError::InvalidStateRoot(*root))) - } else { - Ok(TrieDB { - db: db, - root: root, - hash_count: 0 - }) - } - } - - /// Get the backing database. - pub fn db(&'db self) -> &'db HashDB { - self.db - } - - /// Get the data of the root node. - fn root_data(&self) -> super::Result { - self.db - .get(self.root) - .ok_or_else(|| Box::new(TrieError::InvalidStateRoot(*self.root))) - } - - /// 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) { - 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 } - - fn get_with<'a, 'key, Q: Query>(&'a self, key: &'key [u8], query: Q) -> super::Result> - where 'a: 'key - { - Lookup { - db: self.db, - query: query, - hash: self.root.clone(), - }.look_up(NibbleSlice::new(key)) - } -} - -// This is for pretty debug output only -struct TrieAwareDebugNode<'db, 'a> { - trie: &'db TrieDB<'db>, - key: &'a[u8] -} - -impl<'db, 'a> fmt::Debug for TrieAwareDebugNode<'db, 'a> { - 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) { - Ok(Node::Leaf(slice, value)) => f.debug_struct("Node::Leaf") - .field("slice", &slice) - .field("value", &value) - .finish(), - Ok(Node::Extension(ref slice, ref item)) => f.debug_struct("Node::Extension") - .field("slice", &slice) - .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(); - f.debug_struct("Node::Branch") - .field("nodes", &nodes) - .field("value", &value) - .finish() - }, - Ok(Node::Empty) => f.debug_struct("Node::Empty").finish(), - - Err(e) => f.debug_struct("BROKEN_NODE") - .field("key", &self.key) - .field("error", &format!("ERROR decoding node branch Rlp: {}", e)) - .finish() - } - } else { - f.debug_struct("BROKEN_NODE") - .field("key", &self.key) - .field("error", &"Not found") - .finish() - } - } -} - - -impl<'db> fmt::Debug for TrieDB<'db> { - 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") - .field("hash_count", &self.hash_count) - .field("root", &TrieAwareDebugNode { - trie: self, - key: &root_rlp - }) - .finish() - } -} - -#[derive(Clone, Eq, PartialEq)] -enum Status { - Entering, - At, - AtChild(usize), - Exiting, -} - -#[derive(Eq, PartialEq)] -struct Crumb { - node: OwnedNode, - status: Status, -} - -impl Crumb { - /// Move on to next status in the node's sequence. - fn increment(&mut self) { - self.status = match (&self.status, &self.node) { - (_, &OwnedNode::Empty) => Status::Exiting, - (&Status::Entering, _) => Status::At, - (&Status::At, &OwnedNode::Branch(_, _)) => Status::AtChild(0), - (&Status::AtChild(x), &OwnedNode::Branch(_, _)) if x < 15 => Status::AtChild(x + 1), - _ => Status::Exiting, - } - } -} - -/// Iterator for going through all values in the trie. -pub struct TrieDBIterator<'a> { - db: &'a TrieDB<'a>, - trail: Vec, - key_nibbles: Bytes, -} - -impl<'a> TrieDBIterator<'a> { - /// Create a new iterator. - pub fn new(db: &'a TrieDB) -> super::Result> { - let mut r = TrieDBIterator { - db: db, - trail: vec![], - key_nibbles: Vec::new(), - }; - - 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<()> { - loop { - let (data, mid) = { - let node = TrieDB::decode_node(&node_data); - match node { - Node::Leaf(slice, _) => { - if slice == key { - self.trail.push(Crumb { - status: Status::At, - node: node.clone().into(), - }); - } else { - self.trail.push(Crumb { - status: Status::Exiting, - node: node.clone().into(), - }); - } - - self.key_nibbles.extend(slice.iter()); - return Ok(()) - }, - Node::Extension(ref slice, ref item) => { - if key.starts_with(slice) { - self.trail.push(Crumb { - status: Status::At, - node: node.clone().into(), - }); - self.key_nibbles.extend(slice.iter()); - let data = self.db.get_raw_or_lookup(&*item)?; - (data, slice.len()) - } else { - self.descend(&node_data)?; - return Ok(()) - } - }, - Node::Branch(ref nodes, _) => match key.is_empty() { - true => { - self.trail.push(Crumb { - status: Status::At, - node: node.clone().into(), - }); - return Ok(()) - }, - false => { - let i = key.at(0); - self.trail.push(Crumb { - status: Status::AtChild(i as usize), - node: node.clone().into(), - }); - self.key_nibbles.push(i); - let child = self.db.get_raw_or_lookup(&*nodes[i as usize])?; - (child, 1) - } - }, - _ => return Ok(()), - } - }; - - node_data = data; - key = key.mid(mid); - } - } - - /// 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)) - } - - /// Descend into a payload. - fn descend_into_node(&mut self, node: OwnedNode) { - self.trail.push(Crumb { - status: Status::Entering, - node: 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))); - }, - _ => {} - } - } - - /// The present key. - fn key(&self) -> Bytes { - // collapse the key_nibbles down to bytes. - let nibbles = &self.key_nibbles; - let mut i = 1; - let mut result = Bytes::with_capacity(nibbles.len() / 2); - let len = nibbles.len(); - while i < len { - result.push(nibbles[i - 1] * 16 + nibbles[i]); - i += 2; - } - result - } -} - -impl<'a> TrieIterator for TrieDBIterator<'a> { - /// Position the iterator on the first element with key >= `key` - fn seek(&mut self, key: &[u8]) -> super::Result<()> { - self.trail.clear(); - self.key_nibbles.clear(); - let root_rlp = self.db.root_data()?; - self.seek(root_rlp, NibbleSlice::new(key)) - } -} - -impl<'a> Iterator for TrieDBIterator<'a> { - type Item = TrieItem<'a>; - - fn next(&mut self) -> Option { - enum IterStep { - Continue, - PopTrail, - Descend(super::Result), - } - - loop { - let iter_step = { - self.trail.last_mut()?.increment(); - let b = self.trail.last().expect("trail.last_mut().is_some(); qed"); - - match (b.status.clone(), &b.node) { - (Status::Exiting, n) => { - match *n { - OwnedNode::Leaf(ref n, _) | OwnedNode::Extension(ref n, _) => { - let l = self.key_nibbles.len(); - self.key_nibbles.truncate(l - n.len()); - }, - OwnedNode::Branch(_, _) => { self.key_nibbles.pop(); }, - _ => {} - } - IterStep::PopTrail - }, - (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::Branch(_, _)) => IterStep::Continue, - (Status::AtChild(i), &OwnedNode::Branch(ref children, _)) if children[i].len() > 0 => { - match i { - 0 => self.key_nibbles.push(0), - 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])) - }, - (Status::AtChild(i), &OwnedNode::Branch(_, _)) => { - if i == 0 { - self.key_nibbles.push(0); - } - IterStep::Continue - }, - _ => panic!() // Should never see Entering or AtChild without a Branch here. - } - }; - - match iter_step { - IterStep::PopTrail => { - self.trail.pop(); - }, - IterStep::Descend(Ok(d)) => { - self.descend_into_node(TrieDB::decode_node(&d).into()) - }, - IterStep::Descend(Err(e)) => { - return Some(Err(e)) - } - IterStep::Continue => {}, - } - } - } -} - -#[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(); - } - } - - 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 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(), 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::*; - - 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()), 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") ]; - - 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), -"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 - } - } -}"); -} - -#[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(); - - // 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); -} diff --git a/util/patricia_trie/src/triedbmut.rs b/util/patricia_trie/src/triedbmut.rs deleted file mode 100644 index b8d919deea291a3f9e32ab9452b446f41dea233d..0000000000000000000000000000000000000000 --- a/util/patricia_trie/src/triedbmut.rs +++ /dev/null @@ -1,1310 +0,0 @@ -// Copyright 2015-2017 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 . - -//! In-memory trie representation. - -use super::{TrieError, TrieMut}; -use super::lookup::Lookup; -use super::node::Node as RlpNode; -use super::node::NodeKey; - -use hashdb::HashDB; -use bytes::ToPretty; -use nibbleslice::NibbleSlice; -use rlp::{Rlp, RlpStream}; -use hashdb::DBValue; - -use std::collections::{HashSet, VecDeque}; -use std::mem; -use std::ops::Index; -use ethereum_types::H256; -use elastic_array::ElasticArray1024; -use keccak::{KECCAK_NULL_RLP}; - -// For lookups into the Node storage buffer. -// This is deliberately non-copyable. -#[derive(Debug)] -struct StorageHandle(usize); - -// Handles to nodes in the trie. -#[derive(Debug)] -enum NodeHandle { - /// Loaded into memory. - InMemory(StorageHandle), - /// Either a hash or an inline node - Hash(H256), -} - -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]> { - Box::new([ - None, None, None, None, None, None, None, None, - None, None, None, None, None, None, None, None, - ]) -} - -/// Node types in the Trie. -#[derive(Debug)] -enum Node { - /// Empty node. - Empty, - /// A leaf node contains the end of a key and a value. - /// This key is encoded from a `NibbleSlice`, meaning it contains - /// a flag indicating it is a leaf. - Leaf(NodeKey, DBValue), - /// An extension contains a shared portion of a key and a child 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), - /// A branch has up to 16 children and an optional value. - Branch(Box<[Option; 16]>, Option) -} - -impl Node { - // 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) - .map(NodeHandle::Hash) - .unwrap_or_else(|| { - let child = Node::from_rlp(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)) - } - 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)) - } else { - None - } - }; - - let children = Box::new([ - child(0), child(1), child(2), child(3), - child(4), child(5), child(6), child(7), - child(8), child(9), child(10), child(11), - child(12), child(13), child(14), child(15), - ]); - - Node::Branch(children, val.map(DBValue::from_slice)) - } - } - } - - // encode a node to RLP - // TODO: parallelize - fn into_rlp(self, mut child_cb: F) -> ElasticArray1024 - where F: FnMut(NodeHandle, &mut RlpStream) - { - 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::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() - } - } - } -} - -// post-inspect action. -enum Action { - // Replace a node with a new one. - Replace(Node), - // Restore the original node. This trusts that the node is actually the original. - Restore(Node), - // if it is a new node, just clears the storage. - Delete, -} - -// post-insert action. Same as action without delete -enum InsertAction { - // Replace a node with a new one. - Replace(Node), - // Restore the original node. - Restore(Node), -} - -impl InsertAction { - fn into_action(self) -> Action { - match self { - InsertAction::Replace(n) => Action::Replace(n), - InsertAction::Restore(n) => Action::Restore(n), - } - } - - // unwrap the node, disregarding replace or restore state. - fn unwrap_node(self) -> Node { - match self { - InsertAction::Replace(n) | InsertAction::Restore(n) => n, - } - } -} - -// What kind of node is stored here. -enum Stored { - // A new node. - New(Node), - // A cached node, loaded from the DB. - Cached(Node, H256), -} - -/// Compact and cache-friendly storage for Trie nodes. -struct NodeStorage { - nodes: Vec, - free_indices: VecDeque, -} - -impl NodeStorage { - /// Create a new storage. - fn empty() -> Self { - NodeStorage { - nodes: Vec::new(), - free_indices: VecDeque::new(), - } - } - - /// Allocate a new node in the storage. - fn alloc(&mut self, stored: Stored) -> StorageHandle { - if let Some(idx) = self.free_indices.pop_front() { - self.nodes[idx] = stored; - StorageHandle(idx) - } else { - self.nodes.push(stored); - StorageHandle(self.nodes.len() - 1) - } - } - - /// Remove a node from the storage, consuming the handle and returning the node. - fn destroy(&mut self, handle: StorageHandle) -> Stored { - let idx = handle.0; - - self.free_indices.push_back(idx); - mem::replace(&mut self.nodes[idx], Stored::New(Node::Empty)) - } -} - -impl<'a> Index<&'a StorageHandle> for NodeStorage { - type Output = Node; - - fn index(&self, handle: &'a StorageHandle) -> &Node { - match self.nodes[handle.0] { - Stored::New(ref node) => node, - Stored::Cached(ref node, _) => node, - } - } -} - -/// A `Trie` implementation using a generic `HashDB` backing database. -/// -/// Use it as a `TrieMut` trait object. You can use `db()` to get the backing database object. -/// Note that changes are not committed to the database until `commit` is called. -/// Querying the root or dropping the trie will commit automatically. -/// -/// # Example -/// ``` -/// extern crate patricia_trie as trie; -/// extern crate keccak_hash; -/// extern crate hashdb; -/// extern crate memorydb; -/// extern crate ethereum_types; -/// -/// use keccak_hash::KECCAK_NULL_RLP; -/// use trie::*; -/// use hashdb::*; -/// use memorydb::*; -/// use ethereum_types::H256; -/// -/// fn main() { -/// let mut memdb = MemoryDB::new(); -/// let mut root = H256::new(); -/// let mut t = TrieDBMut::new(&mut memdb, &mut root); -/// assert!(t.is_empty()); -/// assert_eq!(*t.root(), KECCAK_NULL_RLP); -/// t.insert(b"foo", b"bar").unwrap(); -/// assert!(t.contains(b"foo").unwrap()); -/// assert_eq!(t.get(b"foo").unwrap().unwrap(), DBValue::from_slice(b"bar")); -/// t.remove(b"foo").unwrap(); -/// 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, - /// The number of hash operations this trie has performed. - /// Note that none are performed until changes are committed. - hash_count: usize, -} - -impl<'a> TrieDBMut<'a> { - /// 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); - - TrieDBMut { - storage: NodeStorage::empty(), - db: db, - root: root, - root_handle: root_handle, - death_row: HashSet::new(), - hash_count: 0, - } - } - - /// 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 { - if !db.contains(root) { - return Err(Box::new(TrieError::InvalidStateRoot(*root))); - } - - let root_handle = NodeHandle::Hash(*root); - Ok(TrieDBMut { - storage: NodeStorage::empty(), - db: db, - root: root, - root_handle: root_handle, - death_row: HashSet::new(), - hash_count: 0, - }) - } - /// Get the backing database. - pub fn db(&self) -> &HashDB { - self.db - } - - /// Get the backing database mutably. - 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); - 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 { - Ok(match stored { - Stored::New(node) => match inspector(self, node)? { - Action::Restore(node) => Some((Stored::New(node), false)), - Action::Replace(node) => Some((Stored::New(node), true)), - Action::Delete => None, - }, - Stored::Cached(node, hash) => match inspector(self, node)? { - Action::Restore(node) => Some((Stored::Cached(node, hash), false)), - Action::Replace(node) => { - self.death_row.insert(hash); - Some((Stored::New(node), true)) - } - Action::Delete => { - self.death_row.insert(hash); - None - } - }, - }) - } - - // walk the trie, attempting to find the key's node. - fn lookup<'x, 'key>(&'x self, mut partial: NibbleSlice<'key>, handle: &NodeHandle) -> super::Result> - where 'x: 'key - { - let mut handle = handle; - loop { - let (mid, child) = match *handle { - NodeHandle::Hash(ref hash) => return Lookup { - db: &*self.db, - query: DBValue::from_slice, - hash: hash.clone(), - }.look_up(partial), - NodeHandle::InMemory(ref handle) => match self.storage[handle] { - Node::Empty => return Ok(None), - Node::Leaf(ref key, ref value) => { - if NibbleSlice::from_encoded(key).0 == partial { - return Ok(Some(DBValue::from_slice(value))); - } else { - return Ok(None); - } - } - Node::Extension(ref slice, ref child) => { - let slice = NibbleSlice::from_encoded(slice).0; - if partial.starts_with(&slice) { - (slice.len(), child) - } else { - return Ok(None); - } - } - Node::Branch(ref children, ref value) => { - if partial.is_empty() { - return Ok(value.as_ref().map(|v| DBValue::from_slice(v))); - } else { - let idx = partial.at(0); - match children[idx as usize].as_ref() { - Some(child) => (1, child), - None => return Ok(None), - } - } - } - } - }; - - partial = partial.mid(mid); - handle = child; - } - } - - /// 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)> - { - let h = match handle { - NodeHandle::InMemory(h) => h, - NodeHandle::Hash(h) => self.cache(h)?, - }; - let stored = self.storage.destroy(h); - let (new_stored, changed) = self.inspect(stored, move |trie, stored| { - trie.insert_inspector(stored, partial, value, old_val).map(|a| a.into_action()) - })?.expect("Insertion never deletes."); - - Ok((self.storage.alloc(new_stored), changed)) - } - - /// the insertion inspector. - fn insert_inspector(&mut self, node: Node, partial: NibbleSlice, value: DBValue, old_val: &mut Option) - -> super::Result - { - trace!(target: "trie", "augmented (partial: {:?}, value: {:?})", partial, value.pretty()); - - Ok(match node { - Node::Empty => { - trace!(target: "trie", "empty: COMPOSE"); - InsertAction::Replace(Node::Leaf(partial.encoded(true), value)) - } - Node::Branch(mut children, stored_value) => { - trace!(target: "trie", "branch: ROUTE,AUGMENT"); - - if partial.is_empty() { - let unchanged = stored_value.as_ref() == Some(&value); - let branch = Node::Branch(children, Some(value)); - *old_val = stored_value; - - match unchanged { - true => InsertAction::Restore(branch), - false => InsertAction::Replace(branch), - } - } else { - let idx = partial.at(0) as usize; - let partial = partial.mid(1); - if let Some(child) = children[idx].take() { - // original had something there. recurse down into it. - let (new_child, changed) = self.insert_at(child, partial, value, old_val)?; - children[idx] = Some(new_child.into()); - if !changed { - // the new node we composed didn't change. that means our branch is untouched too. - return Ok(InsertAction::Restore(Node::Branch(children, stored_value))); - } - } else { - // original had nothing there. compose a leaf. - let leaf = self.storage.alloc(Stored::New(Node::Leaf(partial.encoded(true), value))); - children[idx] = Some(leaf.into()); - } - - InsertAction::Replace(Node::Branch(children, stored_value)) - } - } - Node::Leaf(encoded, stored_value) => { - let existing_key = NibbleSlice::from_encoded(&encoded).0; - let cp = partial.common_prefix(&existing_key); - if cp == existing_key.len() && cp == partial.len() { - trace!(target: "trie", "equivalent-leaf: REPLACE"); - // equivalent leaf. - let unchanged = stored_value == value; - *old_val = Some(stored_value); - - match unchanged { - // unchanged. restore - true => InsertAction::Restore(Node::Leaf(encoded.clone(), value)), - false => InsertAction::Replace(Node::Leaf(encoded.clone(), value)), - } - } else if cp == 0 { - trace!(target: "trie", "no-common-prefix, not-both-empty (exist={:?}; new={:?}): TRANSMUTE,AUGMENT", existing_key.len(), partial.len()); - - // one of us isn't empty: transmute to branch here - let mut children = empty_children(); - let branch = if existing_key.is_empty() { - // always replace since branch isn't leaf. - Node::Branch(children, Some(stored_value)) - } else { - let idx = existing_key.at(0) as usize; - let new_leaf = Node::Leaf(existing_key.mid(1).encoded(true), stored_value); - children[idx] = Some(self.storage.alloc(Stored::New(new_leaf)).into()); - - Node::Branch(children, None) - }; - - // always replace because whatever we get out here is not the branch we started with. - let branch_action = self.insert_inspector(branch, partial, value, old_val)?.unwrap_node(); - InsertAction::Replace(branch_action) - } else if cp == existing_key.len() { - trace!(target: "trie", "complete-prefix (cp={:?}): AUGMENT-AT-END", cp); - - // fully-shared prefix for an extension. - // make a stub branch and an extension. - let branch = Node::Branch(empty_children(), Some(stored_value)); - // augment the new branch. - let branch = self.insert_inspector(branch, partial.mid(cp), value, old_val)?.unwrap_node(); - - // always replace since we took a leaf and made an extension. - let branch_handle = self.storage.alloc(Stored::New(branch)).into(); - InsertAction::Replace(Node::Extension(existing_key.encoded(false), branch_handle)) - } else { - trace!(target: "trie", "partially-shared-prefix (exist={:?}; new={:?}; cp={:?}): AUGMENT-AT-END", existing_key.len(), partial.len(), cp); - - // partially-shared prefix for an extension. - // start by making a leaf. - let low = Node::Leaf(existing_key.mid(cp).encoded(true), stored_value); - - // augment it. this will result in the Leaf -> cp == 0 routine, - // which creates a branch. - let augmented_low = self.insert_inspector(low, partial.mid(cp), value, old_val)?.unwrap_node(); - - // make an extension using it. this is a replacement. - InsertAction::Replace(Node::Extension( - existing_key.encoded_leftmost(cp, false), - self.storage.alloc(Stored::New(augmented_low)).into() - )) - } - } - Node::Extension(encoded, child_branch) => { - let existing_key = NibbleSlice::from_encoded(&encoded).0; - let cp = partial.common_prefix(&existing_key); - if cp == 0 { - trace!(target: "trie", "no-common-prefix, not-both-empty (exist={:?}; new={:?}): TRANSMUTE,AUGMENT", existing_key.len(), partial.len()); - - // partial isn't empty: make a branch here - // extensions may not have empty partial keys. - assert!(!existing_key.is_empty()); - let idx = existing_key.at(0) as usize; - - let mut children = empty_children(); - children[idx] = if existing_key.len() == 1 { - // direct extension, just replace. - Some(child_branch) - } else { - // more work required after branching. - let ext = Node::Extension(existing_key.mid(1).encoded(false), child_branch); - Some(self.storage.alloc(Stored::New(ext)).into()) - }; - - // continue inserting. - let branch_action = self.insert_inspector(Node::Branch(children, None), partial, value, old_val)?.unwrap_node(); - InsertAction::Replace(branch_action) - } else if cp == existing_key.len() { - trace!(target: "trie", "complete-prefix (cp={:?}): AUGMENT-AT-END", cp); - - // fully-shared prefix. - - // insert into the child node. - let (new_child, changed) = self.insert_at(child_branch, partial.mid(cp), value, old_val)?; - let new_ext = Node::Extension(existing_key.encoded(false), new_child.into()); - - // if the child branch wasn't changed, meaning this extension remains the same. - match changed { - true => InsertAction::Replace(new_ext), - false => InsertAction::Restore(new_ext), - } - } else { - trace!(target: "trie", "partially-shared-prefix (exist={:?}; new={:?}; cp={:?}): AUGMENT-AT-END", existing_key.len(), partial.len(), cp); - - // partially-shared. - let low = Node::Extension(existing_key.mid(cp).encoded(false), child_branch); - // augment the extension. this will take the cp == 0 path, creating a branch. - let augmented_low = self.insert_inspector(low, partial.mid(cp), value, old_val)?.unwrap_node(); - - // always replace, since this extension is not the one we started with. - // this is known because the partial key is only the common prefix. - InsertAction::Replace(Node::Extension( - existing_key.encoded_leftmost(cp, false), - self.storage.alloc(Stored::New(augmented_low)).into() - )) - } - } - }) - } - - /// Remove a node from the trie based on key. - fn remove_at(&mut self, handle: NodeHandle, partial: NibbleSlice, old_val: &mut Option) - -> super::Result> - { - let stored = match handle { - NodeHandle::InMemory(h) => self.storage.destroy(h), - NodeHandle::Hash(h) => { - let handle = self.cache(h)?; - self.storage.destroy(handle) - } - }; - - let opt = self.inspect(stored, move |trie, node| trie.remove_inspector(node, partial, old_val))?; - - Ok(opt.map(|(new, changed)| (self.storage.alloc(new), changed))) - } - - /// the removal inspector - fn remove_inspector(&mut self, node: Node, partial: NibbleSlice, old_val: &mut Option) -> super::Result { - Ok(match (node, partial.is_empty()) { - (Node::Empty, _) => Action::Delete, - (Node::Branch(c, None), true) => Action::Restore(Node::Branch(c, None)), - (Node::Branch(children, Some(val)), true) => { - *old_val = Some(val); - // always replace since we took the value out. - Action::Replace(self.fix(Node::Branch(children, None))?) - } - (Node::Branch(mut children, value), false) => { - let idx = partial.at(0) as usize; - if let Some(child) = children[idx].take() { - trace!(target: "trie", "removing value out of branch child, partial={:?}", partial); - match self.remove_at(child, partial.mid(1), old_val)? { - Some((new, changed)) => { - children[idx] = Some(new.into()); - let branch = Node::Branch(children, value); - match changed { - // child was changed, so we were too. - true => Action::Replace(branch), - // unchanged, so we are too. - false => Action::Restore(branch), - } - } - None => { - // the child we took was deleted. - // the node may need fixing. - trace!(target: "trie", "branch child deleted, partial={:?}", partial); - Action::Replace(self.fix(Node::Branch(children, value))?) - } - } - } else { - // no change needed. - Action::Restore(Node::Branch(children, value)) - } - } - (Node::Leaf(encoded, value), _) => { - if NibbleSlice::from_encoded(&encoded).0 == partial { - // this is the node we were looking for. Let's delete it. - *old_val = Some(value); - Action::Delete - } else { - // leaf the node alone. - trace!(target: "trie", "restoring leaf wrong partial, partial={:?}, existing={:?}", partial, NibbleSlice::from_encoded(&encoded).0); - Action::Restore(Node::Leaf(encoded, value)) - } - } - (Node::Extension(encoded, child_branch), _) => { - let (cp, existing_len) = { - let existing_key = NibbleSlice::from_encoded(&encoded).0; - (existing_key.common_prefix(&partial), existing_key.len()) - }; - if cp == existing_len { - // try to remove from the child branch. - trace!(target: "trie", "removing from extension child, partial={:?}", partial); - match self.remove_at(child_branch, partial.mid(cp), old_val)? { - Some((new_child, changed)) => { - let new_child = new_child.into(); - - // if the child branch was unchanged, then the extension is too. - // otherwise, this extension may need fixing. - match changed { - true => Action::Replace(self.fix(Node::Extension(encoded, new_child))?), - false => Action::Restore(Node::Extension(encoded, new_child)), - } - } - None => { - // the whole branch got deleted. - // that means that this extension is useless. - Action::Delete - } - } - } else { - // partway through an extension -- nothing to do here. - Action::Restore(Node::Extension(encoded, child_branch)) - } - } - }) - } - - /// Given a node which may be in an _invalid state_, fix it such that it is then in a valid - /// state. - /// - /// _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 { - match node { - Node::Branch(mut children, value) => { - // if only a single value, transmute to leaf/extension and feed through fixed. - #[derive(Debug)] - enum UsedIndex { - None, - One(u8), - Many, - }; - let mut used_index = UsedIndex::None; - for i in 0..16 { - match (children[i].is_none(), &used_index) { - (false, &UsedIndex::None) => used_index = UsedIndex::One(i as u8), - (false, &UsedIndex::One(_)) => { - used_index = UsedIndex::Many; - break; - } - _ => continue, - } - } - - match (used_index, value) { - (UsedIndex::None, None) => panic!("Branch with no subvalues. Something went wrong."), - (UsedIndex::One(a), None) => { - // only one onward node. make an extension. - let new_partial = NibbleSlice::new_offset(&[a], 1).encoded(false); - let child = children[a as usize].take().expect("used_index only set if occupied; qed"); - let new_node = Node::Extension(new_partial, child); - self.fix(new_node) - } - (UsedIndex::None, Some(value)) => { - // make a leaf. - trace!(target: "trie", "fixing: branch -> leaf"); - Ok(Node::Leaf(NibbleSlice::new(&[]).encoded(true), value)) - } - (_, value) => { - // all is well. - trace!(target: "trie", "fixing: restoring branch"); - Ok(Node::Branch(children, value)) - } - } - } - Node::Extension(partial, child) => { - let stored = match child { - NodeHandle::InMemory(h) => self.storage.destroy(h), - NodeHandle::Hash(h) => { - let handle = self.cache(h)?; - self.storage.destroy(handle) - } - }; - - let (child_node, maybe_hash) = match stored { - Stored::New(node) => (node, None), - Stored::Cached(node, hash) => (node, Some(hash)) - }; - - match child_node { - Node::Extension(sub_partial, sub_child) => { - // combine with node below. - if let Some(hash) = maybe_hash { - // delete the cached child since we are going to replace it. - self.death_row.insert(hash); - } - let partial = NibbleSlice::from_encoded(&partial).0; - let sub_partial = NibbleSlice::from_encoded(&sub_partial).0; - - let new_partial = NibbleSlice::new_composed(&partial, &sub_partial); - trace!(target: "trie", "fixing: extension combination. new_partial={:?}", new_partial); - self.fix(Node::Extension(new_partial.encoded(false), sub_child)) - } - Node::Leaf(sub_partial, value) => { - // combine with node below. - if let Some(hash) = maybe_hash { - // delete the cached child since we are going to replace it. - self.death_row.insert(hash); - } - let partial = NibbleSlice::from_encoded(&partial).0; - let sub_partial = NibbleSlice::from_encoded(&sub_partial).0; - - let new_partial = NibbleSlice::new_composed(&partial, &sub_partial); - trace!(target: "trie", "fixing: extension -> leaf. new_partial={:?}", new_partial); - Ok(Node::Leaf(new_partial.encoded(true), value)) - } - child_node => { - trace!(target: "trie", "fixing: restoring extension"); - - // reallocate the child node. - let stored = if let Some(hash) = maybe_hash { - Stored::Cached(child_node, hash) - } else { - Stored::New(child_node) - }; - - Ok(Node::Extension(partial, self.storage.alloc(stored).into())) - } - } - } - other => Ok(other), // only ext and branch need fixing. - } - } - - /// Commit the in-memory changes to disk, freeing their storage and - /// updating the state root. - pub fn commit(&mut self) { - trace!(target: "trie", "Committing trie changes to db."); - - // always kill all the nodes on death row. - trace!(target: "trie", "{:?} nodes to remove from db", self.death_row.len()); - for hash in self.death_row.drain() { - self.db.remove(&hash); - } - - let handle = match self.root_handle() { - NodeHandle::Hash(_) => return, // no changes necessary. - NodeHandle::InMemory(h) => h, - }; - - 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[..]); - self.hash_count += 1; - - trace!(target: "trie", "root node rlp: {:?}", (&root_rlp[..]).pretty()); - self.root_handle = NodeHandle::Hash(*self.root); - } - Stored::Cached(node, hash) => { - // probably won't happen, but update the root and move on. - *self.root = hash; - self.root_handle = NodeHandle::InMemory(self.storage.alloc(Stored::Cached(node, hash))); - } - } - } - - /// 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) { - 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) - } - } - } - }; - } - - // a hack to get the root node's handle - fn root_handle(&self) -> NodeHandle { - match self.root_handle { - NodeHandle::Hash(h) => NodeHandle::Hash(h), - NodeHandle::InMemory(StorageHandle(x)) => NodeHandle::InMemory(StorageHandle(x)), - } - } -} - -impl<'a> TrieMut for TrieDBMut<'a> { - fn root(&mut self) -> &H256 { - self.commit(); - self.root - } - - fn is_empty(&self) -> bool { - match self.root_handle { - NodeHandle::Hash(h) => h == KECCAK_NULL_RLP, - NodeHandle::InMemory(ref h) => match self.storage[h] { - Node::Empty => true, - _ => false, - } - } - } - - fn get<'x, 'key>(&'x self, key: &'key [u8]) -> super::Result> where 'x: 'key { - self.lookup(NibbleSlice::new(key), &self.root_handle) - } - - - fn insert(&mut self, key: &[u8], value: &[u8]) -> super::Result> { - if value.is_empty() { return self.remove(key) } - - let mut old_val = None; - - trace!(target: "trie", "insert: key={:?}, value={:?}", key.pretty(), value.pretty()); - - let root_handle = self.root_handle(); - let (new_handle, changed) = self.insert_at( - root_handle, - NibbleSlice::new(key), - DBValue::from_slice(value), - &mut old_val, - )?; - - trace!(target: "trie", "insert: altered trie={}", changed); - self.root_handle = NodeHandle::InMemory(new_handle); - - Ok(old_val) - } - - fn remove(&mut self, key: &[u8]) -> super::Result> { - trace!(target: "trie", "remove: key={:?}", key.pretty()); - - let root_handle = self.root_handle(); - let key = NibbleSlice::new(key); - let mut old_val = None; - - match self.remove_at(root_handle, key, &mut old_val)? { - Some((handle, changed)) => { - trace!(target: "trie", "remove: altered trie={}", changed); - self.root_handle = NodeHandle::InMemory(handle); - } - None => { - trace!(target: "trie", "remove: obliterated trie"); - self.root_handle = NodeHandle::Hash(KECCAK_NULL_RLP); - *self.root = KECCAK_NULL_RLP; - } - } - - Ok(old_val) - } -} - -impl<'a> Drop for TrieDBMut<'a> { - fn drop(&mut self) { - self.commit(); - } -} - -#[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 standardmap::*; - - fn populate_trie<'db>(db: &'db mut HashDB, root: &'db mut H256, v: &[(Vec, Vec)]) -> TrieDBMut<'db> { - let mut t = TrieDBMut::new(db, root); - for i in 0..v.len() { - let key: &[u8]= &v[i].0; - let val: &[u8] = &v[i].1; - t.insert(key, val).unwrap(); - } - t - } - - fn unpopulate_trie<'db>(t: &mut TrieDBMut<'db>, v: &[(Vec, Vec)]) { - for i in v { - let key: &[u8]= &i.0; - t.remove(key).unwrap(); - } - } - - #[test] - fn playpen() { - ::ethcore_logger::init_log(); - - let mut seed = H256::new(); - for test_i in 0..10 { - if test_i % 50 == 0 { - debug!("{:?} of 10000 stress tests done", test_i); - } - let x = StandardMap { - alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()), - min_key: 5, - journal_key: 0, - value_mode: ValueMode::Index, - count: 100, - }.make_with(&mut seed); - - let real = trie_root(x.clone()); - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let mut memtrie = populate_trie(&mut memdb, &mut root, &x); - - memtrie.commit(); - if *memtrie.root() != real { - println!("TRIE MISMATCH"); - println!(""); - println!("{:?} vs {:?}", memtrie.root(), real); - for i in &x { - println!("{:?} -> {:?}", i.0.pretty(), i.1.pretty()); - } - } - assert_eq!(*memtrie.root(), real); - unpopulate_trie(&mut memtrie, &x); - memtrie.commit(); - if *memtrie.root() != KECCAK_NULL_RLP { - println!("- TRIE MISMATCH"); - println!(""); - println!("{:?} vs {:?}", memtrie.root(), real); - for i in &x { - println!("{:?} -> {:?}", i.0.pretty(), i.1.pretty()); - } - } - assert_eq!(*memtrie.root(), KECCAK_NULL_RLP); - } - } - - #[test] - fn init() { - 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); - } - - #[test] - fn insert_on_empty() { - 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(); - assert_eq!(*t.root(), trie_root(vec![ (vec![0x01u8, 0x23], vec![0x01u8, 0x23]) ])); - } - - #[test] - fn remove_to_empty() { - let big_value = b"00000000000000000000000000000000"; - - 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 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(); - t2.remove(&[0x01]).unwrap(); - } - - #[test] - fn insert_replace_root() { - 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(); - t.insert(&[0x01u8, 0x23], &[0x23u8, 0x45]).unwrap(); - assert_eq!(*t.root(), trie_root(vec![ (vec![0x01u8, 0x23], vec![0x23u8, 0x45]) ])); - } - - #[test] - fn insert_make_branch_root() { - 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(); - t.insert(&[0x11u8, 0x23], &[0x11u8, 0x23]).unwrap(); - assert_eq!(*t.root(), trie_root(vec![ - (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), - (vec![0x11u8, 0x23], vec![0x11u8, 0x23]) - ])); - } - - #[test] - fn insert_into_branch_root() { - 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(); - t.insert(&[0xf1u8, 0x23], &[0xf1u8, 0x23]).unwrap(); - t.insert(&[0x81u8, 0x23], &[0x81u8, 0x23]).unwrap(); - assert_eq!(*t.root(), trie_root(vec![ - (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), - (vec![0x81u8, 0x23], vec![0x81u8, 0x23]), - (vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]), - ])); - } - - #[test] - fn insert_value_into_branch_root() { - 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(); - t.insert(&[], &[0x0]).unwrap(); - assert_eq!(*t.root(), trie_root(vec![ - (vec![], vec![0x0]), - (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), - ])); - } - - #[test] - fn insert_split_leaf() { - 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(); - t.insert(&[0x01u8, 0x34], &[0x01u8, 0x34]).unwrap(); - assert_eq!(*t.root(), trie_root(vec![ - (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), - (vec![0x01u8, 0x34], vec![0x01u8, 0x34]), - ])); - } - - #[test] - fn insert_split_extenstion() { - 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(); - t.insert(&[0x01, 0xf3, 0x45], &[0x02]).unwrap(); - t.insert(&[0x01, 0xf3, 0xf5], &[0x03]).unwrap(); - assert_eq!(*t.root(), trie_root(vec![ - (vec![0x01, 0x23, 0x45], vec![0x01]), - (vec![0x01, 0xf3, 0x45], vec![0x02]), - (vec![0x01, 0xf3, 0xf5], vec![0x03]), - ])); - } - - #[test] - fn insert_big_value() { - let big_value0 = b"00000000000000000000000000000000"; - let big_value1 = b"11111111111111111111111111111111"; - - 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(); - t.insert(&[0x11u8, 0x23], big_value1).unwrap(); - assert_eq!(*t.root(), trie_root(vec![ - (vec![0x01u8, 0x23], big_value0.to_vec()), - (vec![0x11u8, 0x23], big_value1.to_vec()) - ])); - } - - #[test] - fn insert_duplicate_value() { - let big_value = b"00000000000000000000000000000000"; - - 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(); - t.insert(&[0x11u8, 0x23], big_value).unwrap(); - assert_eq!(*t.root(), trie_root(vec![ - (vec![0x01u8, 0x23], big_value.to_vec()), - (vec![0x11u8, 0x23], big_value.to_vec()) - ])); - } - - #[test] - fn test_at_empty() { - 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)); - } - - #[test] - fn test_at_one() { - 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(); - assert_eq!(t.get(&[0x1, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x1u8, 0x23])); - t.commit(); - assert_eq!(t.get(&[0x1, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x1u8, 0x23])); - } - - #[test] - fn test_at_three() { - 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(); - t.insert(&[0xf1u8, 0x23], &[0xf1u8, 0x23]).unwrap(); - t.insert(&[0x81u8, 0x23], &[0x81u8, 0x23]).unwrap(); - 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)); - 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)); - } - - #[test] - fn stress() { - let mut seed = H256::new(); - for _ in 0..50 { - let x = StandardMap { - alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()), - min_key: 5, - journal_key: 0, - value_mode: ValueMode::Index, - count: 4, - }.make_with(&mut seed); - - let real = trie_root(x.clone()); - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let mut memtrie = populate_trie(&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 root2 = H256::new(); - let mut memtrie_sorted = populate_trie(&mut memdb2, &mut root2, &y); - if *memtrie.root() != real || *memtrie_sorted.root() != real { - println!("TRIE MISMATCH"); - println!(""); - println!("ORIGINAL... {:?}", memtrie.root()); - for i in &x { - println!("{:?} -> {:?}", i.0.pretty(), i.1.pretty()); - } - println!("SORTED... {:?}", memtrie_sorted.root()); - for i in &y { - println!("{:?} -> {:?}", i.0.pretty(), i.1.pretty()); - } - } - assert_eq!(*memtrie.root(), real); - assert_eq!(*memtrie_sorted.root(), real); - } - } - - #[test] - fn test_trie_existing() { - 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); - } - } - - #[test] - fn insert_empty() { - let mut seed = H256::new(); - let x = StandardMap { - alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()), - min_key: 5, - journal_key: 0, - value_mode: ValueMode::Index, - count: 4, - }.make_with(&mut seed); - - 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 { - t.insert(key, value).unwrap(); - } - - assert_eq!(*t.root(), trie_root(x.clone())); - - for &(ref key, _) in &x { - t.insert(key, &[]).unwrap(); - } - - assert!(t.is_empty()); - assert_eq!(*t.root(), KECCAK_NULL_RLP); - } - - #[test] - fn return_old_values() { - let mut seed = H256::new(); - let x = StandardMap { - alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()), - min_key: 5, - journal_key: 0, - value_mode: ValueMode::Index, - count: 4, - }.make_with(&mut seed); - - 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 { - assert!(t.insert(key, value).unwrap().is_none()); - assert_eq!(t.insert(key, value).unwrap(), Some(DBValue::from_slice(value))); - } - - for (key, value) in x { - assert_eq!(t.remove(&key).unwrap(), Some(DBValue::from_slice(&value))); - assert!(t.remove(&key).unwrap().is_none()); - } - } -} diff --git a/util/plain_hasher/Cargo.toml b/util/plain_hasher/Cargo.toml deleted file mode 100644 index d909f8f9d6ba3b007c1dd96c01c32a305d64a7d0..0000000000000000000000000000000000000000 --- a/util/plain_hasher/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "plain_hasher" -description = "Hasher for 32-bit keys." -version = "0.1.0" -authors = ["Parity Technologies "] -license = "MIT" -keywords = ["hash", "hasher"] -homepage = "https://github.com/paritytech/plain_hasher" - -[dependencies] -crunchy = "0.1.6" -ethereum-types = "0.3" diff --git a/util/plain_hasher/benches/bench.rs b/util/plain_hasher/benches/bench.rs deleted file mode 100644 index e7e8570abb2104a88c88d2b5061e9b3f54dedcc7..0000000000000000000000000000000000000000 --- a/util/plain_hasher/benches/bench.rs +++ /dev/null @@ -1,33 +0,0 @@ -#![feature(test)] - -extern crate test; -extern crate plain_hasher; - -use std::hash::Hasher; -use std::collections::hash_map::DefaultHasher; -use test::{Bencher, black_box}; -use plain_hasher::PlainHasher; - -#[bench] -fn write_plain_hasher(b: &mut Bencher) { - b.iter(|| { - let n: u8 = black_box(100); - (0..n).fold(PlainHasher::default(), |mut old, new| { - let bb = black_box([new; 32]); - old.write(&bb as &[u8]); - old - }); - }); -} - -#[bench] -fn write_default_hasher(b: &mut Bencher) { - b.iter(|| { - let n: u8 = black_box(100); - (0..n).fold(DefaultHasher::default(), |mut old, new| { - let bb = black_box([new; 32]); - old.write(&bb as &[u8]); - old - }); - }); -} diff --git a/util/plain_hasher/src/lib.rs b/util/plain_hasher/src/lib.rs deleted file mode 100644 index d08d4dd1abacfeb1ddacbe97e40da2d53c5aa868..0000000000000000000000000000000000000000 --- a/util/plain_hasher/src/lib.rs +++ /dev/null @@ -1,59 +0,0 @@ -#[macro_use] -extern crate crunchy; -extern crate ethereum_types; - -use ethereum_types::H256; -use std::collections::{HashMap, HashSet}; -use std::hash; - -/// 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. -pub type H256FastSet = HashSet>; - -/// Hasher that just takes 8 bytes of the provided value. -/// May only be used for keys which are 32 bytes. -#[derive(Default)] -pub struct PlainHasher { - prefix: u64, -} - -impl hash::Hasher for PlainHasher { - #[inline] - fn finish(&self) -> u64 { - self.prefix - } - - #[inline] - #[allow(unused_assignments)] - fn write(&mut self, bytes: &[u8]) { - debug_assert!(bytes.len() == 32); - let mut bytes_ptr = bytes.as_ptr(); - let mut prefix_ptr = &mut self.prefix as *mut u64 as *mut u8; - - unroll! { - for _i in 0..8 { - unsafe { - *prefix_ptr ^= (*bytes_ptr ^ *bytes_ptr.offset(8)) ^ (*bytes_ptr.offset(16) ^ *bytes_ptr.offset(24)); - bytes_ptr = bytes_ptr.offset(1); - prefix_ptr = prefix_ptr.offset(1); - } - } - } - } -} - -#[cfg(test)] -mod tests { - use std::hash::Hasher; - use super::PlainHasher; - - #[test] - fn it_works() { - let mut bytes = [32u8; 32]; - bytes[0] = 15; - let mut hasher = PlainHasher::default(); - hasher.write(&bytes); - assert_eq!(hasher.prefix, 47); - } -} diff --git a/util/reactor/src/lib.rs b/util/reactor/src/lib.rs index 9c049b8f75a584927fbcaac9e16472239ec7cac8..8fd37e7c8861d2afeffdc1009fc9e2fad6cff5b6 100644 --- a/util/reactor/src/lib.rs +++ b/util/reactor/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . - //! Tokio Core Reactor wrapper. extern crate futures; @@ -122,7 +121,6 @@ impl Remote { } } - /// Spawn a future to this event loop pub fn spawn(&self, r: R) where R: IntoFuture + Send + 'static, diff --git a/util/rlp/Cargo.toml b/util/rlp/Cargo.toml deleted file mode 100644 index 3bde7206ff8b414c04d30b0488422ca04ceac517..0000000000000000000000000000000000000000 --- a/util/rlp/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -description = "Recursive-length prefix encoding, decoding, and compression" -repository = "https://github.com/paritytech/parity" -license = "MIT/Apache-2.0" -name = "rlp" -version = "0.2.1" -authors = ["Parity Technologies "] - -[dependencies] -elastic-array = "0.10" -ethereum-types = "0.3" -rustc-hex = "1.0" -byteorder = "1.0" diff --git a/util/rlp/LICENSE-APACHE2 b/util/rlp/LICENSE-APACHE2 deleted file mode 100644 index 16fe87b06e802f094b3fbb0894b137bca2b16ef1..0000000000000000000000000000000000000000 --- a/util/rlp/LICENSE-APACHE2 +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/util/rlp/LICENSE-MIT b/util/rlp/LICENSE-MIT deleted file mode 100644 index cd8fdd2b9c6b9f6dec0c6dbf72ad38f3a8eb64b2..0000000000000000000000000000000000000000 --- a/util/rlp/LICENSE-MIT +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2015-2017 Parity Technologies - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/util/rlp/README.md b/util/rlp/README.md deleted file mode 100644 index f4007a88445291858e58a02ab68ab798925c90b4..0000000000000000000000000000000000000000 --- a/util/rlp/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# RLP - -Recursive-length-prefix encoding, decoding, and compression in Rust. - -## License - -Unlike most parts of Parity, which fall under the GPLv3, this package is dual-licensed under MIT/Apache2 at the user's choice. -Find the associated license files in this directory as `LICENSE-MIT` and `LICENSE-APACHE2` respectively. diff --git a/util/rlp/benches/rlp.rs b/util/rlp/benches/rlp.rs deleted file mode 100644 index 6aeabaf5de1846f6c2fe2f877fbe7a9cc6a03acc..0000000000000000000000000000000000000000 --- a/util/rlp/benches/rlp.rs +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2015-2017 Parity Technologies -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! benchmarking for rlp -//! should be started with: -//! ```bash -//! multirust run nightly cargo bench -//! ``` - -#![feature(test)] - -extern crate test; -extern crate ethcore_bigint as bigint; -extern crate rlp; - -use test::Bencher; -use bigint::prelude::U256; -use rlp::{RlpStream, Rlp}; - -#[bench] -fn bench_stream_u64_value(b: &mut Bencher) { - b.iter(|| { - // u64 - let mut stream = RlpStream::new(); - stream.append(&0x1023456789abcdefu64); - let _ = stream.out(); - }); -} - -#[bench] -fn bench_decode_u64_value(b: &mut Bencher) { - b.iter(|| { - // u64 - let data = vec![0x88, 0x10, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]; - let rlp = Rlp::new(&data); - let _: u64 = rlp.as_val(); - }); -} - -#[bench] -fn bench_stream_u256_value(b: &mut Bencher) { - b.iter(|| { - // u256 - let mut stream = RlpStream::new(); - let uint: U256 = "8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0".into(); - stream.append(&uint); - let _ = stream.out(); - }); -} - -#[bench] -fn bench_decode_u256_value(b: &mut Bencher) { - b.iter(|| { - // u256 - let data = vec![0xa0, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0x09, 0x10, 0x20, - 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(); - }); -} - -#[bench] -fn bench_stream_nested_empty_lists(b: &mut Bencher) { - b.iter(|| { - // [ [], [[]], [ [], [[]] ] ] - let mut stream = RlpStream::new_list(3); - stream.begin_list(0); - stream.begin_list(1).begin_list(0); - stream.begin_list(2).begin_list(0).begin_list(1).begin_list(0); - let _ = stream.out(); - }); -} - -#[bench] -fn bench_decode_nested_empty_lists(b: &mut Bencher) { - b.iter(|| { - // [ [], [[]], [ [], [[]] ] ] - 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(); - }); -} - -#[bench] -fn bench_stream_1000_empty_lists(b: &mut Bencher) { - b.iter(|| { - let mut stream = RlpStream::new_list(1000); - for _ in 0..1000 { - stream.begin_list(0); - } - let _ = stream.out(); - }); -} diff --git a/util/rlp/license-header b/util/rlp/license-header deleted file mode 100644 index 03df169c8be2de5fc58938dd2593888f3da115a9..0000000000000000000000000000000000000000 --- a/util/rlp/license-header +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2015-2017 Parity Technologies -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. diff --git a/util/rlp/src/error.rs b/util/rlp/src/error.rs deleted file mode 100644 index 7aef6cfbf72ea1844e5a595a1368ffccd9c0c2d4..0000000000000000000000000000000000000000 --- a/util/rlp/src/error.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2015-2017 Parity Technologies -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::fmt; -use std::error::Error as StdError; - -#[derive(Debug, PartialEq, Eq, Clone)] -/// Error concerning the RLP decoder. -pub enum DecoderError { - /// Data has additional bytes at the end of the valid RLP fragment. - RlpIsTooBig, - /// Data has too few bytes for valid RLP. - RlpIsTooShort, - /// Expect an encoded list, RLP was something else. - RlpExpectedToBeList, - /// Expect encoded data, RLP was something else. - RlpExpectedToBeData, - /// Expected a different size list. - RlpIncorrectListLen, - /// Data length number has a prefixed zero byte, invalid for numbers. - RlpDataLenWithZeroPrefix, - /// List length number has a prefixed zero byte, invalid for numbers. - RlpListLenWithZeroPrefix, - /// Non-canonical (longer than necessary) representation used for data or list. - RlpInvalidIndirection, - /// Declared length is inconsistent with data specified after. - RlpInconsistentLengthAndData, - /// Declared length is invalid and results in overflow - RlpInvalidLength, - /// Custom rlp decoding error. - Custom(&'static str), -} - -impl StdError for DecoderError { - fn description(&self) -> &str { - "builder error" - } -} - -impl fmt::Display for DecoderError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self, f) - } -} diff --git a/util/rlp/src/impls.rs b/util/rlp/src/impls.rs deleted file mode 100644 index 573f2c0781ec0fe97ba77cf4c96cd6c045a8dd45..0000000000000000000000000000000000000000 --- a/util/rlp/src/impls.rs +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright 2015-2017 Parity Technologies -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::{cmp, mem, str}; -use byteorder::{ByteOrder, BigEndian}; -use bigint::{U128, U256, H64, H128, H160, H256, H512, H520, Bloom}; -use traits::{Encodable, Decodable}; -use stream::RlpStream; -use {Rlp, DecoderError}; - -pub fn decode_usize(bytes: &[u8]) -> Result { - match bytes.len() { - l if l <= mem::size_of::() => { - if bytes[0] == 0 { - return Err(DecoderError::RlpInvalidIndirection); - } - let mut res = 0usize; - for i in 0..l { - let shift = (l - 1 - i) * 8; - res = res + ((bytes[i] as usize) << shift); - } - Ok(res) - } - _ => Err(DecoderError::RlpIsTooBig), - } -} - -impl Encodable for bool { - fn rlp_append(&self, s: &mut RlpStream) { - if *self { - s.encoder().encode_value(&[1]); - } else { - s.encoder().encode_value(&[0]); - } - } -} - -impl Decodable for bool { - fn decode(rlp: &Rlp) -> Result { - rlp.decoder().decode_value(|bytes| { - match bytes.len() { - 0 => Ok(false), - 1 => Ok(bytes[0] != 0), - _ => Err(DecoderError::RlpIsTooBig), - } - }) - } -} - -impl<'a> Encodable for &'a [u8] { - fn rlp_append(&self, s: &mut RlpStream) { - s.encoder().encode_value(self); - } -} - -impl Encodable for Vec { - fn rlp_append(&self, s: &mut RlpStream) { - s.encoder().encode_value(self); - } -} - -impl Decodable for Vec { - fn decode(rlp: &Rlp) -> Result { - rlp.decoder().decode_value(|bytes| { - Ok(bytes.to_vec()) - }) - } -} - -impl Encodable for Option where T: Encodable { - fn rlp_append(&self, s: &mut RlpStream) { - match *self { - None => { - s.begin_list(0); - }, - Some(ref value) => { - s.begin_list(1); - s.append(value); - } - } - } -} - -impl Decodable for Option where T: Decodable { - fn decode(rlp: &Rlp) -> Result { - let items = rlp.item_count()?; - match items { - 1 => rlp.val_at(0).map(Some), - 0 => Ok(None), - _ => Err(DecoderError::RlpIncorrectListLen), - } - } -} - -impl Encodable for u8 { - fn rlp_append(&self, s: &mut RlpStream) { - if *self != 0 { - s.encoder().encode_value(&[*self]); - } else { - s.encoder().encode_value(&[]); - } - } -} - -impl Decodable for u8 { - fn decode(rlp: &Rlp) -> Result { - rlp.decoder().decode_value(|bytes| { - match bytes.len() { - 1 if bytes[0] != 0 => Ok(bytes[0]), - 0 => Ok(0), - 1 => Err(DecoderError::RlpInvalidIndirection), - _ => Err(DecoderError::RlpIsTooBig), - } - }) - } -} - -macro_rules! impl_encodable_for_u { - ($name: ident, $func: ident, $size: expr) => { - impl Encodable for $name { - fn rlp_append(&self, s: &mut RlpStream) { - let leading_empty_bytes = self.leading_zeros() as usize / 8; - let mut buffer = [0u8; $size]; - BigEndian::$func(&mut buffer, *self); - s.encoder().encode_value(&buffer[leading_empty_bytes..]); - } - } - } -} - -macro_rules! impl_decodable_for_u { - ($name: ident) => { - impl Decodable for $name { - fn decode(rlp: &Rlp) -> Result { - rlp.decoder().decode_value(|bytes| { - match bytes.len() { - 0 | 1 => u8::decode(rlp).map(|v| v as $name), - l if l <= mem::size_of::<$name>() => { - if bytes[0] == 0 { - return Err(DecoderError::RlpInvalidIndirection); - } - let mut res = 0 as $name; - for i in 0..l { - let shift = (l - 1 - i) * 8; - res = res + ((bytes[i] as $name) << shift); - } - Ok(res) - } - _ => Err(DecoderError::RlpIsTooBig), - } - }) - } - } - } -} - -impl_encodable_for_u!(u16, write_u16, 2); -impl_encodable_for_u!(u32, write_u32, 4); -impl_encodable_for_u!(u64, write_u64, 8); - -impl_decodable_for_u!(u16); -impl_decodable_for_u!(u32); -impl_decodable_for_u!(u64); - -impl Encodable for usize { - fn rlp_append(&self, s: &mut RlpStream) { - (*self as u64).rlp_append(s); - } -} - -impl Decodable for usize { - fn decode(rlp: &Rlp) -> Result { - u64::decode(rlp).map(|value| value as usize) - } -} - -macro_rules! impl_encodable_for_hash { - ($name: ident) => { - impl Encodable for $name { - fn rlp_append(&self, s: &mut RlpStream) { - s.encoder().encode_value(self); - } - } - } -} - -macro_rules! impl_decodable_for_hash { - ($name: ident, $size: expr) => { - impl Decodable for $name { - fn decode(rlp: &Rlp) -> Result { - rlp.decoder().decode_value(|bytes| match bytes.len().cmp(&$size) { - cmp::Ordering::Less => Err(DecoderError::RlpIsTooShort), - cmp::Ordering::Greater => Err(DecoderError::RlpIsTooBig), - cmp::Ordering::Equal => { - let mut t = [0u8; $size]; - t.copy_from_slice(bytes); - Ok($name(t)) - } - }) - } - } - } -} - -impl_encodable_for_hash!(H64); -impl_encodable_for_hash!(H128); -impl_encodable_for_hash!(H160); -impl_encodable_for_hash!(H256); -impl_encodable_for_hash!(H512); -impl_encodable_for_hash!(H520); -impl_encodable_for_hash!(Bloom); - -impl_decodable_for_hash!(H64, 8); -impl_decodable_for_hash!(H128, 16); -impl_decodable_for_hash!(H160, 20); -impl_decodable_for_hash!(H256, 32); -impl_decodable_for_hash!(H512, 64); -impl_decodable_for_hash!(H520, 65); -impl_decodable_for_hash!(Bloom, 256); - -macro_rules! impl_encodable_for_uint { - ($name: ident, $size: expr) => { - impl Encodable for $name { - fn rlp_append(&self, s: &mut RlpStream) { - let leading_empty_bytes = $size - (self.bits() + 7) / 8; - let mut buffer = [0u8; $size]; - self.to_big_endian(&mut buffer); - s.encoder().encode_value(&buffer[leading_empty_bytes..]); - } - } - } -} - -macro_rules! impl_decodable_for_uint { - ($name: ident, $size: expr) => { - impl Decodable for $name { - fn decode(rlp: &Rlp) -> Result { - rlp.decoder().decode_value(|bytes| { - if !bytes.is_empty() && bytes[0] == 0 { - Err(DecoderError::RlpInvalidIndirection) - } else if bytes.len() <= $size { - Ok($name::from(bytes)) - } else { - Err(DecoderError::RlpIsTooBig) - } - }) - } - } - } -} - -impl_encodable_for_uint!(U256, 32); -impl_encodable_for_uint!(U128, 16); - -impl_decodable_for_uint!(U256, 32); -impl_decodable_for_uint!(U128, 16); - -impl<'a> Encodable for &'a str { - fn rlp_append(&self, s: &mut RlpStream) { - s.encoder().encode_value(self.as_bytes()); - } -} - -impl Encodable for String { - fn rlp_append(&self, s: &mut RlpStream) { - s.encoder().encode_value(self.as_bytes()); - } -} - -impl Decodable for String { - fn decode(rlp: &Rlp) -> Result { - rlp.decoder().decode_value(|bytes| { - match str::from_utf8(bytes) { - Ok(s) => Ok(s.to_owned()), - // consider better error type here - Err(_err) => Err(DecoderError::RlpExpectedToBeData), - } - }) - } -} diff --git a/util/rlp/src/lib.rs b/util/rlp/src/lib.rs deleted file mode 100644 index b416b1c25b0090deebddc6c127c19c88838b3d54..0000000000000000000000000000000000000000 --- a/util/rlp/src/lib.rs +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2015-2017 Parity Technologies -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Recursive Length Prefix serialization crate. -//! -//! Allows encoding, decoding, and view onto rlp-slice -//! -//!# What should you use when? -//! -//!### Use `encode` function when: -//! * You want to encode something inline. -//! * You do not work on big set of data. -//! * You want to encode whole data structure at once. -//! -//!### Use `decode` function when: -//! * You want to decode something inline. -//! * You do not work on big set of data. -//! * You want to decode whole rlp at once. -//! -//!### Use `RlpStream` when: -//! * You want to encode something in portions. -//! * You encode a big set of data. -//! -//!### Use `Rlp` when: -//! * You need to handle data corruption errors. -//! * You are working on input data. -//! * You want to get view onto rlp-slice. -//! * You don't want to decode whole rlp at once. - -extern crate byteorder; -extern crate ethereum_types as bigint; -extern crate elastic_array; -extern crate rustc_hex; - -mod traits; -mod error; -mod rlpin; -mod stream; -mod impls; - -use std::borrow::Borrow; -use elastic_array::ElasticArray1024; - -pub use error::DecoderError; -pub use traits::{Decodable, Encodable}; -pub use rlpin::{Rlp, RlpIterator, PayloadInfo, Prototype}; -pub use stream::RlpStream; - -/// The RLP encoded empty data (used to mean "null value"). -pub const NULL_RLP: [u8; 1] = [0x80; 1]; -/// The RLP encoded empty list. -pub const EMPTY_LIST_RLP: [u8; 1] = [0xC0; 1]; - -/// Shortcut function to decode trusted rlp -/// -/// ```rust -/// extern crate rlp; -/// -/// fn main () { -/// let data = vec![0x83, b'c', b'a', b't']; -/// let animal: String = rlp::decode(&data).expect("could not decode"); -/// assert_eq!(animal, "cat".to_owned()); -/// } -/// ``` -pub fn decode(bytes: &[u8]) -> Result where T: Decodable { - let rlp = Rlp::new(bytes); - rlp.as_val() -} - -pub fn decode_list(bytes: &[u8]) -> Vec where T: Decodable { - let rlp = Rlp::new(bytes); - rlp.as_list().expect("trusted rlp should be valid") -} - -/// Shortcut function to encode structure into rlp. -/// -/// ```rust -/// extern crate rlp; -/// -/// fn main () { -/// let animal = "cat"; -/// let out = rlp::encode(&animal).into_vec(); -/// assert_eq!(out, vec![0x83, b'c', b'a', b't']); -/// } -/// ``` -pub fn encode(object: &E) -> ElasticArray1024 where E: Encodable { - let mut stream = RlpStream::new(); - stream.append(object); - stream.drain() -} - -pub fn encode_list(object: &[K]) -> ElasticArray1024 where E: Encodable, K: Borrow { - let mut stream = RlpStream::new(); - stream.append_list(object); - stream.drain() -} diff --git a/util/rlp/src/rlpin.rs b/util/rlp/src/rlpin.rs deleted file mode 100644 index a55b4f7907129e99db4be39b7cd9e91c4ce335af..0000000000000000000000000000000000000000 --- a/util/rlp/src/rlpin.rs +++ /dev/null @@ -1,406 +0,0 @@ -// Copyright 2015-2017 Parity Technologies -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::cell::Cell; -use std::fmt; -use rustc_hex::ToHex; -use impls::decode_usize; -use {Decodable, DecoderError}; - -/// rlp offset -#[derive(Copy, Clone, Debug)] -struct OffsetCache { - index: usize, - offset: usize, -} - -impl OffsetCache { - fn new(index: usize, offset: usize) -> OffsetCache { - OffsetCache { - index: index, - offset: offset, - } - } -} - -#[derive(Debug)] -/// RLP prototype -pub enum Prototype { - /// Empty - Null, - /// Value - Data(usize), - /// List - List(usize), -} - -/// Stores basic information about item -pub struct PayloadInfo { - /// Header length in bytes - pub header_len: usize, - /// Value length in bytes - pub value_len: usize, -} - -fn calculate_payload_info(header_bytes: &[u8], len_of_len: usize) -> Result { - let header_len = 1 + len_of_len; - match header_bytes.get(1) { - Some(&0) => return Err(DecoderError::RlpDataLenWithZeroPrefix), - None => return Err(DecoderError::RlpIsTooShort), - _ => (), - } - if header_bytes.len() < header_len { return Err(DecoderError::RlpIsTooShort); } - let value_len = decode_usize(&header_bytes[1..header_len])?; - Ok(PayloadInfo::new(header_len, value_len)) -} - -impl PayloadInfo { - fn new(header_len: usize, value_len: usize) -> PayloadInfo { - PayloadInfo { - header_len: header_len, - value_len: value_len, - } - } - - /// Total size of the RLP. - pub fn total(&self) -> usize { self.header_len + self.value_len } - - /// Create a new object from the given bytes RLP. The bytes - pub fn from(header_bytes: &[u8]) -> Result { - match header_bytes.first().cloned() { - None => Err(DecoderError::RlpIsTooShort), - Some(0...0x7f) => Ok(PayloadInfo::new(0, 1)), - Some(l @ 0x80...0xb7) => Ok(PayloadInfo::new(1, l as usize - 0x80)), - Some(l @ 0xb8...0xbf) => { - let len_of_len = l as usize - 0xb7; - calculate_payload_info(header_bytes, len_of_len) - } - Some(l @ 0xc0...0xf7) => Ok(PayloadInfo::new(1, l as usize - 0xc0)), - Some(l @ 0xf8...0xff) => { - let len_of_len = l as usize - 0xf7; - calculate_payload_info(header_bytes, len_of_len) - }, - // we cant reach this place, but rust requires _ to be implemented - _ => { unreachable!(); } - } - } -} - -/// Data-oriented view onto rlp-slice. -/// -/// This is an immutable structure. No operations change it. -/// -/// Should be used in places where, error handling is required, -/// eg. on input -#[derive(Debug)] -pub struct Rlp<'a> { - bytes: &'a [u8], - offset_cache: Cell, - count_cache: Cell>, -} - -impl<'a> Clone for Rlp<'a> { - fn clone(&self) -> Rlp<'a> { - Rlp { - bytes: self.bytes, - offset_cache: self.offset_cache.clone(), - count_cache: self.count_cache.clone(), - } - } -} - -impl<'a> fmt::Display for Rlp<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match self.prototype() { - Ok(Prototype::Null) => write!(f, "null"), - Ok(Prototype::Data(_)) => write!(f, "\"0x{}\"", self.data().unwrap().to_hex()), - Ok(Prototype::List(len)) => { - write!(f, "[")?; - for i in 0..len-1 { - write!(f, "{}, ", self.at(i).unwrap())?; - } - write!(f, "{}", self.at(len - 1).unwrap())?; - write!(f, "]") - }, - Err(err) => write!(f, "{:?}", err) - } - } -} - -impl<'a, 'view> Rlp<'a> where 'a: 'view { - pub fn new(bytes: &'a [u8]) -> Rlp<'a> { - Rlp { - bytes: bytes, - offset_cache: Cell::new(OffsetCache::new(usize::max_value(), 0)), - count_cache: Cell::new(None) - } - } - - pub fn as_raw(&'view self) -> &'a [u8] { - self.bytes - } - - pub fn prototype(&self) -> Result { - // optimize? && return appropriate errors - if self.is_data() { - Ok(Prototype::Data(self.size())) - } else if self.is_list() { - self.item_count().map(Prototype::List) - } else { - Ok(Prototype::Null) - } - } - - pub fn payload_info(&self) -> Result { - BasicDecoder::payload_info(self.bytes) - } - - pub fn data(&'view self) -> Result<&'a [u8], DecoderError> { - let pi = BasicDecoder::payload_info(self.bytes)?; - Ok(&self.bytes[pi.header_len..(pi.header_len + pi.value_len)]) - } - - pub fn item_count(&self) -> Result { - match self.is_list() { - true => match self.count_cache.get() { - Some(c) => Ok(c), - None => { - let c = self.iter().count(); - self.count_cache.set(Some(c)); - Ok(c) - } - }, - false => Err(DecoderError::RlpExpectedToBeList), - } - } - - pub fn size(&self) -> usize { - match self.is_data() { - // TODO: No panic on malformed data, but ideally would Err on no PayloadInfo. - true => BasicDecoder::payload_info(self.bytes).map(|b| b.value_len).unwrap_or(0), - false => 0 - } - } - - pub fn at(&'view self, index: usize) -> Result, DecoderError> { - if !self.is_list() { - return Err(DecoderError::RlpExpectedToBeList); - } - - // move to cached position if its index is less or equal to - // current search index, otherwise move to beginning of list - let c = self.offset_cache.get(); - let (mut bytes, to_skip) = match c.index <= index { - true => (Rlp::consume(self.bytes, c.offset)?, index - c.index), - false => (self.consume_list_payload()?, index), - }; - - // skip up to x items - bytes = Rlp::consume_items(bytes, to_skip)?; - - // update the cache - self.offset_cache.set(OffsetCache::new(index, self.bytes.len() - bytes.len())); - - // construct new rlp - let found = BasicDecoder::payload_info(bytes)?; - Ok(Rlp::new(&bytes[0..found.header_len + found.value_len])) - } - - pub fn is_null(&self) -> bool { - self.bytes.len() == 0 - } - - pub fn is_empty(&self) -> bool { - !self.is_null() && (self.bytes[0] == 0xc0 || self.bytes[0] == 0x80) - } - - pub fn is_list(&self) -> bool { - !self.is_null() && self.bytes[0] >= 0xc0 - } - - pub fn is_data(&self) -> bool { - !self.is_null() && self.bytes[0] < 0xc0 - } - - pub fn is_int(&self) -> bool { - if self.is_null() { - return false; - } - - match self.bytes[0] { - 0...0x80 => true, - 0x81...0xb7 => self.bytes[1] != 0, - b @ 0xb8...0xbf => self.bytes[1 + b as usize - 0xb7] != 0, - _ => false - } - } - - pub fn iter(&'view self) -> RlpIterator<'a, 'view> { - self.into_iter() - } - - pub fn as_val(&self) -> Result where T: Decodable { - T::decode(self) - } - - pub fn as_list(&self) -> Result, DecoderError> where T: Decodable { - self.iter().map(|rlp| rlp.as_val()).collect() - } - - pub fn val_at(&self, index: usize) -> Result where T: Decodable { - self.at(index)?.as_val() - } - - pub fn list_at(&self, index: usize) -> Result, DecoderError> where T: Decodable { - self.at(index)?.as_list() - } - - pub fn decoder(&self) -> BasicDecoder { - BasicDecoder::new(self.clone()) - } - - /// consumes first found prefix - fn consume_list_payload(&self) -> Result<&'a [u8], DecoderError> { - let item = BasicDecoder::payload_info(self.bytes)?; - let bytes = Rlp::consume(self.bytes, item.header_len)?; - Ok(bytes) - } - - /// consumes fixed number of items - fn consume_items(bytes: &'a [u8], items: usize) -> Result<&'a [u8], DecoderError> { - let mut result = bytes; - for _ in 0..items { - let i = BasicDecoder::payload_info(result)?; - result = Rlp::consume(result, i.header_len + i.value_len)?; - } - Ok(result) - } - - - /// consumes slice prefix of length `len` - fn consume(bytes: &'a [u8], len: usize) -> Result<&'a [u8], DecoderError> { - match bytes.len() >= len { - true => Ok(&bytes[len..]), - false => Err(DecoderError::RlpIsTooShort), - } - } -} - -/// Iterator over rlp-slice list elements. -pub struct RlpIterator<'a, 'view> where 'a: 'view { - rlp: &'view Rlp<'a>, - index: usize, -} - -impl<'a, 'view> IntoIterator for &'view Rlp<'a> where 'a: 'view { - type Item = Rlp<'a>; - type IntoIter = RlpIterator<'a, 'view>; - - fn into_iter(self) -> Self::IntoIter { - RlpIterator { - rlp: self, - index: 0, - } - } -} - -impl<'a, 'view> Iterator for RlpIterator<'a, 'view> { - type Item = Rlp<'a>; - - fn next(&mut self) -> Option> { - let index = self.index; - let result = self.rlp.at(index).ok(); - self.index += 1; - result - } -} - -pub struct BasicDecoder<'a> { - rlp: Rlp<'a> -} - -impl<'a> BasicDecoder<'a> { - pub fn new(rlp: Rlp<'a>) -> BasicDecoder<'a> { - BasicDecoder { - rlp: rlp - } - } - - /// Return first item info. - fn payload_info(bytes: &[u8]) -> Result { - let item = PayloadInfo::from(bytes)?; - match item.header_len.checked_add(item.value_len) { - Some(x) if x <= bytes.len() => Ok(item), - _ => Err(DecoderError::RlpIsTooShort), - } - } - - pub fn decode_value(&self, f: F) -> Result - where F: Fn(&[u8]) -> Result { - - let bytes = self.rlp.as_raw(); - - match bytes.first().cloned() { - // RLP is too short. - None => Err(DecoderError::RlpIsTooShort), - // Single byte value. - Some(l @ 0...0x7f) => Ok(f(&[l])?), - // 0-55 bytes - Some(l @ 0x80...0xb7) => { - let last_index_of = 1 + l as usize - 0x80; - if bytes.len() < last_index_of { - return Err(DecoderError::RlpInconsistentLengthAndData); - } - let d = &bytes[1..last_index_of]; - if l == 0x81 && d[0] < 0x80 { - return Err(DecoderError::RlpInvalidIndirection); - } - Ok(f(d)?) - }, - // Longer than 55 bytes. - Some(l @ 0xb8...0xbf) => { - let len_of_len = l as usize - 0xb7; - let begin_of_value = 1 as usize + len_of_len; - if bytes.len() < begin_of_value { - return Err(DecoderError::RlpInconsistentLengthAndData); - } - let len = decode_usize(&bytes[1..begin_of_value])?; - - let last_index_of_value = begin_of_value.checked_add(len) - .ok_or(DecoderError::RlpInvalidLength)?; - if bytes.len() < last_index_of_value { - return Err(DecoderError::RlpInconsistentLengthAndData); - } - Ok(f(&bytes[begin_of_value..last_index_of_value])?) - } - // We are reading value, not a list! - _ => Err(DecoderError::RlpExpectedToBeData) - } - } -} - -#[cfg(test)] -mod tests { - use {Rlp, DecoderError}; - - #[test] - fn test_rlp_display() { - use rustc_hex::FromHex; - let data = "f84d0589010efbef67941f79b2a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470".from_hex().unwrap(); - let rlp = Rlp::new(&data); - assert_eq!(format!("{}", rlp), "[\"0x05\", \"0x010efbef67941f79b2\", \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\", \"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\"]"); - } - - #[test] - fn length_overflow() { - let bs = [0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe5]; - let rlp = Rlp::new(&bs); - let res: Result = rlp.as_val(); - assert_eq!(Err(DecoderError::RlpInvalidLength), res); - } -} diff --git a/util/rlp/src/stream.rs b/util/rlp/src/stream.rs deleted file mode 100644 index 000b6e15bcbe8714283ed2139528b510929f058f..0000000000000000000000000000000000000000 --- a/util/rlp/src/stream.rs +++ /dev/null @@ -1,382 +0,0 @@ -// Copyright 2015-2017 Parity Technologies -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::borrow::Borrow; -use byteorder::{ByteOrder, BigEndian}; -use elastic_array::{ElasticArray16, ElasticArray1024}; -use traits::Encodable; - -#[derive(Debug, Copy, Clone)] -struct ListInfo { - position: usize, - current: usize, - max: Option, -} - -impl ListInfo { - fn new(position: usize, max: Option) -> ListInfo { - ListInfo { - position: position, - current: 0, - max: max, - } - } -} - -/// Appendable rlp encoder. -pub struct RlpStream { - unfinished_lists: ElasticArray16, - buffer: ElasticArray1024, - finished_list: bool, -} - -impl Default for RlpStream { - fn default() -> Self { - RlpStream::new() - } -} - -impl RlpStream { - /// Initializes instance of empty `Stream`. - pub fn new() -> Self { - RlpStream { - unfinished_lists: ElasticArray16::new(), - buffer: ElasticArray1024::new(), - finished_list: false, - } - } - - /// Initializes the `Stream` as a list. - pub fn new_list(len: usize) -> Self { - let mut stream = RlpStream::new(); - stream.begin_list(len); - stream - } - - /// Appends value to the end of stream, chainable. - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let mut stream = RlpStream::new_list(2); - /// stream.append(&"cat").append(&"dog"); - /// let out = stream.out(); - /// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']); - /// } - /// ``` - pub fn append<'a, E>(&'a mut self, value: &E) -> &'a mut Self where E: Encodable { - self.finished_list = false; - value.rlp_append(self); - if !self.finished_list { - self.note_appended(1); - } - self - } - - /// Appends list of values to the end of stream, chainable. - pub fn append_list<'a, E, K>(&'a mut self, values: &[K]) -> &'a mut Self where E: Encodable, K: Borrow { - self.begin_list(values.len()); - for value in values { - self.append(value.borrow()); - } - self - } - - /// Appends value to the end of stream, but do not count it as an appended item. - /// It's useful for wrapper types - pub fn append_internal<'a, E>(&'a mut self, value: &E) -> &'a mut Self where E: Encodable { - value.rlp_append(self); - self - } - - /// Declare appending the list of given size, chainable. - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let mut stream = RlpStream::new_list(2); - /// stream.begin_list(2).append(&"cat").append(&"dog"); - /// stream.append(&""); - /// let out = stream.out(); - /// assert_eq!(out, vec![0xca, 0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g', 0x80]); - /// } - /// ``` - pub fn begin_list(&mut self, len: usize) -> &mut RlpStream { - self.finished_list = false; - match len { - 0 => { - // we may finish, if the appended list len is equal 0 - self.buffer.push(0xc0u8); - self.note_appended(1); - self.finished_list = true; - }, - _ => { - // payload is longer than 1 byte only for lists > 55 bytes - // by pushing always this 1 byte we may avoid unnecessary shift of data - self.buffer.push(0); - - let position = self.buffer.len(); - self.unfinished_lists.push(ListInfo::new(position, Some(len))); - }, - } - - // return chainable self - self - } - - - /// Declare appending the list of unknown size, chainable. - pub fn begin_unbounded_list(&mut self) -> &mut RlpStream { - self.finished_list = false; - // payload is longer than 1 byte only for lists > 55 bytes - // by pushing always this 1 byte we may avoid unnecessary shift of data - self.buffer.push(0); - let position = self.buffer.len(); - self.unfinished_lists.push(ListInfo::new(position, None)); - // return chainable self - 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 { - return false; - } - self.append_raw(bytes, item_count); - true - } - - /// Calculate total RLP size for appended payload. - pub fn estimate_size<'a>(&'a self, add: usize) -> usize { - let total_size = self.buffer.len() + add; - let mut base_size = total_size; - for list in &self.unfinished_lists[..] { - let len = total_size - list.position; - if len > 55 { - let leading_empty_bytes = (len as u64).leading_zeros() as usize / 8; - let size_bytes = 8 - leading_empty_bytes; - base_size += size_bytes; - } - } - base_size - } - - - /// Returns current RLP size in bytes for the data pushed into the list. - pub fn len<'a>(&'a self) -> usize { - self.estimate_size(0) - } - - /// Clear the output stream so far. - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let mut stream = RlpStream::new_list(3); - /// stream.append(&"cat"); - /// stream.clear(); - /// stream.append(&"dog"); - /// let out = stream.out(); - /// assert_eq!(out, vec![0x83, b'd', b'o', b'g']); - /// } - pub fn clear(&mut self) { - // clear bytes - self.buffer.clear(); - - // clear lists - self.unfinished_lists.clear(); - } - - /// Returns true if stream doesnt expect any more items. - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let mut stream = RlpStream::new_list(2); - /// stream.append(&"cat"); - /// assert_eq!(stream.is_finished(), false); - /// stream.append(&"dog"); - /// assert_eq!(stream.is_finished(), true); - /// let out = stream.out(); - /// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']); - /// } - pub fn is_finished(&self) -> bool { - self.unfinished_lists.len() == 0 - } - - /// Get raw encoded bytes - pub fn as_raw(&self) -> &[u8] { - //&self.encoder.bytes - &self.buffer - } - - /// Streams out encoded bytes. - /// - /// panic! if stream is not finished. - pub fn out(self) -> Vec { - match self.is_finished() { - //true => self.encoder.out().into_vec(), - true => self.buffer.into_vec(), - false => panic!() - } - } - - /// Try to finish lists - fn note_appended(&mut self, inserted_items: usize) -> () { - if self.unfinished_lists.len() == 0 { - return; - } - - let back = self.unfinished_lists.len() - 1; - let should_finish = match self.unfinished_lists.get_mut(back) { - None => false, - Some(ref mut x) => { - x.current += inserted_items; - match x.max { - Some(ref max) if x.current > *max => panic!("You cannot append more items then you expect!"), - Some(ref max) => x.current == *max, - _ => false, - } - } - }; - - if should_finish { - let x = self.unfinished_lists.pop().unwrap(); - let len = self.buffer.len() - x.position; - self.encoder().insert_list_payload(len, x.position); - self.note_appended(1); - } - self.finished_list = should_finish; - } - - pub fn encoder(&mut self) -> BasicEncoder { - 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."); - if list.max.is_some() { - panic!("List type mismatch."); - } - let len = self.buffer.len() - list.position; - self.encoder().insert_list_payload(len, list.position); - self.note_appended(1); - } -} - -pub struct BasicEncoder<'a> { - buffer: &'a mut ElasticArray1024, -} - -impl<'a> BasicEncoder<'a> { - fn new(stream: &'a mut RlpStream) -> Self { - BasicEncoder { - buffer: &mut stream.buffer - } - } - - fn insert_size(&mut self, size: usize, position: usize) -> u8 { - let size = size as u32; - let leading_empty_bytes = size.leading_zeros() as usize / 8; - let size_bytes = 4 - leading_empty_bytes as u8; - let mut buffer = [0u8; 4]; - BigEndian::write_u32(&mut buffer, size); - self.buffer.insert_slice(position, &buffer[leading_empty_bytes..]); - size_bytes as u8 - } - - /// Inserts list prefix at given position - fn insert_list_payload(&mut self, len: usize, pos: usize) { - // 1 byte was already reserved for payload earlier - match len { - 0...55 => { - self.buffer[pos - 1] = 0xc0u8 + len as u8; - }, - _ => { - let inserted_bytes = self.insert_size(len, pos); - self.buffer[pos - 1] = 0xf7u8 + inserted_bytes; - } - }; - } - - /// Pushes encoded value to the end of buffer - pub fn encode_value(&mut self, value: &[u8]) { - match value.len() { - // just 0 - 0 => self.buffer.push(0x80u8), - // byte is its own encoding if < 0x80 - 1 if value[0] < 0x80 => self.buffer.push(value[0]), - // (prefix + length), followed by the string - len @ 1 ... 55 => { - self.buffer.push(0x80u8 + len as u8); - self.buffer.append_slice(value); - } - // (prefix + length of length), followed by the length, followd by the string - len => { - self.buffer.push(0); - let position = self.buffer.len(); - let inserted_bytes = self.insert_size(len, position); - self.buffer[position - 1] = 0xb7 + inserted_bytes; - self.buffer.append_slice(value); - } - } - } -} diff --git a/util/rlp/src/traits.rs b/util/rlp/src/traits.rs deleted file mode 100644 index 1596009e75f40c3446d47ac5e7fee2d2e9df997e..0000000000000000000000000000000000000000 --- a/util/rlp/src/traits.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2015-2017 Parity Technologies -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Common RLP traits -use elastic_array::ElasticArray1024; -use {DecoderError, Rlp, RlpStream}; - -/// RLP decodable trait -pub trait Decodable: Sized { - /// Decode a value from RLP bytes - fn decode(rlp: &Rlp) -> Result; -} - -/// Structure encodable to RLP -pub trait Encodable { - /// Append a value to the stream - fn rlp_append(&self, s: &mut RlpStream); - - /// Get rlp-encoded bytes for this instance - fn rlp_bytes(&self) -> ElasticArray1024 { - let mut s = RlpStream::new(); - self.rlp_append(&mut s); - s.drain() - } -} diff --git a/util/rlp/tests/tests.rs b/util/rlp/tests/tests.rs deleted file mode 100644 index 041c267667da3becfcb8de92dd6adf536da42425..0000000000000000000000000000000000000000 --- a/util/rlp/tests/tests.rs +++ /dev/null @@ -1,426 +0,0 @@ -// Copyright 2015-2017 Parity Technologies -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -extern crate ethereum_types as bigint; -extern crate rlp; - -use std::{fmt, cmp}; -use bigint::{U256, H160}; -use rlp::{Encodable, Decodable, Rlp, RlpStream, DecoderError}; - -#[test] -fn rlp_at() { - let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - { - let rlp = Rlp::new(&data); - assert!(rlp.is_list()); - let animals: Vec = rlp.as_list().unwrap(); - assert_eq!(animals, vec!["cat".to_owned(), "dog".to_owned()]); - - let cat = rlp.at(0).unwrap(); - assert!(cat.is_data()); - assert_eq!(cat.as_raw(), &[0x83, b'c', b'a', b't']); - assert_eq!(cat.as_val::().unwrap(), "cat".to_owned()); - - let dog = rlp.at(1).unwrap(); - assert!(dog.is_data()); - assert_eq!(dog.as_raw(), &[0x83, b'd', b'o', b'g']); - assert_eq!(dog.as_val::().unwrap(), "dog".to_owned()); - - let cat_again = rlp.at(0).unwrap(); - assert!(cat_again.is_data()); - assert_eq!(cat_again.as_raw(), &[0x83, b'c', b'a', b't']); - assert_eq!(cat_again.as_val::().unwrap(), "cat".to_owned()); - } -} - -#[test] -fn rlp_at_err() { - let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o']; - { - let rlp = Rlp::new(&data); - assert!(rlp.is_list()); - - let cat_err = rlp.at(0).unwrap_err(); - assert_eq!(cat_err, DecoderError::RlpIsTooShort); - - let dog_err = rlp.at(1).unwrap_err(); - assert_eq!(dog_err, DecoderError::RlpIsTooShort); - } -} - -#[test] -fn rlp_iter() { - let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - { - let rlp = Rlp::new(&data); - let mut iter = rlp.iter(); - - let cat = iter.next().unwrap(); - assert!(cat.is_data()); - assert_eq!(cat.as_raw(), &[0x83, b'c', b'a', b't']); - - let dog = iter.next().unwrap(); - assert!(dog.is_data()); - assert_eq!(dog.as_raw(), &[0x83, b'd', b'o', b'g']); - - let none = iter.next(); - assert!(none.is_none()); - - let cat_again = rlp.at(0).unwrap(); - assert!(cat_again.is_data()); - assert_eq!(cat_again.as_raw(), &[0x83, b'c', b'a', b't']); - } -} - -struct ETestPair(T, Vec) where T: Encodable; - -fn run_encode_tests(tests: Vec>) - where T: Encodable -{ - for t in &tests { - let res = rlp::encode(&t.0); - assert_eq!(&res[..], &t.1[..]); - } -} - -struct VETestPair(Vec, Vec) where T: Encodable; - -fn run_encode_tests_list(tests: Vec>) - where T: Encodable -{ - for t in &tests { - let res = rlp::encode_list(&t.0); - assert_eq!(&res[..], &t.1[..]); - } -} - -#[test] -fn encode_u16() { - let tests = vec![ - ETestPair(0u16, vec![0x80u8]), - ETestPair(0x100, vec![0x82, 0x01, 0x00]), - ETestPair(0xffff, vec![0x82, 0xff, 0xff]), - ]; - run_encode_tests(tests); -} - -#[test] -fn encode_u32() { - let tests = vec![ - ETestPair(0u32, vec![0x80u8]), - ETestPair(0x10000, vec![0x83, 0x01, 0x00, 0x00]), - ETestPair(0xffffff, vec![0x83, 0xff, 0xff, 0xff]), - ]; - run_encode_tests(tests); -} - -#[test] -fn encode_u64() { - let tests = vec![ - ETestPair(0u64, vec![0x80u8]), - ETestPair(0x1000000, vec![0x84, 0x01, 0x00, 0x00, 0x00]), - ETestPair(0xFFFFFFFF, vec![0x84, 0xff, 0xff, 0xff, 0xff]), - ]; - run_encode_tests(tests); -} - -#[test] -fn encode_u256() { - let tests = vec![ETestPair(U256::from(0u64), vec![0x80u8]), - ETestPair(U256::from(0x1000000u64), vec![0x84, 0x01, 0x00, 0x00, 0x00]), - ETestPair(U256::from(0xffffffffu64), - vec![0x84, 0xff, 0xff, 0xff, 0xff]), - ETestPair(("8090a0b0c0d0e0f00910203040506077000000000000\ - 000100000000000012f0").into(), - vec![0xa0, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, - 0x09, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x77, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x12, 0xf0])]; - run_encode_tests(tests); -} - -#[test] -fn encode_str() { - let tests = vec![ETestPair("cat", vec![0x83, b'c', b'a', b't']), - ETestPair("dog", vec![0x83, b'd', b'o', b'g']), - ETestPair("Marek", vec![0x85, b'M', b'a', b'r', b'e', b'k']), - ETestPair("", vec![0x80]), - ETestPair("Lorem ipsum dolor sit amet, consectetur adipisicing elit", - vec![0xb8, 0x38, b'L', b'o', b'r', b'e', b'm', b' ', b'i', - b'p', b's', b'u', b'm', b' ', b'd', b'o', b'l', b'o', - b'r', b' ', b's', b'i', b't', b' ', b'a', b'm', b'e', - b't', b',', b' ', b'c', b'o', b'n', b's', b'e', b'c', - b't', b'e', b't', b'u', b'r', b' ', b'a', b'd', b'i', - b'p', b'i', b's', b'i', b'c', b'i', b'n', b'g', b' ', - b'e', b'l', b'i', b't'])]; - run_encode_tests(tests); -} - -#[test] -fn encode_address() { - let tests = vec![ - ETestPair(H160::from("ef2d6d194084c2de36e0dabfce45d046b37d1106"), - vec![0x94, 0xef, 0x2d, 0x6d, 0x19, 0x40, 0x84, 0xc2, 0xde, - 0x36, 0xe0, 0xda, 0xbf, 0xce, 0x45, 0xd0, 0x46, - 0xb3, 0x7d, 0x11, 0x06]) - ]; - run_encode_tests(tests); -} - -/// Vec (Bytes) is treated as a single value -#[test] -fn encode_vector_u8() { - let tests = vec![ - ETestPair(vec![], vec![0x80]), - ETestPair(vec![0u8], vec![0]), - ETestPair(vec![0x15], vec![0x15]), - ETestPair(vec![0x40, 0x00], vec![0x82, 0x40, 0x00]), - ]; - run_encode_tests(tests); -} - -#[test] -fn encode_vector_u64() { - let tests = vec![ - VETestPair(vec![], vec![0xc0]), - VETestPair(vec![15u64], vec![0xc1, 0x0f]), - VETestPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]), - VETestPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]), - ]; - run_encode_tests_list(tests); -} - -#[test] -fn encode_vector_str() { - let tests = vec![VETestPair(vec!["cat", "dog"], - vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'])]; - run_encode_tests_list(tests); -} - -struct DTestPair(T, Vec) where T: Decodable + fmt::Debug + cmp::Eq; - -struct VDTestPair(Vec, Vec) where T: Decodable + fmt::Debug + cmp::Eq; - -fn run_decode_tests(tests: Vec>) where T: Decodable + fmt::Debug + cmp::Eq { - for t in &tests { - let res : Result = rlp::decode(&t.1); - assert!(res.is_ok()); - let res = res.unwrap(); - assert_eq!(&res, &t.0); - } -} - -fn run_decode_tests_list(tests: Vec>) where T: Decodable + fmt::Debug + cmp::Eq { - for t in &tests { - let res: Vec = rlp::decode_list(&t.1); - assert_eq!(res, t.0); - } -} - -/// Vec (Bytes) is treated as a single value -#[test] -fn decode_vector_u8() { - let tests = vec![ - DTestPair(vec![], vec![0x80]), - DTestPair(vec![0u8], vec![0]), - DTestPair(vec![0x15], vec![0x15]), - DTestPair(vec![0x40, 0x00], vec![0x82, 0x40, 0x00]), - ]; - run_decode_tests(tests); -} - -#[test] -fn decode_untrusted_u8() { - let tests = vec![ - DTestPair(0x0u8, vec![0x80]), - DTestPair(0x77u8, vec![0x77]), - DTestPair(0xccu8, vec![0x81, 0xcc]), - ]; - run_decode_tests(tests); -} - -#[test] -fn decode_untrusted_u16() { - let tests = vec![ - DTestPair(0x100u16, vec![0x82, 0x01, 0x00]), - DTestPair(0xffffu16, vec![0x82, 0xff, 0xff]), - ]; - run_decode_tests(tests); -} - -#[test] -fn decode_untrusted_u32() { - let tests = vec![ - DTestPair(0x10000u32, vec![0x83, 0x01, 0x00, 0x00]), - DTestPair(0xffffffu32, vec![0x83, 0xff, 0xff, 0xff]), - ]; - run_decode_tests(tests); -} - -#[test] -fn decode_untrusted_u64() { - let tests = vec![ - DTestPair(0x1000000u64, vec![0x84, 0x01, 0x00, 0x00, 0x00]), - DTestPair(0xFFFFFFFFu64, vec![0x84, 0xff, 0xff, 0xff, 0xff]), - ]; - run_decode_tests(tests); -} - -#[test] -fn decode_untrusted_u256() { - let tests = vec![DTestPair(U256::from(0u64), vec![0x80u8]), - DTestPair(U256::from(0x1000000u64), vec![0x84, 0x01, 0x00, 0x00, 0x00]), - DTestPair(U256::from(0xffffffffu64), - vec![0x84, 0xff, 0xff, 0xff, 0xff]), - DTestPair(("8090a0b0c0d0e0f00910203040506077000000000000\ - 000100000000000012f0").into(), - vec![0xa0, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, - 0x09, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x77, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x12, 0xf0])]; - run_decode_tests(tests); -} - -#[test] -fn decode_untrusted_str() { - let tests = vec![DTestPair("cat".to_owned(), vec![0x83, b'c', b'a', b't']), - DTestPair("dog".to_owned(), vec![0x83, b'd', b'o', b'g']), - DTestPair("Marek".to_owned(), - vec![0x85, b'M', b'a', b'r', b'e', b'k']), - DTestPair("".to_owned(), vec![0x80]), - DTestPair("Lorem ipsum dolor sit amet, consectetur adipisicing elit" - .to_owned(), - vec![0xb8, 0x38, b'L', b'o', b'r', b'e', b'm', b' ', b'i', - b'p', b's', b'u', b'm', b' ', b'd', b'o', b'l', b'o', - b'r', b' ', b's', b'i', b't', b' ', b'a', b'm', b'e', - b't', b',', b' ', b'c', b'o', b'n', b's', b'e', b'c', - b't', b'e', b't', b'u', b'r', b' ', b'a', b'd', b'i', - b'p', b'i', b's', b'i', b'c', b'i', b'n', b'g', b' ', - b'e', b'l', b'i', b't'])]; - run_decode_tests(tests); -} - -#[test] -fn decode_untrusted_address() { - let tests = vec![ - DTestPair(H160::from("ef2d6d194084c2de36e0dabfce45d046b37d1106"), - vec![0x94, 0xef, 0x2d, 0x6d, 0x19, 0x40, 0x84, 0xc2, 0xde, - 0x36, 0xe0, 0xda, 0xbf, 0xce, 0x45, 0xd0, 0x46, - 0xb3, 0x7d, 0x11, 0x06]) - ]; - run_decode_tests(tests); -} - -#[test] -fn decode_untrusted_vector_u64() { - let tests = vec![ - VDTestPair(vec![], vec![0xc0]), - VDTestPair(vec![15u64], vec![0xc1, 0x0f]), - VDTestPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]), - VDTestPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]), - ]; - run_decode_tests_list(tests); -} - -#[test] -fn decode_untrusted_vector_str() { - let tests = vec![VDTestPair(vec!["cat".to_owned(), "dog".to_owned()], - vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'])]; - run_decode_tests_list(tests); -} - -#[test] -fn test_rlp_data_length_check() -{ - let data = vec![0x84, b'c', b'a', b't']; - let rlp = Rlp::new(&data); - - let as_val: Result = rlp.as_val(); - assert_eq!(Err(DecoderError::RlpInconsistentLengthAndData), as_val); -} - -#[test] -fn test_rlp_long_data_length_check() -{ - let mut data: Vec = vec![0xb8, 255]; - for _ in 0..253 { - data.push(b'c'); - } - - let rlp = Rlp::new(&data); - - let as_val: Result = rlp.as_val(); - assert_eq!(Err(DecoderError::RlpInconsistentLengthAndData), as_val); -} - -#[test] -fn test_the_exact_long_string() -{ - let mut data: Vec = vec![0xb8, 255]; - for _ in 0..255 { - data.push(b'c'); - } - - let rlp = Rlp::new(&data); - - let as_val: Result = rlp.as_val(); - assert!(as_val.is_ok()); -} - -#[test] -fn test_rlp_2bytes_data_length_check() -{ - let mut data: Vec = vec![0xb9, 2, 255]; // 512+255 - for _ in 0..700 { - data.push(b'c'); - } - - let rlp = Rlp::new(&data); - - let as_val: Result = rlp.as_val(); - assert_eq!(Err(DecoderError::RlpInconsistentLengthAndData), as_val); -} - -#[test] -fn test_rlp_nested_empty_list_encode() { - let mut stream = RlpStream::new_list(2); - stream.append_list(&(Vec::new() as Vec)); - stream.append(&40u32); - assert_eq!(stream.drain()[..], [0xc2u8, 0xc0u8, 40u8][..]); -} - -#[test] -fn test_rlp_list_length_overflow() { - let data: Vec = vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00]; - let rlp = Rlp::new(&data); - let as_val: Result = rlp.val_at(0); - assert_eq!(Err(DecoderError::RlpIsTooShort), as_val); -} - -#[test] -fn test_rlp_stream_size_limit() { - for limit in 40 .. 270 { - let item = [0u8; 1]; - let mut stream = RlpStream::new(); - while stream.append_raw_checked(&item, 1, limit) {} - assert_eq!(stream.drain().len(), limit); - } -} - -#[test] -fn test_rlp_stream_unbounded_list() { - let mut stream = RlpStream::new(); - stream.begin_unbounded_list(); - stream.append(&40u32); - stream.append(&41u32); - assert!(!stream.is_finished()); - stream.complete_unbounded_list(); - assert!(stream.is_finished()); -} - diff --git a/util/rlp_compress/Cargo.toml b/util/rlp_compress/Cargo.toml index d5f85425f2376a025922ec43f0191e0bcd62e43c..c61d1f206d292c541f40137cd4d9402948f55531 100644 --- a/util/rlp_compress/Cargo.toml +++ b/util/rlp_compress/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" authors = ["Parity Technologies "] [dependencies] -rlp = { path = "../rlp" } +rlp = { git = "https://github.com/paritytech/parity-common" } elastic-array = "0.10" lazy_static = "1.0" diff --git a/util/rlp_compress/src/lib.rs b/util/rlp_compress/src/lib.rs index b895e1ce1acdbae06843e8c18706a314652f9f06..af5b09aac79b81e0cb0d3a2d03baae4fe2b559ae 100644 --- a/util/rlp_compress/src/lib.rs +++ b/util/rlp_compress/src/lib.rs @@ -107,4 +107,3 @@ impl<'a> Compressor for Swapper<'a> { self.rlp_to_compressed.get(rlp).cloned() } } - diff --git a/util/rlp_compress/tests/compress.rs b/util/rlp_compress/tests/compress.rs index a01dbde358c1e0d5066bce11cc70f5d7f32a96f6..9d23f8c670c820f85aa4e4d8d71f6075f8593d1e 100644 --- a/util/rlp_compress/tests/compress.rs +++ b/util/rlp_compress/tests/compress.rs @@ -1,3 +1,19 @@ +// 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 . + extern crate rlp_compress; use rlp_compress::{compress, decompress, Swapper, snapshot_swapper, blocks_swapper, Compressor, Decompressor}; diff --git a/util/rlp_derive/Cargo.toml b/util/rlp_derive/Cargo.toml index bb488cc29e679622731c519984b3741e8a2d3169..c71e3d2454fca96c39658db368daebfb13f8aef6 100644 --- a/util/rlp_derive/Cargo.toml +++ b/util/rlp_derive/Cargo.toml @@ -12,4 +12,4 @@ syn = "0.13" quote = "0.5" [dev-dependencies] -rlp = { path = "../rlp" } +rlp = { git = "https://github.com/paritytech/parity-common" } diff --git a/util/rlp_derive/src/de.rs b/util/rlp_derive/src/de.rs index dac4e34cdb3a6a2d218f62bd5bee4a2a780cd57a..fe0ccfba6f208cd62388dbc7dff8550f2cdb1ab0 100644 --- a/util/rlp_derive/src/de.rs +++ b/util/rlp_derive/src/de.rs @@ -1,3 +1,19 @@ +// 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 . + use {syn, quote}; struct ParseQuotes { @@ -28,7 +44,6 @@ pub fn impl_decodable(ast: &syn::DeriveInput) -> quote::Tokens { _ => panic!("#[derive(RlpDecodable)] is only defined for structs."), }; - let stmts: Vec<_> = body.fields.iter().enumerate().map(decodable_field_map).collect(); let name = &ast.ident; @@ -132,4 +147,3 @@ fn decodable_field(index: usize, field: &syn::Field, quotes: ParseQuotes) -> quo _ => panic!("rlp_derive not supported"), } } - diff --git a/util/rlp_derive/src/en.rs b/util/rlp_derive/src/en.rs index 484ac015e5dcf72f56befc572779c60d8c0217a0..607255a96c1d87e85afcef9edede6a9b0847938a 100644 --- a/util/rlp_derive/src/en.rs +++ b/util/rlp_derive/src/en.rs @@ -1,3 +1,19 @@ +// 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 . + use {syn, quote}; pub fn impl_encodable(ast: &syn::DeriveInput) -> quote::Tokens { @@ -104,4 +120,3 @@ fn encodable_field(index: usize, field: &syn::Field) -> quote::Tokens { _ => panic!("rlp_derive not supported"), } } - diff --git a/util/rlp_derive/src/lib.rs b/util/rlp_derive/src/lib.rs index 93f8d9619d10b861d5d1baba967213de2291e6a0..bc6bff1d5c4bdbe1dd1cc4d6ebfa47d7ce080eba 100644 --- a/util/rlp_derive/src/lib.rs +++ b/util/rlp_derive/src/lib.rs @@ -1,3 +1,19 @@ +// 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 . + extern crate proc_macro; extern crate syn; #[macro_use] diff --git a/util/rlp_derive/tests/rlp.rs b/util/rlp_derive/tests/rlp.rs index ba51309146e92cec645cf6285a32cd80eb3797e2..7115b87c965aa0f94fce7c2357e7b4e4cf66007a 100644 --- a/util/rlp_derive/tests/rlp.rs +++ b/util/rlp_derive/tests/rlp.rs @@ -1,3 +1,19 @@ +// 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 . + extern crate rlp; #[macro_use] extern crate rlp_derive; @@ -41,4 +57,3 @@ fn test_encode_foo_wrapper() { let decoded = decode(&expected).expect("decode failure"); assert_eq!(foo, decoded); } - diff --git a/util/stats/src/lib.rs b/util/stats/src/lib.rs index 74fda927265612247284b213986a5fd584fc6d17..8d107f4e9cc63101aac9faac6a1d5a3f9102a67f 100644 --- a/util/stats/src/lib.rs +++ b/util/stats/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -130,7 +130,6 @@ impl Histogram } } - #[cfg(test)] mod tests { use super::*; diff --git a/util/stop-guard/src/lib.rs b/util/stop-guard/src/lib.rs index f208138ab6e6eec13de34119d718f17cccaa9a72..208b57c6d90482e3630bbd1f9a9c40aae253f602 100644 --- a/util/stop-guard/src/lib.rs +++ b/util/stop-guard/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/trace-time/src/lib.rs b/util/trace-time/src/lib.rs index e9566e7f94419fff266b1bcdd3066e40d7342fbe..4c3b0b274350f0ac89828e20be0f825ca027f225 100644 --- a/util/trace-time/src/lib.rs +++ b/util/trace-time/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/trie-standardmap/Cargo.toml b/util/trie-standardmap/Cargo.toml deleted file mode 100644 index 1177f30752c3f2a154a8ee309332fb993e9dc8f6..0000000000000000000000000000000000000000 --- a/util/trie-standardmap/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "trie-standardmap" -version = "0.1.0" -authors = ["debris "] -description = "Standard test map for profiling tries" - -[dependencies] -ethcore-bytes = { path = "../bytes" } -ethereum-types = "0.3" -keccak-hash = { path = "../hash" } -rlp = { path = "../rlp" } diff --git a/util/trie-standardmap/src/lib.rs b/util/trie-standardmap/src/lib.rs deleted file mode 100644 index d7ee08ac46cc879366a7cadf8a87d7144efa00d4..0000000000000000000000000000000000000000 --- a/util/trie-standardmap/src/lib.rs +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Key-value datastore with a modified Merkle tree. - -extern crate ethcore_bytes as bytes; -extern crate ethereum_types; -extern crate keccak_hash; -extern crate rlp; - -use bytes::Bytes; -use ethereum_types::H256; -use keccak_hash::keccak; -use rlp::encode; - -/// Alphabet to use when creating words for insertion into tries. -pub enum Alphabet { - /// All values are allowed in each bytes of the key. - All, - /// Only a 6 values ('a' - 'f') are chosen to compose the key. - Low, - /// Quite a few values (around 32) are chosen to compose the key. - Mid, - /// A set of bytes given is used to compose the key. - Custom(Bytes), -} - -/// Means of determining the value. -pub enum ValueMode { - /// Same as the key. - Mirror, - /// Randomly (50:50) 1 or 32 byte randomly string. - Random, - /// RLP-encoded index. - Index, -} - -/// Standard test map for profiling tries. -pub struct StandardMap { - /// The alphabet to use for keys. - pub alphabet: Alphabet, - /// Minimum size of key. - pub min_key: usize, - /// Delta size of key. - pub journal_key: usize, - /// Mode of value generation. - pub value_mode: ValueMode, - /// Number of keys. - pub count: usize, -} - -impl StandardMap { - /// Get a bunch of random bytes, at least `min_count` bytes, at most `min_count` + `journal_count` bytes. - /// `seed` is mutated pseudoramdonly and used. - fn random_bytes(min_count: usize, journal_count: usize, seed: &mut H256) -> Vec { - assert!(min_count + journal_count <= 32); - *seed = keccak(&seed); - let r = min_count + (seed[31] as usize % (journal_count + 1)); - seed[0..r].to_vec() - } - - /// Get a random value. Equal chance of being 1 byte as of 32. `seed` is mutated pseudoramdonly and used. - fn random_value(seed: &mut H256) -> Bytes { - *seed = keccak(&seed); - match seed[0] % 2 { - 1 => vec![seed[31];1], - _ => seed.to_vec(), - } - } - - /// Get a random word of, at least `min_count` bytes, at most `min_count` + `journal_count` bytes. - /// Each byte is an item from `alphabet`. `seed` is mutated pseudoramdonly and used. - fn random_word(alphabet: &[u8], min_count: usize, journal_count: usize, seed: &mut H256) -> Vec { - assert!(min_count + journal_count <= 32); - *seed = keccak(&seed); - let r = min_count + (seed[31] as usize % (journal_count + 1)); - let mut ret: Vec = Vec::with_capacity(r); - for i in 0..r { - ret.push(alphabet[seed[i] as usize % alphabet.len()]); - } - ret - } - - /// Create the standard map (set of keys and values) for the object's fields. - pub fn make(&self) -> Vec<(Bytes, Bytes)> { - self.make_with(&mut H256::new()) - } - - /// Create the standard map (set of keys and values) for the object's fields, using the given seed. - pub fn make_with(&self, seed: &mut H256) -> Vec<(Bytes, Bytes)> { - let low = b"abcdef"; - let mid = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; - - let mut d: Vec<(Bytes, Bytes)> = Vec::new(); - for index in 0..self.count { - let k = match self.alphabet { - Alphabet::All => Self::random_bytes(self.min_key, self.journal_key, seed), - Alphabet::Low => Self::random_word(low, self.min_key, self.journal_key, seed), - Alphabet::Mid => Self::random_word(mid, self.min_key, self.journal_key, seed), - Alphabet::Custom(ref a) => Self::random_word(a, self.min_key, self.journal_key, seed), - }; - let v = match self.value_mode { - ValueMode::Mirror => k.clone(), - ValueMode::Random => Self::random_value(seed), - ValueMode::Index => encode(&index).into_vec(), - }; - d.push((k, v)) - } - d - } -} diff --git a/util/triehash-ethereum/Cargo.toml b/util/triehash-ethereum/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..d5b1b118aa3d8df40a09f341745752fc34380e47 --- /dev/null +++ b/util/triehash-ethereum/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "triehash-ethereum" +version = "0.2.0" +authors = ["Parity Technologies "] +description = "Trie-root helpers, ethereum style" +license = "GPL-3.0" + +[dependencies] +triehash = { git = "https://github.com/paritytech/parity-common" } +ethereum-types = "0.3" +keccak-hasher = { path = "../keccak-hasher" } \ No newline at end of file diff --git a/util/triehash-ethereum/src/lib.rs b/util/triehash-ethereum/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..7de77473c5b7d08e403847b19d5139773b7a1c12 --- /dev/null +++ b/util/triehash-ethereum/src/lib.rs @@ -0,0 +1,87 @@ +// 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 . + +//! Generates Keccak-flavoured trie roots. + +extern crate ethereum_types; +extern crate keccak_hasher; +extern crate triehash; + +use ethereum_types::H256; +use keccak_hasher::KeccakHasher; + +/// Generates a trie root hash for a vector of key-value tuples +pub fn trie_root(input: I) -> H256 +where + I: IntoIterator, + K: AsRef<[u8]> + Ord, + V: AsRef<[u8]>, +{ + triehash::trie_root::(input) +} + +/// Generates a key-hashed (secure) trie root hash for a vector of key-value tuples. +pub fn sec_trie_root(input: I) -> H256 +where + I: IntoIterator, + K: AsRef<[u8]>, + V: AsRef<[u8]>, +{ + triehash::sec_trie_root::(input) +} + +/// Generates a trie root hash for a vector of values +pub fn ordered_trie_root(input: I) -> H256 +where + I: IntoIterator, + V: AsRef<[u8]>, +{ + triehash::ordered_trie_root::(input) +} + +#[cfg(test)] +mod tests { + use super::{trie_root, sec_trie_root, ordered_trie_root}; + use triehash; + use keccak_hasher::KeccakHasher; + + #[test] + fn simple_test() { + assert_eq!(trie_root(vec![ + (b"A", b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" as &[u8]) + ]), "d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab".into()); + } + + #[test] + fn proxy_works() { + let input = vec![(b"A", b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" as &[u8])]; + assert_eq!( + trie_root(input.clone()), + triehash::trie_root::(input.clone()) + ); + + assert_eq!( + sec_trie_root(input.clone()), + triehash::sec_trie_root::(input.clone()) + ); + + let data = &["cake", "pie", "candy"]; + assert_eq!( + ordered_trie_root(data), + triehash::ordered_trie_root::(data) + ); + } +} \ No newline at end of file diff --git a/util/triehash/Cargo.toml b/util/triehash/Cargo.toml deleted file mode 100644 index ee42b9d8253efa6962efe8328fe9ce75ed117e85..0000000000000000000000000000000000000000 --- a/util/triehash/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "triehash" -version = "0.1.0" -authors = ["Parity Technologies "] -description = "in memory patricia trie operations" -license = "GPL-3.0" - -[dependencies] -elastic-array = "0.10" -rlp = { version = "0.2.1", path = "../rlp" } -ethereum-types = "0.3" -keccak-hash = { version = "0.1", path = "../hash" } - -[dev-dependencies] -trie-standardmap = { path = "../trie-standardmap" } diff --git a/util/triehash/benches/triehash.rs b/util/triehash/benches/triehash.rs deleted file mode 100644 index 505ea1223d985d2af6dd0fb31e789faf2f68b19a..0000000000000000000000000000000000000000 --- a/util/triehash/benches/triehash.rs +++ /dev/null @@ -1,147 +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 . - -#![feature(test)] - -extern crate ethereum_types; -extern crate keccak_hash; -extern crate test; -extern crate trie_standardmap; -extern crate triehash; - -use ethereum_types::H256; -use keccak_hash::keccak; -use test::Bencher; -use trie_standardmap::{Alphabet, ValueMode, StandardMap}; -use triehash::trie_root; - -fn random_word(alphabet: &[u8], min_count: usize, diff_count: usize, seed: &mut H256) -> Vec { - assert!(min_count + diff_count <= 32); - *seed = keccak(&seed); - let r = min_count + (seed[31] as usize % (diff_count + 1)); - let mut ret: Vec = Vec::with_capacity(r); - for i in 0..r { - ret.push(alphabet[seed[i] as usize % alphabet.len()]); - } - ret -} - -fn random_bytes(min_count: usize, diff_count: usize, seed: &mut H256) -> Vec { - assert!(min_count + diff_count <= 32); - *seed = keccak(&seed); - let r = min_count + (seed[31] as usize % (diff_count + 1)); - seed[0..r].to_vec() -} - -fn random_value(seed: &mut H256) -> Vec { - *seed = keccak(&seed); - match seed[0] % 2 { - 1 => vec![seed[31];1], - _ => seed.to_vec(), - } -} - -#[bench] -fn triehash_insertions_32_mir_1k(b: &mut Bencher) { - let st = StandardMap { - alphabet: Alphabet::All, - min_key: 32, - journal_key: 0, - value_mode: ValueMode::Mirror, - count: 1000, - }; - let d = st.make(); - b.iter(&mut ||{ - trie_root(d.clone()).clone(); - }); -} - -#[bench] -fn triehash_insertions_32_ran_1k(b: &mut Bencher) { - let st = StandardMap { - alphabet: Alphabet::All, - min_key: 32, - journal_key: 0, - value_mode: ValueMode::Random, - count: 1000, - }; - let d = st.make(); - b.iter(&mut ||{ - trie_root(d.clone()).clone(); - }); -} - -#[bench] -fn triehash_insertions_six_high(b: &mut Bencher) { - let mut d: Vec<(Vec, Vec)> = Vec::new(); - let mut seed = H256::new(); - for _ in 0..1000 { - let k = random_bytes(6, 0, &mut seed); - let v = random_value(&mut seed); - d.push((k, v)) - } - - b.iter(&||{ - trie_root(d.clone()); - }) -} - -#[bench] -fn triehash_insertions_six_mid(b: &mut Bencher) { - let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; - let mut d: Vec<(Vec, Vec)> = Vec::new(); - let mut seed = H256::new(); - for _ in 0..1000 { - let k = random_word(alphabet, 6, 0, &mut seed); - let v = random_value(&mut seed); - d.push((k, v)) - } - b.iter(||{ - trie_root(d.clone()); - }) -} - -#[bench] -fn triehash_insertions_random_mid(b: &mut Bencher) { - let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; - let mut d: Vec<(Vec, Vec)> = Vec::new(); - let mut seed = H256::new(); - for _ in 0..1000 { - let k = random_word(alphabet, 1, 5, &mut seed); - let v = random_value(&mut seed); - d.push((k, v)) - } - - b.iter(||{ - trie_root(d.clone()); - }) -} - -#[bench] -fn triehash_insertions_six_low(b: &mut Bencher) { - let alphabet = b"abcdef"; - let mut d: Vec<(Vec, Vec)> = Vec::new(); - let mut seed = H256::new(); - for _ in 0..1000 { - let k = random_word(alphabet, 6, 0, &mut seed); - let v = random_value(&mut seed); - d.push((k, v)) - } - - b.iter(||{ - trie_root(d.clone()); - }) -} diff --git a/util/triehash/src/lib.rs b/util/triehash/src/lib.rs deleted file mode 100644 index 7f20d3915e145fd23d8b0266ad3687d4cc26c0ac..0000000000000000000000000000000000000000 --- a/util/triehash/src/lib.rs +++ /dev/null @@ -1,378 +0,0 @@ -// Copyright 2015-2017 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 . - -//! Generetes trie root. -//! -//! This module should be used to generate trie root hash. - -extern crate elastic_array; -extern crate ethereum_types; -extern crate keccak_hash as hash; -extern crate rlp; - -use std::collections::BTreeMap; -use std::cmp; -use elastic_array::{ElasticArray4, ElasticArray8}; -use ethereum_types::H256; -use hash::keccak; -use rlp::RlpStream; - -fn shared_prefix_len(first: &[T], second: &[T]) -> usize { - let len = cmp::min(first.len(), second.len()); - (0..len).take_while(|&i| first[i] == second[i]).count() -} - -/// Generates a trie root hash for a vector of values -/// -/// ```rust -/// extern crate triehash; -/// use triehash::ordered_trie_root; -/// -/// fn main() { -/// let v = &["doe", "reindeer"]; -/// let root = "e766d5d51b89dc39d981b41bda63248d7abce4f0225eefd023792a540bcffee3"; -/// assert_eq!(ordered_trie_root(v), root.into()); -/// } -/// ``` -pub fn ordered_trie_root(input: I) -> H256 - where I: IntoIterator, - A: AsRef<[u8]>, -{ - let gen_input: Vec<_> = input - // first put elements into btree to sort them by nibbles - // optimize it later - .into_iter() - .enumerate() - .map(|(i, slice)| (rlp::encode(&i), slice)) - .collect::>() - // then move them to a vector - .into_iter() - .map(|(k, v)| (as_nibbles(&k), v) ) - .collect(); - - gen_trie_root(&gen_input) -} - -/// Generates a trie root hash for a vector of key-values -/// -/// ```rust -/// extern crate triehash; -/// use triehash::trie_root; -/// -/// fn main() { -/// let v = vec![ -/// ("doe", "reindeer"), -/// ("dog", "puppy"), -/// ("dogglesworth", "cat"), -/// ]; -/// -/// let root = "8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3"; -/// assert_eq!(trie_root(v), root.into()); -/// } -/// ``` -pub fn trie_root(input: I) -> H256 - where I: IntoIterator, - A: AsRef<[u8]> + Ord, - B: AsRef<[u8]>, -{ - let gen_input: Vec<_> = input - // first put elements into btree to sort them and to remove duplicates - .into_iter() - .collect::>() - // then move them to a vector - .into_iter() - .map(|(k, v)| (as_nibbles(k.as_ref()), v) ) - .collect(); - - gen_trie_root(&gen_input) -} - -/// Generates a key-hashed (secure) trie root hash for a vector of key-values. -/// -/// ```rust -/// extern crate triehash; -/// use triehash::sec_trie_root; -/// -/// fn main() { -/// let v = vec![ -/// ("doe", "reindeer"), -/// ("dog", "puppy"), -/// ("dogglesworth", "cat"), -/// ]; -/// -/// let root = "d4cd937e4a4368d7931a9cf51686b7e10abb3dce38a39000fd7902a092b64585"; -/// assert_eq!(sec_trie_root(v), root.into()); -/// } -/// ``` -pub fn sec_trie_root(input: I) -> H256 - where I: IntoIterator, - A: AsRef<[u8]>, - B: AsRef<[u8]>, -{ - let gen_input: Vec<_> = input - // first put elements into btree to sort them and to remove duplicates - .into_iter() - .map(|(k, v)| (keccak(k), v)) - .collect::>() - // then move them to a vector - .into_iter() - .map(|(k, v)| (as_nibbles(&k), v) ) - .collect(); - - gen_trie_root(&gen_input) -} - -fn gen_trie_root, B: AsRef<[u8]>>(input: &[(A, B)]) -> H256 { - let mut stream = RlpStream::new(); - hash256rlp(input, 0, &mut stream); - keccak(stream.out()) -} - -/// Hex-prefix Notation. First nibble has flags: oddness = 2^0 & termination = 2^1. -/// -/// The "termination marker" and "leaf-node" specifier are completely equivalent. -/// -/// Input values are in range `[0, 0xf]`. -/// -/// ```markdown -/// [0,0,1,2,3,4,5] 0x10012345 // 7 > 4 -/// [0,1,2,3,4,5] 0x00012345 // 6 > 4 -/// [1,2,3,4,5] 0x112345 // 5 > 3 -/// [0,0,1,2,3,4] 0x00001234 // 6 > 3 -/// [0,1,2,3,4] 0x101234 // 5 > 3 -/// [1,2,3,4] 0x001234 // 4 > 3 -/// [0,0,1,2,3,4,5,T] 0x30012345 // 7 > 4 -/// [0,0,1,2,3,4,T] 0x20001234 // 6 > 4 -/// [0,1,2,3,4,5,T] 0x20012345 // 6 > 4 -/// [1,2,3,4,5,T] 0x312345 // 5 > 3 -/// [1,2,3,4,T] 0x201234 // 4 > 3 -/// ``` -fn hex_prefix_encode(nibbles: &[u8], leaf: bool) -> ElasticArray4 { - let inlen = nibbles.len(); - let oddness_factor = inlen % 2; - let mut res = ElasticArray4::new(); - - let first_byte = { - let mut bits = ((inlen as u8 & 1) + (2 * leaf as u8)) << 4; - if oddness_factor == 1 { - bits += nibbles[0]; - } - bits - }; - - res.push(first_byte); - - let mut offset = oddness_factor; - while offset < inlen { - let byte = (nibbles[offset] << 4) + nibbles[offset + 1]; - res.push(byte); - offset += 2; - } - - res -} - -/// Converts slice of bytes to nibbles. -fn as_nibbles(bytes: &[u8]) -> ElasticArray8 { - let mut res = ElasticArray8::new(); - for i in 0..bytes.len() { - let byte = bytes[i]; - res.push(byte >> 4); - res.push(byte & 0b1111); - } - res -} - -fn hash256rlp, B: AsRef<[u8]>>(input: &[(A, B)], pre_len: usize, stream: &mut RlpStream) { - let inlen = input.len(); - - // in case of empty slice, just append empty data - if inlen == 0 { - stream.append_empty_data(); - return; - } - - // take slices - let key: &[u8] = &input[0].0.as_ref(); - let value: &[u8] = &input[0].1.as_ref(); - - // if the slice contains just one item, append the suffix of the key - // and then append value - if inlen == 1 { - stream.begin_list(2); - stream.append(&&*hex_prefix_encode(&key[pre_len..], true)); - stream.append(&value); - return; - } - - // get length of the longest shared prefix in slice keys - let shared_prefix = input.iter() - // skip first element - .skip(1) - // get minimum number of shared nibbles between first and each successive - .fold(key.len(), | acc, &(ref k, _) | { - cmp::min(shared_prefix_len(key, k.as_ref()), acc) - }); - - // if shared prefix is higher than current prefix append its - // new part of the key to the stream - // then recursively append suffixes of all items who had this key - if shared_prefix > pre_len { - stream.begin_list(2); - stream.append(&&*hex_prefix_encode(&key[pre_len..shared_prefix], false)); - hash256aux(input, shared_prefix, stream); - return; - } - - // an item for every possible nibble/suffix - // + 1 for data - stream.begin_list(17); - - // if first key len is equal to prefix_len, move to next element - let mut begin = match pre_len == key.len() { - true => 1, - false => 0 - }; - - // iterate over all possible nibbles - for i in 0..16 { - // cout how many successive elements have same next nibble - let len = match begin < input.len() { - true => input[begin..].iter() - .take_while(| pair | pair.0.as_ref()[pre_len] == i ) - .count(), - false => 0 - }; - - // if at least 1 successive element has the same nibble - // append their suffixes - match len { - 0 => { stream.append_empty_data(); }, - _ => hash256aux(&input[begin..(begin + len)], pre_len + 1, stream) - } - begin += len; - } - - // if fist key len is equal prefix, append its value - match pre_len == key.len() { - true => { stream.append(&value); }, - false => { stream.append_empty_data(); } - }; -} - -fn hash256aux, B: AsRef<[u8]>>(input: &[(A, B)], pre_len: usize, stream: &mut RlpStream) { - let mut s = RlpStream::new(); - hash256rlp(input, pre_len, &mut s); - let out = s.out(); - match out.len() { - 0...31 => stream.append_raw(&out, 1), - _ => stream.append(&keccak(out)) - }; -} - - -#[test] -fn test_nibbles() { - let v = vec![0x31, 0x23, 0x45]; - let e = vec![3, 1, 2, 3, 4, 5]; - assert_eq!(as_nibbles(&v), e); - - // A => 65 => 0x41 => [4, 1] - let v: Vec = From::from("A"); - let e = vec![4, 1]; - assert_eq!(as_nibbles(&v), e); -} - - -#[cfg(test)] -mod tests { - use super::{trie_root, shared_prefix_len, hex_prefix_encode}; - - #[test] - fn test_hex_prefix_encode() { - let v = vec![0, 0, 1, 2, 3, 4, 5]; - let e = vec![0x10, 0x01, 0x23, 0x45]; - let h = hex_prefix_encode(&v, false); - assert_eq!(h, e); - - let v = vec![0, 1, 2, 3, 4, 5]; - let e = vec![0x00, 0x01, 0x23, 0x45]; - let h = hex_prefix_encode(&v, false); - assert_eq!(h, e); - - let v = vec![0, 1, 2, 3, 4, 5]; - let e = vec![0x20, 0x01, 0x23, 0x45]; - let h = hex_prefix_encode(&v, true); - assert_eq!(h, e); - - let v = vec![1, 2, 3, 4, 5]; - let e = vec![0x31, 0x23, 0x45]; - let h = hex_prefix_encode(&v, true); - assert_eq!(h, e); - - let v = vec![1, 2, 3, 4]; - let e = vec![0x00, 0x12, 0x34]; - let h = hex_prefix_encode(&v, false); - assert_eq!(h, e); - - let v = vec![4, 1]; - let e = vec![0x20, 0x41]; - let h = hex_prefix_encode(&v, true); - assert_eq!(h, e); - } - - #[test] - fn simple_test() { - assert_eq!(trie_root(vec![ - (b"A", b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" as &[u8]) - ]), "d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab".into()); - } - - #[test] - fn test_triehash_out_of_order() { - assert!(trie_root(vec![ - (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), - (vec![0x81u8, 0x23], vec![0x81u8, 0x23]), - (vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]), - ]) == - trie_root(vec![ - (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), - (vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]), - (vec![0x81u8, 0x23], vec![0x81u8, 0x23]), - ])); - } - - #[test] - fn test_shared_prefix() { - let a = vec![1,2,3,4,5,6]; - let b = vec![4,2,3,4,5,6]; - assert_eq!(shared_prefix_len(&a, &b), 0); - } - - #[test] - fn test_shared_prefix2() { - let a = vec![1,2,3,3,5]; - let b = vec![1,2,3]; - assert_eq!(shared_prefix_len(&a, &b), 3); - } - - #[test] - fn test_shared_prefix3() { - let a = vec![1,2,3,4,5,6]; - let b = vec![1,2,3,4,5,6]; - assert_eq!(shared_prefix_len(&a, &b), 6); - } -} diff --git a/util/unexpected/src/lib.rs b/util/unexpected/src/lib.rs index 4cf8448bd491dcec1b337173914b68ca4f8a8314..77d4035a647d07e0893c81f5d420d2d38dc7ff29 100644 --- a/util/unexpected/src/lib.rs +++ b/util/unexpected/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/using_queue/src/lib.rs b/util/using_queue/src/lib.rs index 03862e9c8a573f1233fd959038ed172346cb3f86..b2c94b3f4a42b9ea6d9ce38f3cf7597e680eb05f 100644 --- a/util/using_queue/src/lib.rs +++ b/util/using_queue/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -19,7 +19,7 @@ /// Special queue-like datastructure that includes the notion of /// usage to avoid items that were queued but never used from making it into /// the queue. -pub struct UsingQueue where T: Clone { +pub struct UsingQueue { /// Not yet being sealed by a miner, but if one asks for work, we'd prefer they do this. pending: Option, /// Currently being sealed by miners. @@ -36,7 +36,7 @@ pub enum GetAction { Clone, } -impl UsingQueue where T: Clone { +impl UsingQueue { /// Create a new struct with a maximum size of `max_size`. pub fn new(max_size: usize) -> UsingQueue { UsingQueue { @@ -88,12 +88,12 @@ impl UsingQueue where T: Clone { /// Returns `Some` item which is the first that `f` returns `true` with a reference to it /// as a parameter or `None` if no such item exists in the queue. - fn clone_used_if

(&mut self, predicate: P) -> Option where P: Fn(&T) -> bool { + fn clone_used_if

(&mut self, predicate: P) -> Option where P: Fn(&T) -> bool, T: Clone { self.in_use.iter().find(|r| predicate(r)).cloned() } /// Fork-function for `take_used_if` and `clone_used_if`. - pub fn get_used_if

(&mut self, action: GetAction, predicate: P) -> Option where P: Fn(&T) -> bool { + pub fn get_used_if

(&mut self, action: GetAction, predicate: P) -> Option where P: Fn(&T) -> bool, T: Clone { match action { GetAction::Take => self.take_used_if(predicate), GetAction::Clone => self.clone_used_if(predicate), @@ -104,7 +104,7 @@ impl UsingQueue where T: Clone { /// a parameter, otherwise `None`. /// Will not destroy a block if a reference to it has previously been returned by `use_last_ref`, /// but rather clone it. - pub fn pop_if

(&mut self, predicate: P) -> Option where P: Fn(&T) -> bool { + pub fn pop_if

(&mut self, predicate: P) -> Option where P: Fn(&T) -> bool, T: Clone { // a bit clumsy - TODO: think about a nicer way of expressing this. if let Some(x) = self.pending.take() { if predicate(&x) { diff --git a/util/version/Cargo.toml b/util/version/Cargo.toml index 297211b2bd0775b32c553a3e85c2be36a5286cf1..fc4cdece6dbafde58622b03a5c1c79d537be4d9a 100644 --- a/util/version/Cargo.toml +++ b/util/version/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "parity-version" # NOTE: this value is used for Parity version string (via env CARGO_PKG_VERSION) -version = "1.12.0" +version = "2.1.0" authors = ["Parity Technologies "] build = "build.rs" @@ -12,18 +12,17 @@ build = "build.rs" # Used by auto-updater and for Parity version string. track = "nightly" -# Indicates a critical release in this track (i.e. consensus issue) -critical = false - -# Latest supported fork blocks for various networks. Used ONLY by auto-updater. -[package.metadata.forks] -foundation = 4370000 -ropsten = 10 -kovan = 6600000 +# Network specific settings, used ONLY by auto-updater. +# Latest supported fork blocks. +# Indicates a critical release in this track (i.e. consensus issue). +[package.metadata.networks] +foundation = { forkBlock = 4370000, critical = false } +ropsten = { forkBlock = 10, critical = false } +kovan = { forkBlock = 6600000, critical = false } [dependencies] -ethcore-bytes = { path = "../bytes" } -rlp = { path = "../rlp" } +parity-bytes = { git = "https://github.com/paritytech/parity-common" } +rlp = { git = "https://github.com/paritytech/parity-common" } target_info = "0.1" [build-dependencies] diff --git a/util/version/build.rs b/util/version/build.rs index 47c0e128f2244889aadb3d4e29d70fc20dbf5e04..a367296a5fb5eda6a656f3dc20fecadc38bc6cf1 100644 --- a/util/version/build.rs +++ b/util/version/build.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/version/src/lib.rs b/util/version/src/lib.rs index 6c56bfb7e6817a9f6669fe060bd020d087ef39a3..a7452e0ce93c770b2d3a87e4883a7452ab6a29da 100644 --- a/util/version/src/lib.rs +++ b/util/version/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Parity version specific information. extern crate target_info; -extern crate ethcore_bytes as bytes; +extern crate parity_bytes as bytes; extern crate rlp; use target_info::Target; @@ -54,7 +54,7 @@ pub fn version() -> String { let sha3_dash = if sha3.is_empty() { "" } else { "-" }; let commit_date = vergen::commit_date().replace("-", ""); let date_dash = if commit_date.is_empty() { "" } else { "-" }; - format!("Parity/v{}-{}{}{}{}{}/{}/rustc{}", env!("CARGO_PKG_VERSION"), THIS_TRACK, sha3_dash, sha3, date_dash, commit_date, platform(), generated::rustc_version()) + format!("Parity-Ethereum/v{}-{}{}{}{}{}/{}/rustc{}", env!("CARGO_PKG_VERSION"), THIS_TRACK, sha3_dash, sha3, date_dash, commit_date, platform(), generated::rustc_version()) } /// Get the standard version data for this software. @@ -65,7 +65,7 @@ pub fn version_data() -> Bytes { (env!("CARGO_PKG_VERSION_MINOR").parse::().expect("Environment variables are known to be valid; qed") << 8) + env!("CARGO_PKG_VERSION_PATCH").parse::().expect("Environment variables are known to be valid; qed"); s.append(&v); - s.append(&"Parity"); + s.append(&"Parity-Ethereum"); s.append(&generated::rustc_version()); s.append(&&Target::os()[0..2]); s.out() diff --git a/whisper/Cargo.toml b/whisper/Cargo.toml index e503a74fd6d9094d27868463a022dc73e64169e0..44882b4f54132fd8889550f4afbc4bab9b4f6eb0 100644 --- a/whisper/Cargo.toml +++ b/whisper/Cargo.toml @@ -9,15 +9,15 @@ bitflags = "0.9" byteorder = "1.0.0" ethereum-types = "0.3" ethcore-network = { path = "../util/network" } -ethcore-crypto = { path = "../ethcore/crypto" } +parity-crypto = { git = "https://github.com/paritytech/parity-common" } ethkey = { path = "../ethkey" } 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" } +rlp = { git = "https://github.com/paritytech/parity-common" } serde = "1.0" serde_derive = "1.0" serde_json = "1.0" diff --git a/whisper/cli/src/main.rs b/whisper/cli/src/main.rs index 6f3aec8594e165d020c860a58d01bffcb8a0f88e..d09ff307cf41e90d21c13834c9771bae5ea82819 100644 --- a/whisper/cli/src/main.rs +++ b/whisper/cli/src/main.rs @@ -184,17 +184,18 @@ impl fmt::Display for Error { } fn main() { - panic_hook::set(); + panic_hook::set_abort(); match execute(env::args()) { Ok(_) => { println!("whisper-cli terminated"); process::exit(1); - } + }, + Err(Error::Docopt(ref e)) => e.exit(), Err(err) => { println!("{}", err); process::exit(1); - }, + } } } diff --git a/whisper/src/lib.rs b/whisper/src/lib.rs index 85ab55e0f4637b61b6fa0fed559668ad937f6606..66d8d1b7321451a939e77086551e0c648e30ca8d 100644 --- a/whisper/src/lib.rs +++ b/whisper/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -18,7 +18,7 @@ //! interface. extern crate byteorder; -extern crate ethcore_crypto as crypto; +extern crate parity_crypto as crypto; extern crate ethcore_network as network; extern crate ethereum_types; extern crate ethkey; diff --git a/whisper/src/message.rs b/whisper/src/message.rs index d0de9af4b5aa784d0b3eac3f1b39d0ea24b73c29..95c2112551382e1dcf5a5faffadc32aa0f312ef2 100644 --- a/whisper/src/message.rs +++ b/whisper/src/message.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/whisper/src/net/mod.rs b/whisper/src/net/mod.rs index c462baa9d72236d7d7870cffe2cb6d5497a39bbd..6ec3b08a548540fbf618ee5c999065368cbf0da6 100644 --- a/whisper/src/net/mod.rs +++ b/whisper/src/net/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -23,7 +23,7 @@ use std::time::{Duration, SystemTime}; use std::sync::Arc; use ethereum_types::{H256, H512}; -use network::{self, HostInfo, NetworkContext, NodeId, PeerId, ProtocolId, TimerToken}; +use network::{self, NetworkContext, NodeId, PeerId, ProtocolId, TimerToken}; use ordered_float::OrderedFloat; use parking_lot::{Mutex, RwLock}; use rlp::{DecoderError, RlpStream, Rlp}; @@ -423,7 +423,6 @@ pub struct Network { messages: Arc>, handler: T, peers: RwLock>>, - node_key: RwLock, } // public API. @@ -434,7 +433,6 @@ impl Network { messages: Arc::new(RwLock::new(Messages::new(messages_size_bytes))), handler: handler, peers: RwLock::new(HashMap::new()), - node_key: RwLock::new(Default::default()), } } @@ -685,12 +683,10 @@ impl Network { } impl ::network::NetworkProtocolHandler for Network { - fn initialize(&self, io: &NetworkContext, host_info: &HostInfo) { + fn initialize(&self, io: &NetworkContext) { // set up broadcast timer (< 1s) io.register_timer(RALLY_TOKEN, RALLY_TIMEOUT) .expect("Failed to initialize message rally timer"); - - *self.node_key.write() = host_info.id().clone(); } fn read(&self, io: &NetworkContext, peer: &PeerId, packet_id: u8, data: &[u8]) { @@ -720,7 +716,7 @@ impl ::network::NetworkProtocolHandler for Network { pub struct ParityExtensions; impl ::network::NetworkProtocolHandler for ParityExtensions { - fn initialize(&self, _io: &NetworkContext, _host_info: &HostInfo) { } + fn initialize(&self, _io: &NetworkContext) { } fn read(&self, _io: &NetworkContext, _peer: &PeerId, _id: u8, _msg: &[u8]) { } diff --git a/whisper/src/net/tests.rs b/whisper/src/net/tests.rs index 51c9c00ce272653f8c8db7dd110fc8943b79b3e2..15aba5c3eed077465477749b0591ad63057da81b 100644 --- a/whisper/src/net/tests.rs +++ b/whisper/src/net/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/whisper/src/rpc/crypto.rs b/whisper/src/rpc/crypto.rs index 667656d6bf321fde92547e01ae322b8462328ec1..a796a0613cced52227d4f701c1c6180c3328715b 100644 --- a/whisper/src/rpc/crypto.rs +++ b/whisper/src/rpc/crypto.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/whisper/src/rpc/filter.rs b/whisper/src/rpc/filter.rs index 8d125174ed748e065bf693a701ce23d358572270..d1b9c4c1cc6b1b760f8f1446ddc50c177132912c 100644 --- a/whisper/src/rpc/filter.rs +++ b/whisper/src/rpc/filter.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/whisper/src/rpc/key_store.rs b/whisper/src/rpc/key_store.rs index 1fb4e264ace64b507d1e20a0b0148f028c0ca14c..a63ef8652c45ee96fb1accae4165e361efcdb863 100644 --- a/whisper/src/rpc/key_store.rs +++ b/whisper/src/rpc/key_store.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/whisper/src/rpc/mod.rs b/whisper/src/rpc/mod.rs index 7daa3f45590e8b2bcf1a97f7dafed02491cd32e2..7406d6421d331d7b826461ea39db814a07dfead0 100644 --- a/whisper/src/rpc/mod.rs +++ b/whisper/src/rpc/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/whisper/src/rpc/payload.rs b/whisper/src/rpc/payload.rs index 75d24bd7cfe70778f4233742bf19232f210e85d5..5884cdee98080784ae10e81a5cd8618b5a663983 100644 --- a/whisper/src/rpc/payload.rs +++ b/whisper/src/rpc/payload.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -184,7 +184,6 @@ pub fn decode(payload: &[u8]) -> Result { } }; - if next_slice(1)?[0] != STANDARD_PAYLOAD_VERSION { return Err("unknown payload version."); } diff --git a/whisper/src/rpc/types.rs b/whisper/src/rpc/types.rs index 9598f48bf8e7473607482a73e4bc5fc9363e2a65..3d132c73ccede7ff0a551ea76a428ae9c36db078 100644 --- a/whisper/src/rpc/types.rs +++ b/whisper/src/rpc/types.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/windows/ptray/ptray.cpp b/windows/ptray/ptray.cpp deleted file mode 100644 index 8fc29880e9eb8114e6d59df41199d1343c7f6fe0..0000000000000000000000000000000000000000 --- a/windows/ptray/ptray.cpp +++ /dev/null @@ -1,361 +0,0 @@ -// Copyright 2015-2017 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 . - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "resource.h" - -#pragma comment(lib, "shlwapi.lib") - -#define MAX_LOADSTRING 100 -#define IDM_EXIT 100 -#define IDM_OPEN 101 -#define IDM_AUTOSTART 102 -#define WM_USER_SHELLICON WM_USER + 1 - -HANDLE parityHandle = INVALID_HANDLE_VALUE; -DWORD parityProcId = 0; -NOTIFYICONDATA nidApp; -WCHAR szTitle[MAX_LOADSTRING]; -WCHAR szWindowClass[MAX_LOADSTRING]; -LPCWCHAR commandLineFiltered = L""; - -LPCWSTR cParityExe = _T("parity.exe"); - -ATOM MyRegisterClass(HINSTANCE hInstance); -bool InitInstance(HINSTANCE, int, LPWSTR cmdLine); -LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); -void KillParity(); -void OpenUI(); -bool ParityIsRunning(); -bool AutostartEnabled(); -void EnableAutostart(bool enable); - -bool GetParityExePath(TCHAR* dest, size_t destSize) -{ - if (!dest || MAX_PATH > destSize) - return false; - GetModuleFileName(NULL, dest, (DWORD)destSize); - if (!PathRemoveFileSpec(dest)) - return false; - return PathAppend(dest, _T("parity.exe")) == TRUE; -} - -bool GetTrayExePath(TCHAR* dest, size_t destSize) -{ - if (!dest || MAX_PATH > destSize) - return false; - GetModuleFileName(NULL, dest, (DWORD)destSize); - return true; -} - -int APIENTRY wWinMain(_In_ HINSTANCE hInstance, - _In_opt_ HINSTANCE hPrevInstance, - _In_ LPWSTR lpCmdLine, - _In_ int nCmdShow) -{ - UNREFERENCED_PARAMETER(hPrevInstance); - UNREFERENCED_PARAMETER(lpCmdLine); - - CreateMutex(0, FALSE, _T("Local\\ParityTray")); - if (GetLastError() == ERROR_ALREADY_EXISTS) { - // open the UI - OpenUI(); - return 0; - } - - LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); - LoadStringW(hInstance, IDC_PTRAY, szWindowClass, MAX_LOADSTRING); - MyRegisterClass(hInstance); - - if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) - return FALSE; - - HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_PTRAY)); - MSG msg; - // Main message loop: - while (GetMessage(&msg, nullptr, 0, 0)) - { - if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - - return (int)msg.wParam; -} - -ATOM MyRegisterClass(HINSTANCE hInstance) -{ - WNDCLASSEXW wcex; - - wcex.cbSize = sizeof(WNDCLASSEX); - - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = WndProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = hInstance; - wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PTRAY)); - wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); - wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_PTRAY); - wcex.lpszClassName = szWindowClass; - wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); - - return RegisterClassExW(&wcex); -} - - -bool InitInstance(HINSTANCE hInstance, int nCmdShow, LPWSTR cmdLine) -{ - if (lstrlen(cmdLine) > 0) - { - int commandLineArgs = 0; - LPWSTR* commandLine = CommandLineToArgvW(cmdLine, &commandLineArgs); - LPWSTR filteredArgs = new WCHAR[lstrlen(cmdLine) + 2]; - filteredArgs[0] = '\0'; - for (int i = 0; i < commandLineArgs; i++) - { - // Remove "ui" from command line - if (lstrcmp(commandLine[i], L"ui") != 0) - { - lstrcat(filteredArgs, commandLine[i]); - lstrcat(filteredArgs, L" "); - } - } - commandLineFiltered = filteredArgs; - } - - // Check if already running - PROCESSENTRY32 entry; - entry.dwSize = sizeof(PROCESSENTRY32); - - HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); - if (Process32First(snapshot, &entry) == TRUE) - { - while (Process32Next(snapshot, &entry) == TRUE) - { - if (lstrcmp(entry.szExeFile, cParityExe) == 0) - { - parityHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID); - parityProcId = entry.th32ProcessID; - break; - } - } - } - - CloseHandle(snapshot); - - if (parityHandle == INVALID_HANDLE_VALUE) - { - // Launch parity - TCHAR path[MAX_PATH] = { 0 }; - if (!GetParityExePath(path, MAX_PATH)) - return false; - - PROCESS_INFORMATION procInfo = { 0 }; - STARTUPINFO startupInfo = { sizeof(STARTUPINFO) }; - - LPWSTR cmd = new WCHAR[lstrlen(cmdLine) + lstrlen(path) + 2]; - lstrcpy(cmd, path); - lstrcat(cmd, _T(" ")); - lstrcat(cmd, cmdLine); - if (!CreateProcess(nullptr, cmd, nullptr, nullptr, false, CREATE_NO_WINDOW, nullptr, nullptr, &startupInfo, &procInfo)) - return false; - delete[] cmd; - parityHandle = procInfo.hProcess; - parityProcId = procInfo.dwProcessId; - } - - HWND hWnd = CreateWindowW(szWindowClass, szTitle, 0, - CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr); - - if (!hWnd) - return false; - - HICON hMainIcon = LoadIcon(hInstance, (LPCTSTR)MAKEINTRESOURCE(IDI_PTRAY)); - - nidApp.cbSize = sizeof(NOTIFYICONDATA); // sizeof the struct in bytes - nidApp.hWnd = (HWND)hWnd; //handle of the window which will process this app. messages - nidApp.uID = IDI_PTRAY; //ID of the icon that willl appear in the system tray - nidApp.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; //ORing of all the flags - nidApp.hIcon = hMainIcon; // handle of the Icon to be displayed, obtained from LoadIcon - nidApp.uCallbackMessage = WM_USER_SHELLICON; - LoadString(hInstance, IDS_CONTROL_PARITY, nidApp.szTip, MAX_LOADSTRING); - Shell_NotifyIcon(NIM_ADD, &nidApp); - - SetTimer(hWnd, 0, 1000, nullptr); - return true; - -} - -LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - case WM_USER_SHELLICON: - // systray msg callback - POINT lpClickPoint; - switch (LOWORD(lParam)) - { - case WM_LBUTTONDOWN: - OpenUI(); - break; - case WM_RBUTTONDOWN: - UINT uFlag = MF_BYPOSITION | MF_STRING; - GetCursorPos(&lpClickPoint); - HMENU hPopMenu = CreatePopupMenu(); - InsertMenu(hPopMenu, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING, IDM_OPEN, _T("Open")); - InsertMenu(hPopMenu, 0xFFFFFFFF, MF_SEPARATOR | MF_BYPOSITION, 0, nullptr); - InsertMenu(hPopMenu, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING, IDM_AUTOSTART, _T("Start at Login")); - InsertMenu(hPopMenu, 0xFFFFFFFF, MF_SEPARATOR | MF_BYPOSITION, 0, nullptr); - InsertMenu(hPopMenu, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING, IDM_EXIT, _T("Exit")); - bool autoStart = AutostartEnabled(); - CheckMenuItem(hPopMenu, IDM_AUTOSTART, autoStart ? MF_CHECKED : autoStart); - - SetForegroundWindow(hWnd); - TrackPopupMenu(hPopMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_BOTTOMALIGN, lpClickPoint.x, lpClickPoint.y, 0, hWnd, NULL); - return TRUE; - - } - break; - case WM_COMMAND: - { - int wmId = LOWORD(wParam); - // Parse the menu selections: - switch (wmId) - { - case IDM_EXIT: - DestroyWindow(hWnd); - break; - case IDM_OPEN: - OpenUI(); - break; - case IDM_AUTOSTART: - { - bool autoStart = AutostartEnabled(); - EnableAutostart(!autoStart); - } - break; - default: - return DefWindowProc(hWnd, message, wParam, lParam); - } - } - break; - case WM_DESTROY: - Shell_NotifyIcon(NIM_DELETE, &nidApp); - KillParity(); - PostQuitMessage(0); - break; - case WM_TIMER: - if (!ParityIsRunning()) - DestroyWindow(hWnd); - default: - return DefWindowProc(hWnd, message, wParam, lParam); - } - return 0; -} - -void KillParity() -{ - DWORD procId = parityProcId; - //This does not require the console window to be visible. - if (AttachConsole(procId)) - { - // Disable Ctrl-C handling for our program - SetConsoleCtrlHandler(nullptr, true); - GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); - FreeConsole(); - - //Re-enable Ctrl-C handling or any subsequently started - //programs will inherit the disabled state. - SetConsoleCtrlHandler(nullptr, false); - } - WaitForSingleObject(parityHandle, INFINITE); -} - -bool ParityIsRunning() -{ - return WaitForSingleObject(parityHandle, 0) == WAIT_TIMEOUT; -} - -void OpenUI() -{ - // Launch parity - TCHAR path[MAX_PATH] = { 0 }; - if (!GetParityExePath(path, MAX_PATH)) - return; - - PROCESS_INFORMATION procInfo = { 0 }; - STARTUPINFO startupInfo = { sizeof(STARTUPINFO) }; - - LPWSTR args = new WCHAR[lstrlen(commandLineFiltered) + MAX_PATH + 2]; - lstrcpy(args, L"parity.exe "); - lstrcat(args, commandLineFiltered); - lstrcat(args, L" ui"); - CreateProcess(path, args, nullptr, nullptr, false, CREATE_NO_WINDOW, nullptr, nullptr, &startupInfo, &procInfo); -} - -bool AutostartEnabled() { - HKEY hKey; - LONG lRes = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_READ, &hKey); - if (lRes != ERROR_SUCCESS) - return false; - - WCHAR szBuffer[512]; - DWORD dwBufferSize = sizeof(szBuffer); - ULONG nError; - nError = RegQueryValueExW(hKey, L"Parity", 0, nullptr, (LPBYTE)szBuffer, &dwBufferSize); - if (ERROR_SUCCESS != nError) - return false; - return true; -} - -void EnableAutostart(bool enable) { - HKEY hKey; - LONG lRes = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_WRITE, &hKey); - if (lRes != ERROR_SUCCESS) - return; - - if (enable) - { - LPWSTR args = new WCHAR[lstrlen(commandLineFiltered) + MAX_PATH + 2]; - if (GetTrayExePath(args, MAX_PATH)) - { - lstrcat(args, L" "); - lstrcat(args, commandLineFiltered); - RegSetValueEx(hKey, L"Parity", 0, REG_SZ, (LPBYTE)args, MAX_PATH); - } - delete[] args; - } - else - { - RegDeleteValue(hKey, L"Parity"); - } -} - diff --git a/windows/ptray/ptray.ico b/windows/ptray/ptray.ico deleted file mode 100644 index cda99eef8b3668827befd6a13ff8268c096ceae4..0000000000000000000000000000000000000000 Binary files a/windows/ptray/ptray.ico and /dev/null differ diff --git a/windows/ptray/ptray.rc b/windows/ptray/ptray.rc deleted file mode 100644 index 9f10e0aa852b9acce480a966a239fee3f292cc38..0000000000000000000000000000000000000000 Binary files a/windows/ptray/ptray.rc and /dev/null differ diff --git a/windows/ptray/ptray.vcxproj b/windows/ptray/ptray.vcxproj deleted file mode 100644 index e015d55c1ebb1ed5d26551aa8100519fbdff78a5..0000000000000000000000000000000000000000 --- a/windows/ptray/ptray.vcxproj +++ /dev/null @@ -1,155 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {37C89E90-8C9E-4FFC-AAE7-B3695D5EB6F4} - Win32Proj - ptray - 8.1 - - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - - - true - - - false - - - false - - - - NotUsing - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) - - - Windows - true - - - - - NotUsing - Level3 - Disabled - _DEBUG;_WINDOWS;%(PreprocessorDefinitions) - - - Windows - true - - - - - Level3 - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) - - - Windows - true - true - true - - - - - Level3 - NotUsing - MaxSpeed - true - true - NDEBUG;_WINDOWS;%(PreprocessorDefinitions) - - - Windows - true - true - true - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/windows/ptray/resource.h b/windows/ptray/resource.h deleted file mode 100644 index 1f4b023431b96fb9c6edaf617bd5e9ac940c75c7..0000000000000000000000000000000000000000 Binary files a/windows/ptray/resource.h and /dev/null differ diff --git a/windows/ptray/targetver.h b/windows/ptray/targetver.h deleted file mode 100644 index 87c0086de751bac3d47208b77d76b82d78f26702..0000000000000000000000000000000000000000 --- a/windows/ptray/targetver.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -// Including SDKDDKVer.h defines the highest available Windows platform. - -// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and -// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. - -#include