Compare commits

..

11 Commits

Author SHA1 Message Date
s3krit
6bd7db96fe v2.5.7 stable (#11006)
* [trace] check mem diff within range (#11002)

* Update version (v2.5.7-stable)
2019-08-29 12:06:49 +02:00
s3krit
ff398fe7ff V2.5.6 stable (#10961)
-  Fix cargo audit (#10921)
  - Add support for Energy Web Foundation's new chains (#10957)
  - Kaspersky AV whitelisting (#10919)
  - Avast whitelist script (#10900)
  - Docker images renaming (#10863)
  - Remove excessive warning (#10831)
  - Allow --nat extip:your.host.here.org (#10830)
  - When updating the client or when called from RPC, sleep should mean sleep (#10814)
  - added new ropsten-bootnode and removed old one (#10794)
  - ethkey no longer uses byteorder (#10786)
  - Do not drop the peer with None difficulty (#10772)
  - docs: Update Readme with TOC, Contributor Guideline. Update Cargo package descriptions (#10652)
2019-08-12 18:55:11 +02:00
s3krit
3ebc769757 version: stabilise v2.5 (#10857) 2019-07-08 12:30:14 +02:00
s3krit
d60e6384d7 Beta 2.5.4 (#10827)
* cargo update -p smallvec (#10822)

Fixes https://github.com/servo/rust-smallvec/issues/148

* Update version to v2.5.3

Signed-off-by: Martin Pugh <pugh@s3kr.it>
2019-07-01 12:33:35 +02:00
s3krit
3fd58bdcbd Beta 2.5.3 (#10776)
* ethcore/res: activate atlantis classic hf on block 8772000 (#10766)

* fix docker tags for publishing (#10741)

* fix: aura don't add `SystemTime::now()` (#10720)

This commit does the following:
- Prevent overflow in `verify_timestamp()` by not adding `now` to found faulty timestamp
- Use explicit `CheckedSystemTime::checked_add` to prevent potential consensus issues because SystemTime is platform
depedent
- remove `#[cfg(not(time_checked_add))]` conditional compilation

* Update version

* Treat empty account the same as non-exist accounts in EIP-1052 (#10775)

* DevP2p: Get node IP address and udp port from Socket, if not included in PING packet (#10705)

* get node IP address and udp port from Socket, if not included in PING packet

* prevent bootnodes from being added to host nodes

* code corrections

* code corrections

* code corrections

* code corrections

* docs

* code corrections

* code corrections

* Apply suggestions from code review

Co-Authored-By: David <dvdplm@gmail.com>

* Add a way to signal shutdown to snapshotting threads (#10744)

* Add a way to signal shutdown to snapshotting threads

* Pass Progress to fat_rlps() so we can abort from there too.

* Checking for abort in a single spot

* Remove nightly-only weak/strong counts

* fix warning

* Fix tests

* Add dummy impl to abort snapshots

* Add another dummy impl for TestSnapshotService

* Remove debugging code

* Return error instead of the odd Ok(())
Switch to AtomicU64

* revert .as_bytes() change

* fix build

* fix build maybe
2019-06-25 13:38:29 +00:00
Talha Cross
ecbafb2390 backports for beta 2.5.2 (#10737)
* version: bump beta to 2.5.2

* [CI] allow cargo audit to fail (#10676)

* [CI] allow cargo audit to fail

* [.gitlab-ci.yml] add a comment about cargo audit

* [Cargo.lock] cargo update -p protobuf

* Reset blockchain properly (#10669)

* delete BlockDetails from COL_EXTRA

* better proofs

* added tests

* PR suggestions

* new image (#10673)

* Update publishing (#10644)

* docker images are now built on k8s: test run

* copy check_sync.sh in build-linux job

* copy scripts/docker/hub/* in build-linux job

* removed cache var

* cleanup, no more nightly dockers

* cleanup in dockerfile

* some new tags

* removed sccsche debug log, cleanup

* no_gits, new artifacts dir, changed scripts. Test run.

* define version once

* one source for TRACK

* stop kovan onchain updates

* moved changes for two images to a new branch

* rename Dockerfile

* no need in libudev-dev

* enable lto for release builds (#10717)

* Use RUSTFLAGS to set the optimization level (#10719)

* Use RUSTFLAGS to set the optimization level

Cargo has a [quirk]() in how configuration settings are propagated when `cargo test` runs: local code respect the settings in `[profile.test]` but all dependencies use the `[profile.dev]` settings. Here we force `opt-level=3` for all dependencies.

* Remove unused profile settings

* Maybe like this?

* Turn off incremental compilation

* Remove colors; try again with overflow-checks on

* Use quiet CI machine

* Turn overflow checking back on

* Be explicit about what options we use

* Remove "quiet machine" override

* ethcore: enable ECIP-1054 for classic (#10731)

* config: enable atlantis on ethereum classic

* config: enable atlantis on morden classic

* config: enable atlantis on morden classic

* config: enable atlantis on kotti classic

* ethcore: move kotti fork block to 0xAEF49

* ethcore: move morden fork block to 0x4829BA

* ethcore: move classic fork block to 0x81B320

* remove trailing comma

* remove trailing comma

* fix chainspec

* ethcore: move classic fork block to 0x7fffffffffffffff
2019-06-11 20:56:03 +02:00
Talha Cross
adabd8198c beta ci: backport missing diff from master (#10661)
* ci: publish docs debug (#10638)

* ci: backport missing diff from master
2019-05-14 15:03:29 +02:00
Talha Cross
c2487cfe07 ci: publish docs debug (#10638) (#10660) 2019-05-14 14:04:54 +02:00
Talha Cross
e0141f8324 beta 2.5.1 (#10643)
* version: bump beta to 2.5.1

* fix(whisper expiry): current time + work + ttl (#10587)

* update bootnodes (#10595)

* config: update goerli bootnodes

* config: update kotti bootnodes

* adds rpc error message for --no-ancient-blocks (#10608)

* adds error message for --no-ancient-blocks, closes #10261

* Apply suggestions from code review

Co-Authored-By: seunlanlege <seunlanlege@gmail.com>

* Constantinople HF on POA Core (#10606)

* Constantinople HF on POA Core

Plan Constantinople/St.Petersfork HF on POA Core network at block 8582254.
Original PR in POA repository: https://github.com/poanetwork/poa-chain-spec/pull/110

* Remove extra empty line

* evm: add some mulmod benches (#10600)

* evm: add blockhash_mulmod bench

* evm: use num-bigint for mod ops

* Clique: zero-fill extradata when the supplied value is less than 32 bytes in length (#10605)

* Update kovan.json to switch validator set to POA Consensus Contracts (#10628)

* Fix publish docs (#10635)

* Fix publish docs

* this never should be forced, either way compiling previous versions will produce outdated docs

* fix array, var was moved to the group project global variables list

* Fix rinkeby petersburg fork (#10632)
2019-05-10 13:48:52 +02:00
Talha Cross
b52ac20660 beta backports (#10576)
* Reject crazy timestamps instead of truncating.

* fix(light cull): poll light cull instead of timer (#10559)

* fix(light cull): poll light cull instead of timer

* fix(grumbles): remove error + updated docs

* fix(on-demand request): `expect()` reason

* docs(remove misleading info)
2019-04-08 11:44:10 +02:00
soc1c
3c85f29f11 version: betalize 2.5 2019-04-02 09:37:43 +02:00
480 changed files with 10518 additions and 11388 deletions

View File

@@ -1,27 +1,3 @@
# NOTE: if you make changes here, remember to also update:
# scripts/test-linux.sh
# scripts/build-linux.sh
# scripts/build-windows.sh
# Using 'cfg` is broken, see https://github.com/rust-lang/cargo/issues/6858
#[target.'cfg(target_arch = "x86_64")']
#rustflags = ["-Ctarget-feature=+aes,+sse2,+ssse3"]
# …so instead we list all target triples (Tier 1 64-bit platforms)
[target.x86_64-unknown-linux-gnu]
# Enables the aes-ni instructions for RustCrypto dependency.
rustflags = ["-Ctarget-feature=+aes,+sse2,+ssse3"]
[target.x86_64-pc-windows-gnu]
# Enables the aes-ni instructions for RustCrypto dependency.
rustflags = ["-Ctarget-feature=+aes,+sse2,+ssse3"]
[target.x86_64-pc-windows-msvc]
# Enables the aes-ni instructions for RustCrypto dependency.
# Link the C runtime statically ; https://github.com/paritytech/parity-ethereum/issues/6643
rustflags = ["-Ctarget-feature=+aes,+sse2,+ssse3", "-Ctarget-feature=+crt-static"]
[target.x86_64-apple-darwin]
# Enables the aes-ni instructions for RustCrypto dependency.
rustflags = ["-Ctarget-feature=+aes,+sse2,+ssse3"]
rustflags = ["-Ctarget-feature=+crt-static"]

View File

@@ -1,14 +1,10 @@
_Before filing a new issue, please **provide the following information**._
_If you think that your issue is an exploitable security vulnerability, please mail your bugreport to security@parity.io instead; your submission might be eligible for our Bug Bounty._
_You can find mode info on the reporting process in [SECURITY.md](https://github.com/paritytech/parity-ethereum/blob/master/SECURITY.md)_
- **Parity Ethereum version**: 0.0.0
- **Operating system**: Windows / MacOS / Linux
- **Installation**: homebrew / one-line installer / built from source
- **Fully synchronized**: no / yes
- **Network**: ethereum / ropsten / goerli / ...
- **Network**: ethereum / ropsten / kovan / ...
- **Restarted**: no / yes
_Your issue description goes here below. Try to include **actual** vs. **expected behavior** and **steps to reproduce** the issue._

View File

@@ -1,21 +0,0 @@
Thank you for your Pull Request!
Before you submitting, please check that:
- [ ] You added a brief description of the PR, e.g.:
- What does it do?
- What important points reviewers should know?
- Is there something left for follow-up PRs?
- [ ] You labeled the PR with appropriate labels if you have permissions to do so.
- [ ] You mentioned a related issue if this PR related to it, e.g. `Fixes #228` or `Related #1337`.
- [ ] You asked any particular reviewers to review. If you aren't sure, start with GH suggestions.
- [ ] Your PR adheres [the style guide](https://wiki.parity.io/Coding-guide)
- In particular, mind the maximal line length.
- There is no commented code checked in unless necessary.
- Any panickers have a proof or removed.
- [ ] You updated any rustdocs which may have changed
After you've read this notice feel free to remove it.
Thank you!
✄ -----------------------------------------------------------------------------

View File

@@ -153,7 +153,7 @@ build-android:
build-linux:
<<: *build-on-linux
only: *releaseable_branches
# only: *releaseable_branches
build-linux-i386:
<<: *build-on-linux

View File

@@ -1,185 +1,95 @@
## Parity-Ethereum [v2.6.1](https://github.com/paritytech/parity-ethereum/releases/tag/v2.6.1)
## Parity-Ethereum [v2.5.6](https://github.com/paritytech/parity-ethereum/releases/tag/v2.5.5)
Parity-Ethereum 2.6.1-beta is a patch release that improves stability.
Parity-Ethereum v2.5.6-stable is a bugfix release that improves stability.
This release includes:
* Allow specifying hostnames for node URLs
* Fix a bug where archive nodes were losing peers
* Add support for Energy Web Foundations new chains 'Volta' and 'EWC', and remove their deprecated 'Tobalaba' chain.
* Allow specifying hostnames for node URLs
* Fix a bug where archive nodes were losing peers
The full list of included changes:
* Add support for Energy Web Foundation's new chains (#10957)
* Kaspersky AV whitelisting (#10919)
* Avast whitelist script (#10900)
* Docker images renaming (#10863)
* Remove excessive warning (#10831)
* Allow --nat extip:your.host.here.org (#10830)
* When updating the client or when called from RPC, sleep should mean sleep (#10814)
* added new ropsten-bootnode and removed old one (#10794)
* ethkey no longer uses byteorder (#10786)
* docs: Update Readme with TOC, Contributor Guideline. Update Cargo package descriptions (#10652)
## Parity-Ethereum [v2.6.0](https://github.com/paritytech/parity-ethereum/releases/tag/v2.6.0)
* Kaspersky AV whitelisting (#10919)
* Avast whitelist script (#10900)
* Docker images renaming (#10863)
* Remove excessive warning (#10831)
* Allow --nat extip:your.host.here.org (#10830)
* When updating the client or when called from RPC, sleep should mean sleep (#10814)
* added new ropsten-bootnode and removed old one (#10794)
* ethkey no longer uses byteorder (#10786)
* Do not drop the peer with None difficulty (#10772)
* docs: Update Readme with TOC, Contributor Guideline. Update Cargo package descriptions (#10652)
Parity-Ethereum 2.6.0-beta is a minor release that stabilizes the 2.6 branch by
marking it as a beta release.
## Parity-Ethereum [v2.5.5](https://github.com/paritytech/parity-ethereum/releases/tag/v2.5.5)
This release includes:
* Major refactoring of the codebase
* Many bugfixes
* Significant improvements to logging, error and warning message clarity.
* SecretStore: remove support of old database formats (#10757)
* This is a potentially breaking change if you have not upgraded for
quite some time.
Parity-Ethereum v2.5.5-stable is a minor release that improves performance and stability.
This release stabilises the 2.5 branch.
As of today, Parity-Ethereum 2.4 reaches end of life, and everyone is
encouraged to upgrade.
As of today, Parity-Ethereum 2.4 reaches end of life and everyone is
encouraged to upgrade.
## Parity-Ethereum [v2.5.4](https://github.com/paritytech/parity-ethereum/releases/tag/v2.5.4)
Parity Ethereum v2.5.4-beta is a security update that addresses servo/rust-smallvec#148
The full list of included changes:
* update jsonrpc to 12.0 ([#10841](https://github.com/paritytech/parity-ethereum/pull/10841))
* Move more code into state-account ([#10840](https://github.com/paritytech/parity-ethereum/pull/10840))
* Extract AccountDB to account-db ([#10839](https://github.com/paritytech/parity-ethereum/pull/10839))
* Extricate PodAccount and state Account to own crates ([#10838](https://github.com/paritytech/parity-ethereum/pull/10838))
* Fix fork choice ([#10837](https://github.com/paritytech/parity-ethereum/pull/10837))
* tests: Relates to #10655: Test instructions for Readme ([#10835](https://github.com/paritytech/parity-ethereum/pull/10835))
* idiomatic changes to PodState ([#10834](https://github.com/paritytech/parity-ethereum/pull/10834))
* Break circular dependency between Client and Engine (part 1) ([#10833](https://github.com/paritytech/parity-ethereum/pull/10833))
* Remove excessive warning ([#10831](https://github.com/paritytech/parity-ethereum/pull/10831))
* Allow --nat extip:your.host.here.org ([#10830](https://github.com/paritytech/parity-ethereum/pull/10830))
* ethcore does not use byteorder ([#10829](https://github.com/paritytech/parity-ethereum/pull/10829))
* Fix typo in README.md ([#10828](https://github.com/paritytech/parity-ethereum/pull/10828))
* Update wordlist to v1.3 ([#10823](https://github.com/paritytech/parity-ethereum/pull/10823))
* bump `smallvec 0.6.10` to fix vulnerability ([#10822](https://github.com/paritytech/parity-ethereum/pull/10822))
* removed additional_params method ([#10818](https://github.com/paritytech/parity-ethereum/pull/10818))
* Improve logging when remote peer is unknown ([#10817](https://github.com/paritytech/parity-ethereum/pull/10817))
* replace memzero with zeroize crate ([#10816](https://github.com/paritytech/parity-ethereum/pull/10816))
* When updating the client or when called from RPC, sleep should mean sleep ([#10814](https://github.com/paritytech/parity-ethereum/pull/10814))
* Don't reimplement the logic from the Default impl ([#10813](https://github.com/paritytech/parity-ethereum/pull/10813))
* refactor: whisper: Add type aliases and update rustdocs in message.rs ([#10812](https://github.com/paritytech/parity-ethereum/pull/10812))
* test: whisper/cli `add invalid pool size test depending on processor` ([#10811](https://github.com/paritytech/parity-ethereum/pull/10811))
* Add Constantinople EIPs to the dev (instant_seal) config ([#10809](https://github.com/paritytech/parity-ethereum/pull/10809))
* fix spurious test failure ([#10808](https://github.com/paritytech/parity-ethereum/pull/10808))
* revert temp changes to .gitlab-ci.yml ([#10807](https://github.com/paritytech/parity-ethereum/pull/10807))
* removed redundant fmt::Display implementations ([#10806](https://github.com/paritytech/parity-ethereum/pull/10806))
* removed EthEngine alias ([#10805](https://github.com/paritytech/parity-ethereum/pull/10805))
* ethcore-bloom-journal updated to 2018 ([#10804](https://github.com/paritytech/parity-ethereum/pull/10804))
* Fix a few typos and unused warnings. ([#10803](https://github.com/paritytech/parity-ethereum/pull/10803))
* updated price-info to edition 2018 ([#10801](https://github.com/paritytech/parity-ethereum/pull/10801))
* updated parity-local-store to edition 2018 ([#10800](https://github.com/paritytech/parity-ethereum/pull/10800))
* updated project to ansi_term 0.11 ([#10799](https://github.com/paritytech/parity-ethereum/pull/10799))
* ethcore-light uses bincode 1.1 ([#10798](https://github.com/paritytech/parity-ethereum/pull/10798))
* ethcore-network-devp2p uses igd 0.9 ([#10797](https://github.com/paritytech/parity-ethereum/pull/10797))
* Better logging when backfilling ancient blocks fail ([#10796](https://github.com/paritytech/parity-ethereum/pull/10796))
* added new ropsten-bootnode and removed old one ([#10794](https://github.com/paritytech/parity-ethereum/pull/10794))
* Removed machine abstraction from ethcore ([#10791](https://github.com/paritytech/parity-ethereum/pull/10791))
* Removed redundant ethcore-service error type ([#10788](https://github.com/paritytech/parity-ethereum/pull/10788))
* Cleanup unused vm dependencies ([#10787](https://github.com/paritytech/parity-ethereum/pull/10787))
* ethkey no longer uses byteorder ([#10786](https://github.com/paritytech/parity-ethereum/pull/10786))
* Updated blooms-db to rust 2018 and removed redundant deps ([#10785](https://github.com/paritytech/parity-ethereum/pull/10785))
* Treat empty account the same as non-exist accounts in EIP-1052 ([#10775](https://github.com/paritytech/parity-ethereum/pull/10775))
* Do not drop the peer with None difficulty ([#10772](https://github.com/paritytech/parity-ethereum/pull/10772))
* EIP-1702: Generalized Account Versioning Scheme ([#10771](https://github.com/paritytech/parity-ethereum/pull/10771))
* Move Engine::register_client to be before other I/O handler registration ([#10767](https://github.com/paritytech/parity-ethereum/pull/10767))
* cargo update -p smallvec ([#10822](https://github.com/paritytech/parity-ethereum/pull/10822))
## Parity-Ethereum [v2.5.3](https://github.com/paritytech/parity-ethereum/releases/tag/v2.5.3)
Parity-Ethereum 2.5.3-beta is a bugfix release that improves performance and stability.
* EthereumClassic: activate the Atlantis Hardfork
* Clique: fix time overflow
* State tests: treat empty accounts the same as non-existant accounts (EIP 1052)
* Networking: support discovery-only peers (geth bootnodes)
* Snapshotting: fix unclean shutdown while snappshotting is under way
The full list of included changes:
* ethcore/res: activate atlantis classic hf on block 8772000 ([#10766](https://github.com/paritytech/parity-ethereum/pull/10766))
* Updated Bn128PairingImpl to use optimized batch pairing ([#10765](https://github.com/paritytech/parity-ethereum/pull/10765))
* Remove unused code ([#10762](https://github.com/paritytech/parity-ethereum/pull/10762))
* Initialize private tx logger only if private tx functionality is enabled ([#10758](https://github.com/paritytech/parity-ethereum/pull/10758))
* SecretStore: remove support of old database formats ([#10757](https://github.com/paritytech/parity-ethereum/pull/10757))
* Enable aesni ([#10756](https://github.com/paritytech/parity-ethereum/pull/10756))
* updater: fix static id hashes initialization ([#10755](https://github.com/paritytech/parity-ethereum/pull/10755))
* Use fewer threads for snapshotting ([#10752](https://github.com/paritytech/parity-ethereum/pull/10752))
* Die error_chain, die ([#10747](https://github.com/paritytech/parity-ethereum/pull/10747))
* Fix deprectation warnings on nightly ([#10746](https://github.com/paritytech/parity-ethereum/pull/10746))
* Improve logging and cleanup in miner around block sealing ([#10745](https://github.com/paritytech/parity-ethereum/pull/10745))
* Add a way to signal shutdown to snapshotting threads ([#10744](https://github.com/paritytech/parity-ethereum/pull/10744))
* fix docker tags for publishing ([#10741](https://github.com/paritytech/parity-ethereum/pull/10741))
* refactor: Fix indentation in ethjson ([#10740](https://github.com/paritytech/parity-ethereum/pull/10740))
* Log validator set changes in EpochManager ([#10734](https://github.com/paritytech/parity-ethereum/pull/10734))
* Print warnings when using dangerous settings for ValidatorSet ([#10733](https://github.com/paritytech/parity-ethereum/pull/10733))
* ethcore: enable ECIP-1054 for classic ([#10731](https://github.com/paritytech/parity-ethereum/pull/10731))
* Stop breaking out of loop if a non-canonical hash is found ([#10729](https://github.com/paritytech/parity-ethereum/pull/10729))
* Removed secret_store folder ([#10722](https://github.com/paritytech/parity-ethereum/pull/10722))
* Revert "enable lto for release builds (#10717)" ([#10721](https://github.com/paritytech/parity-ethereum/pull/10721))
* fix: aura don't add `SystemTime::now()` ([#10720](https://github.com/paritytech/parity-ethereum/pull/10720))
* Use RUSTFLAGS to set the optimization level ([#10719](https://github.com/paritytech/parity-ethereum/pull/10719))
* enable lto for release builds ([#10717](https://github.com/paritytech/parity-ethereum/pull/10717))
* [devp2p] Update to 2018 edition ([#10716](https://github.com/paritytech/parity-ethereum/pull/10716))
* [devp2p] Don't use `rust-crypto` ([#10714](https://github.com/paritytech/parity-ethereum/pull/10714))
* [devp2p] Fix warnings and re-org imports ([#10710](https://github.com/paritytech/parity-ethereum/pull/10710))
* Treat empty account the same as non-exist accounts in EIP-1052 ([#10775](https://github.com/paritytech/parity-ethereum/pull/10775))
* DevP2p: Get node IP address and udp port from Socket, if not included in PING packet ([#10705](https://github.com/paritytech/parity-ethereum/pull/10705))
* introduce MissingParent Error, fixes #10699 ([#10700](https://github.com/paritytech/parity-ethereum/pull/10700))
* Refactor Clique stepping ([#10691](https://github.com/paritytech/parity-ethereum/pull/10691))
* add_sync_notifier in EthPubSubClient holds on to a Client for too long ([#10689](https://github.com/paritytech/parity-ethereum/pull/10689))
* Fix compiler warning (that will become an error) ([#10683](https://github.com/paritytech/parity-ethereum/pull/10683))
* Don't panic if extra_data is longer than VANITY_LENGTH ([#10682](https://github.com/paritytech/parity-ethereum/pull/10682))
* Remove annoying compiler warnings ([#10679](https://github.com/paritytech/parity-ethereum/pull/10679))
* Remove support for hardware wallets ([#10678](https://github.com/paritytech/parity-ethereum/pull/10678))
* Add a way to signal shutdown to snapshotting threads ([#10744](https://github.com/paritytech/parity-ethereum/pull/10744))
## Parity-Ethereum [v2.5.2](https://github.com/paritytech/parity-ethereum/releases/tag/v2.5.2)
Parity-Ethereum 2.5.2-beta is a bugfix release that improves performance and stability.
Among others, it enables the _Atlantis_ hardfork on **Morden** and **Kotti** Classic networks.
The full list of included changes:
* [CI] allow cargo audit to fail ([#10676](https://github.com/paritytech/parity-ethereum/pull/10676))
* new image ([#10673](https://github.com/paritytech/parity-ethereum/pull/10673))
* Upgrade ethereum types ([#10670](https://github.com/paritytech/parity-ethereum/pull/10670))
* Reset blockchain properly ([#10669](https://github.com/paritytech/parity-ethereum/pull/10669))
* fix: Move PR template into .github/ folder ([#10663](https://github.com/paritytech/parity-ethereum/pull/10663))
* docs: evmbin - Update Rust docs ([#10658](https://github.com/paritytech/parity-ethereum/pull/10658))
* refactor: Related #9459 - evmbin: replace untyped json! macro with fully typed serde serialization using Rust structs ([#10657](https://github.com/paritytech/parity-ethereum/pull/10657))
* docs: Add PR template ([#10654](https://github.com/paritytech/parity-ethereum/pull/10654))
* docs: Add ProgPoW Rust docs to ethash module ([#10653](https://github.com/paritytech/parity-ethereum/pull/10653))
* docs: Update Readme with TOC, Contributor Guideline. Update Cargo package descriptions ([#10652](https://github.com/paritytech/parity-ethereum/pull/10652))
* Upgrade to parity-crypto 0.4 ([#10650](https://github.com/paritytech/parity-ethereum/pull/10650))
* fix(compilation warnings) ([#10649](https://github.com/paritytech/parity-ethereum/pull/10649))
* [whisper] Move needed aes_gcm crypto in-crate ([#10647](https://github.com/paritytech/parity-ethereum/pull/10647))
* new image ([#10673](https://github.com/paritytech/parity-ethereum/pull/10673))
* Update publishing ([#10644](https://github.com/paritytech/parity-ethereum/pull/10644))
* enable lto for release builds ([#10717](https://github.com/paritytech/parity-ethereum/pull/10717))
* Use RUSTFLAGS to set the optimization level ([#10719](https://github.com/paritytech/parity-ethereum/pull/10719))
* ethcore: enable ECIP-1054 for classic ([#10731](https://github.com/paritytech/parity-ethereum/pull/10731))
## Parity-Ethereum [v2.5.1](https://github.com/paritytech/parity-ethereum/releases/tag/v2.5.1)
Parity-Ethereum 2.5.1-beta is a bugfix release that improves performance and stability.
Among others, it enables the Petersburg hardfork on **Rinkeby** and **POA-Core** Network, as well as the **Kovan** Network community hardfork.
The full list of included changes:
* ci: publish docs debug ([#10638](https://github.com/paritytech/parity-ethereum/pull/10638))
* Fix publish docs ([#10635](https://github.com/paritytech/parity-ethereum/pull/10635))
* Fix rinkeby petersburg fork ([#10632](https://github.com/paritytech/parity-ethereum/pull/10632))
* Update kovan.json to switch Kovan validator set to POA Consensus Contracts ([#10628](https://github.com/paritytech/parity-ethereum/pull/10628))
* [ethcore] remove error_chain ([#10616](https://github.com/paritytech/parity-ethereum/pull/10616))
* Remove unused import ([#10615](https://github.com/paritytech/parity-ethereum/pull/10615))
* Adds parity_getRawBlockByNumber, parity_submitRawBlock ([#10609](https://github.com/paritytech/parity-ethereum/pull/10609))
* adds rpc error message for --no-ancient-blocks ([#10608](https://github.com/paritytech/parity-ethereum/pull/10608))
* Constantinople HF on POA Core ([#10606](https://github.com/paritytech/parity-ethereum/pull/10606))
* Clique: zero-fill extradata when the supplied value is less than 32 bytes in length ([#10605](https://github.com/paritytech/parity-ethereum/pull/10605))
* evm: add some mulmod benches ([#10600](https://github.com/paritytech/parity-ethereum/pull/10600))
* sccache logs to stdout ([#10596](https://github.com/paritytech/parity-ethereum/pull/10596))
* update bootnodes ([#10595](https://github.com/paritytech/parity-ethereum/pull/10595))
* Merge `Notifier` and `TransactionsPoolNotifier` ([#10591](https://github.com/paritytech/parity-ethereum/pull/10591))
* fix(whisper): change expiry `unix_time + ttl + work` ([#10587](https://github.com/paritytech/parity-ethereum/pull/10587))
* fix(evmbin): make benches compile again ([#10586](https://github.com/paritytech/parity-ethereum/pull/10586))
* fix issue with compilation when 'slow-blocks' feature enabled ([#10585](https://github.com/paritytech/parity-ethereum/pull/10585))
* Allow CORS requests in Secret Store API ([#10584](https://github.com/paritytech/parity-ethereum/pull/10584))
* CI improvements ([#10579](https://github.com/paritytech/parity-ethereum/pull/10579))
* ethcore: improve timestamp handling ([#10574](https://github.com/paritytech/parity-ethereum/pull/10574))
* Update Issue Template to direct security issue to email ([#10562](https://github.com/paritytech/parity-ethereum/pull/10562))
* version: bump master to 2.6 ([#10560](https://github.com/paritytech/parity-ethereum/pull/10560))
## Parity-Ethereum [v2.5.0](https://github.com/paritytech/parity-ethereum/releases/tag/v2.5.0)
Parity-Ethereum 2.5.0-beta is a minor release that improves performance and stabilizes the 2.5 branch by marking it as beta release.
- This release adds support for the Clique consensus engine ([#9981](https://github.com/paritytech/parity-ethereum/pull/9981))
- This enables Parity-Ethereum users to use the Görli, the Kotti Classic, and the legacy Rinkeby testnet. To get started try `parity --chain goerli`; note that light client support is currently not yet fully functional.
- This release removes the dead chain configs for Easthub and Ethereum Social ([#10531](https://github.com/paritytech/parity-ethereum/pull/10531))
As of today, Parity-Ethereum 2.3 reaches end of life and everyone is encouraged to upgrade.
The full list of included changes:
* fix(light cull): poll light cull instead of timer ([#10559](https://github.com/paritytech/parity-ethereum/pull/10559))
* Watch transactions pool ([#10558](https://github.com/paritytech/parity-ethereum/pull/10558))
* Add SealingState; don't prepare block when not ready. ([#10529](https://github.com/paritytech/parity-ethereum/pull/10529))
* Explicitly enable or disable Stratum in config file (Issue 9785) ([#10521](https://github.com/paritytech/parity-ethereum/pull/10521))
* Add filtering capability to `parity_pendingTransactions` (issue 8269) ([#10506](https://github.com/paritytech/parity-ethereum/pull/10506))
* Remove calls to heapsize ([#10432](https://github.com/paritytech/parity-ethereum/pull/10432))
* RPC: Implements eth_subscribe("syncing") ([#10311](https://github.com/paritytech/parity-ethereum/pull/10311))
* SecretStore: non-blocking wait of session completion ([#10303](https://github.com/paritytech/parity-ethereum/pull/10303))
* Node table limiting and cache for node filter ([#10288](https://github.com/paritytech/parity-ethereum/pull/10288))
* SecretStore: expose restore_key_public in HTTP API ([#10241](https://github.com/paritytech/parity-ethereum/pull/10241))
* Trivial journal for private transactions ([#10056](https://github.com/paritytech/parity-ethereum/pull/10056))
## Previous releases
- [CHANGELOG-2.5](docs/CHANGELOG-2.5.md) (_stable_)
- [CHANGELOG-2.4](docs/CHANGELOG-2.4.md) (EOL: 2019-07-08)
- [CHANGELOG-2.3](docs/CHANGELOG-2.3.md) (EOL: 2019-04-09)
- [CHANGELOG-2.2](docs/CHANGELOG-2.2.md) (EOL: 2019-02-25)
- [CHANGELOG-2.1](docs/CHANGELOG-2.1.md) (EOL: 2019-01-16)
- [CHANGELOG-2.0](docs/CHANGELOG-2.0.md) (EOL: 2018-11-15)
- [CHANGELOG-1.11](docs/CHANGELOG-1.11.md) (EOL: 2018-09-19)
- [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)
- [CHANGELOG-1.6](docs/CHANGELOG-1.6.md) (EOL: 2017-10-15)
- [CHANGELOG-1.5](docs/CHANGELOG-1.5.md) (EOL: 2017-07-28)
- [CHANGELOG-1.4](docs/CHANGELOG-1.4.md) (EOL: 2017-03-13)
- [CHANGELOG-1.3](docs/CHANGELOG-1.3.md) (EOL: 2017-01-19)
- [CHANGELOG-1.2](docs/CHANGELOG-1.2.md) (EOL: 2016-11-07)
- [CHANGELOG-1.1](docs/CHANGELOG-1.1.md) (EOL: 2016-08-12)
- [CHANGELOG-1.0](docs/CHANGELOG-1.0.md) (EOL: 2016-06-24)
- [CHANGELOG-0.9](docs/CHANGELOG-0.9.md) (EOL: 2016-05-02)

1711
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
description = "Parity Ethereum client"
name = "parity-ethereum"
# NOTE Make sure to update util/version/Cargo.toml as well
version = "2.6.2"
version = "2.5.7"
license = "GPL-3.0"
authors = ["Parity Technologies <admin@parity.io>"]
@@ -18,7 +18,7 @@ num_cpus = "1.2"
number_prefix = "0.2"
rpassword = "1.0"
semver = "0.9"
ansi_term = "0.11"
ansi_term = "0.10"
parking_lot = "0.7"
regex = "1.0"
atty = "0.2.8"
@@ -29,7 +29,7 @@ serde_derive = "1.0"
futures = "0.1"
fdlimit = "0.1"
ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" }
jsonrpc-core = "12.0.0"
jsonrpc-core = "10.0.1"
parity-bytes = "0.1"
common-types = { path = "ethcore/types" }
ethcore = { path = "ethcore", features = ["parity"] }
@@ -45,11 +45,11 @@ ethcore-network = { path = "util/network" }
ethcore-private-tx = { path = "ethcore/private-tx" }
ethcore-service = { path = "ethcore/service" }
ethcore-sync = { path = "ethcore/sync" }
ethereum-types = "0.6.0"
ethereum-types = "0.4"
ethkey = { path = "accounts/ethkey" }
ethstore = { path = "accounts/ethstore" }
node-filter = { path = "ethcore/node-filter" }
rlp = "0.4.0"
rlp = { version = "0.3.0", features = ["ethereum"] }
cli-signer= { path = "cli-signer" }
parity-daemonize = "0.3"
parity-hash-fetch = { path = "updater/hash-fetch" }
@@ -63,7 +63,7 @@ parity-whisper = { path = "whisper" }
parity-path = "0.1"
dir = { path = "util/dir" }
panic_hook = { path = "util/panic-hook" }
keccak-hash = "0.2.0"
keccak-hash = "0.1"
migration-rocksdb = { path = "util/migration-rocksdb" }
kvdb = "0.1"
kvdb-rocksdb = "0.1.3"
@@ -73,8 +73,6 @@ ethcore-secretstore = { path = "secret-store", optional = true }
registrar = { path = "util/registrar" }
parity-util-mem = { version = "0.1", features = ["jemalloc-global"] }
[build-dependencies]
rustc_version = "0.2"
@@ -83,6 +81,7 @@ pretty_assertions = "0.1"
ipnetwork = "0.12.6"
tempdir = "0.3"
fake-fetch = { path = "util/fake-fetch" }
lazy_static = "1.2.0"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.4", features = ["winsock2", "winuser", "shellapi"] }
@@ -119,6 +118,10 @@ path = "parity/lib.rs"
path = "parity/main.rs"
name = "parity"
[profile.test]
lto = false
opt-level = 3 # makes tests slower to compile, but faster to run
[profile.release]
debug = false
lto = true
@@ -139,5 +142,8 @@ members = [
"util/keccak-hasher",
"util/patricia-trie-ethereum",
"util/fastmap",
"util/time-utils",
"util/time-utils"
]
[patch.crates-io]
heapsize = { git = "https://github.com/cheme/heapsize.git", branch = "ec-macfix" }

View File

@@ -16,12 +16,11 @@
3.2 [Building from Source Code](#chapter-0032)<br>
3.3 [Simple One-Line Installer for Mac and Linux](#chapter-0033)<br>
3.4 [Starting Parity Ethereum](#chapter-0034)
4. [Testing](#chapter-004)
5. [Documentation](#chapter-005)
6. [Toolchain](#chapter-006)
7. [Community](#chapter-007)
8. [Contributing](#chapter-008)
9. [License](#chapter-009)
4. [Documentation](#chapter-004)
5. [Toolchain](#chapter-005)
6. [Community](#chapter-006)
7. [Contributing](#chapter-007)
8. [License](#chapter-008)
## 1. Description <a id="chapter-001"></a>
@@ -57,7 +56,7 @@ We recommend installing Rust through [rustup](https://www.rustup.rs/). If you do
$ curl https://sh.rustup.rs -sSf | sh
```
Parity Ethereum also requires `gcc`, `g++`, `pkg-config`, `file`, `make`, and `cmake` packages to be installed.
Parity Ethereum also requires `gcc`, `g++`, `libudev-dev`, `pkg-config`, `file`, `make`, and `cmake` packages to be installed.
- OSX:
```bash
@@ -66,7 +65,7 @@ We recommend installing Rust through [rustup](https://www.rustup.rs/). If you do
`clang` is required. It comes with Xcode command line tools or can be installed with homebrew.
- Windows:
- 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:
```bash
@@ -149,25 +148,7 @@ To start Parity Ethereum as a regular user using `systemd` init:
2. Copy release to bin folder, write `sudo install ./target/release/parity /usr/bin/parity`
3. 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.
## 4. Testing <a id="chapter-004"></a>
You can run tests with the following commands:
* **All** packages
```
cargo test --all
```
* Specific package
```
cargo test --package <spec>
```
Replace `<spec>` with one of the packages from the [package list](#package-list) (e.g. `cargo test --package evmbin`).
You can show your logs in the test output by passing `--nocapture` (i.e. `cargo test --package evmbin -- --nocapture`)
## 5. Documentation <a id="chapter-005"></a>
## 4. Documentation <a id="chapter-004"></a>
Official website: https://parity.io
@@ -179,20 +160,16 @@ You can generate documentation for Parity Ethereum Rust packages that automatica
* **All** packages
```
cargo doc --document-private-items --open
cargo doc --open
```
* Specific package
```
cargo doc --package <spec> -- --document-private-items --open
cargo doc --package <spec> --open
```
Use`--document-private-items` to also view private documentation and `--no-deps` to exclude building documentation for dependencies.
Replacing `<spec>` with one of the following from the details section below (i.e. `cargo doc --package parity-ethereum --open`):
<a id="package-list"></a>
**Package List**
<details><p>
* Parity Ethereum (EthCore) Client Application
@@ -353,7 +330,7 @@ Example (generic documentation comment):
///
```
## 6. Toolchain <a id="chapter-006"></a>
## 5. Toolchain <a id="chapter-005"></a>
In addition to the Parity Ethereum client, there are additional tools in this repository available:
@@ -365,7 +342,7 @@ In addition to the Parity Ethereum client, there are additional tools in this re
The following tool is available in a separate repository:
- [ethabi](https://github.com/paritytech/ethabi) - Parity Ethereum Encoding of Function Calls. [Docs here](https://crates.io/crates/ethabi)
## 7. Community <a id="chapter-007"></a>
## 6. Community <a id="chapter-006"></a>
### Join the chat!
@@ -378,7 +355,7 @@ Questions? Get in touch with us on Gitter:
Alternatively, join our community on Matrix:
[![Riot: +Parity](https://img.shields.io/badge/riot-%2Bparity%3Amatrix.parity.io-orange.svg)](https://riot.im/app/#/group/+parity:matrix.parity.io)
## 8. Contributing <a id="chapter-008"></a>
## 7. Contributing <a id="chapter-007"></a>
An introduction has been provided in the ["So You Want to be a Core Developer" presentation slides by Hernando Castano](http://tiny.cc/contrib-to-parity-eth). Additional guidelines are provided in [CONTRIBUTING](./.github/CONTRIBUTING.md).
@@ -386,6 +363,6 @@ An introduction has been provided in the ["So You Want to be a Core Developer" p
[CODE_OF_CONDUCT](./.github/CODE_OF_CONDUCT.md)
## 9. License <a id="chapter-009"></a>
## 8. License <a id="chapter-008"></a>
[LICENSE](./LICENSE)

View File

@@ -8,6 +8,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
[dependencies]
common-types = { path = "../ethcore/types" }
ethkey = { path = "ethkey" }
ethstore = { path = "ethstore" }
log = "0.4"
@@ -16,6 +17,12 @@ serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))'.dependencies]
hardware-wallet = { path = "hw" }
[target.'cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))'.dependencies]
fake-hardware-wallet = { path = "fake-hardware-wallet" }
[dev-dependencies]
ethereum-types = "0.6.0"
ethereum-types = "0.4"
tempdir = "0.3"

View File

@@ -6,16 +6,16 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
edit-distance = "2.0"
parity-crypto = "0.4.0"
parity-crypto = "0.3.0"
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" }
ethereum-types = "0.6.0"
ethereum-types = "0.4"
lazy_static = "1.0"
log = "0.4"
parity-wordlist = "1.3"
memzero = { path = "../../util/memzero" }
parity-wordlist = "1.2"
quick-error = "1.2.2"
rand = "0.6"
rand = "0.4"
rustc-hex = "1.0"
serde = "1.0"
serde_derive = "1.0"
tiny-keccak = "1.4"
zeroize = "0.9.1"

View File

@@ -47,7 +47,7 @@ impl Generator for BrainPrefix {
for _ in 0..self.iterations {
let phrase = wordlist::random_phrase(self.no_of_words);
let keypair = Brain::new(phrase.clone()).generate().unwrap();
if keypair.address().as_ref().starts_with(&self.prefix) {
if keypair.address().starts_with(&self.prefix) {
self.last_phrase = phrase;
return Ok(keypair)
}
@@ -65,6 +65,6 @@ mod tests {
fn prefix_generator() {
let prefix = vec![0x00u8];
let keypair = BrainPrefix::new(prefix.clone(), usize::max_value(), 12).generate().unwrap();
assert!(keypair.address().as_bytes().starts_with(&prefix));
assert!(keypair.address().starts_with(&prefix));
}
}

View File

@@ -57,7 +57,7 @@ pub mod ecdh {
};
let publ = key::PublicKey::from_slice(context, &pdata)?;
let sec = key::SecretKey::from_slice(context, secret.as_bytes())?;
let sec = key::SecretKey::from_slice(context, &secret)?;
let shared = ecdh::SharedSecret::new_raw(context, &publ, &sec);
Secret::from_unsafe_slice(&shared[0..32])
@@ -89,12 +89,12 @@ pub mod ecies {
msg[0] = 0x04u8;
{
let msgd = &mut msg[1..];
msgd[0..64].copy_from_slice(r.public().as_bytes());
msgd[0..64].copy_from_slice(r.public());
let iv = H128::random();
msgd[64..80].copy_from_slice(iv.as_bytes());
msgd[64..80].copy_from_slice(&iv);
{
let cipher = &mut msgd[(64 + 16)..(64 + 16 + plain.len())];
aes::encrypt_128_ctr(ekey, iv.as_bytes(), plain, cipher)?;
aes::encrypt_128_ctr(ekey, &iv, plain, cipher)?;
}
let mut hmac = hmac::Signer::with(&mkey);
{
@@ -156,7 +156,7 @@ pub mod ecies {
let mut hasher = digest::Hasher::sha256();
let ctrs = [(ctr >> 24) as u8, (ctr >> 16) as u8, (ctr >> 8) as u8, ctr as u8];
hasher.update(&ctrs);
hasher.update(secret.as_bytes());
hasher.update(secret);
hasher.update(s1);
let d = hasher.finish();
&mut dest[written..(written + 32)].copy_from_slice(&d);

View File

@@ -63,7 +63,7 @@ impl Label for H256 {
fn len() -> usize { 32 }
fn store(&self, target: &mut [u8]) {
(&mut target[0..32]).copy_from_slice(self.as_bytes());
self.copy_to(&mut target[0..32]);
}
}
@@ -179,7 +179,7 @@ impl ExtendedKeyPair {
pub fn with_seed(seed: &[u8]) -> Result<ExtendedKeyPair, DerivationError> {
let (master_key, chain_code) = derivation::seed_pair(seed);
Ok(ExtendedKeyPair::with_secret(
Secret::from_unsafe_slice(master_key.as_bytes()).map_err(|_| DerivationError::InvalidSeed)?,
Secret::from_unsafe_slice(&*master_key).map_err(|_| DerivationError::InvalidSeed)?,
chain_code,
))
}
@@ -207,13 +207,12 @@ impl ExtendedKeyPair {
// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
mod derivation {
use parity_crypto::hmac;
use ethereum_types::{BigEndianHash, U256, U512, H512, H256};
use ethereum_types::{U256, U512, H512, H256};
use secp256k1::key::{SecretKey, PublicKey};
use SECP256K1;
use keccak;
use math::curve_order;
use super::{Label, Derivation};
use std::convert::TryInto;
#[derive(Debug)]
pub enum Error {
@@ -237,18 +236,18 @@ mod derivation {
}
fn hmac_pair(data: &[u8], private_key: H256, chain_code: H256) -> (H256, H256) {
let private: U256 = private_key.into_uint();
let private: U256 = private_key.into();
// produces 512-bit derived hmac (I)
let skey = hmac::SigKey::sha512(chain_code.as_bytes());
let skey = hmac::SigKey::sha512(&*chain_code);
let i_512 = hmac::sign(&skey, &data[..]);
// left most 256 bits are later added to original private key
let hmac_key: U256 = H256::from_slice(&i_512[0..32]).into_uint();
let hmac_key: U256 = H256::from_slice(&i_512[0..32]).into();
// right most 256 bits are new chain code for later derivations
let next_chain_code = H256::from_slice(&i_512[32..64]);
let next_chain_code = H256::from(&i_512[32..64]);
let child_key = BigEndianHash::from_uint(&private_add(hmac_key, private));
let child_key = private_add(hmac_key, private).into();
(child_key, next_chain_code)
}
@@ -257,7 +256,7 @@ mod derivation {
fn private_soft<T>(private_key: H256, chain_code: H256, index: T) -> (H256, H256) where T: Label {
let mut data = vec![0u8; 33 + T::len()];
let sec_private = SecretKey::from_slice(&SECP256K1, private_key.as_bytes())
let sec_private = SecretKey::from_slice(&SECP256K1, &*private_key)
.expect("Caller should provide valid private key");
let sec_public = PublicKey::from_secret_key(&SECP256K1, &sec_private)
.expect("Caller should provide valid private key");
@@ -276,7 +275,7 @@ mod derivation {
// corresponding public keys of the original and derived private keys
fn private_hard<T>(private_key: H256, chain_code: H256, index: T) -> (H256, H256) where T: Label {
let mut data: Vec<u8> = vec![0u8; 33 + T::len()];
let private: U256 = private_key.into_uint();
let private: U256 = private_key.into();
// 0x00 (padding) -- private_key -- index
// 0 -- 1..33 -- 33..end
@@ -293,8 +292,9 @@ mod derivation {
// todo: surely can be optimized
fn modulo(u1: U512, u2: U256) -> U256 {
let m = u1 % U512::from(u2);
m.try_into().expect("U512 modulo U256 should fit into U256; qed")
let dv = u1 / U512::from(u2);
let md = u1 - (dv * U512::from(u2));
md.into()
}
pub fn public<T>(public_key: H512, chain_code: H256, derivation: Derivation<T>) -> Result<(H512, H256), Error> where T: Label {
@@ -305,7 +305,7 @@ mod derivation {
let mut public_sec_raw = [0u8; 65];
public_sec_raw[0] = 4;
public_sec_raw[1..65].copy_from_slice(public_key.as_bytes());
public_sec_raw[1..65].copy_from_slice(&*public_key);
let public_sec = PublicKey::from_slice(&SECP256K1, &public_sec_raw).map_err(|_| Error::InvalidPoint)?;
let public_serialized = public_sec.serialize_vec(&SECP256K1, true);
@@ -316,15 +316,15 @@ mod derivation {
index.store(&mut data[33..(33 + T::len())]);
// HMAC512SHA produces [derived private(256); new chain code(256)]
let skey = hmac::SigKey::sha512(chain_code.as_bytes());
let skey = hmac::SigKey::sha512(&*chain_code);
let i_512 = hmac::sign(&skey, &data[..]);
let new_private = H256::from_slice(&i_512[0..32]);
let new_chain_code = H256::from_slice(&i_512[32..64]);
let new_private = H256::from(&i_512[0..32]);
let new_chain_code = H256::from(&i_512[32..64]);
// Generated private key can (extremely rarely) be out of secp256k1 key field
if curve_order() <= new_private.into_uint() { return Err(Error::MissingIndex); }
let new_private_sec = SecretKey::from_slice(&SECP256K1, new_private.as_bytes())
if curve_order() <= new_private.clone().into() { return Err(Error::MissingIndex); }
let new_private_sec = SecretKey::from_slice(&SECP256K1, &*new_private)
.expect("Private key belongs to the field [0..CURVE_ORDER) (checked above); So initializing can never fail; qed");
let mut new_public = PublicKey::from_secret_key(&SECP256K1, &new_private_sec)
.expect("Valid private key produces valid public key");
@@ -336,7 +336,7 @@ mod derivation {
let serialized = new_public.serialize_vec(&SECP256K1, false);
Ok((
H512::from_slice(&serialized[1..65]),
H512::from(&serialized[1..65]),
new_chain_code,
))
}
@@ -347,18 +347,18 @@ mod derivation {
pub fn chain_code(secret: H256) -> H256 {
// 10,000 rounds of sha3
let mut running_sha3 = sha3(secret.as_bytes());
for _ in 0..99999 { running_sha3 = sha3(running_sha3.as_bytes()); }
let mut running_sha3 = sha3(&*secret);
for _ in 0..99999 { running_sha3 = sha3(&*running_sha3); }
running_sha3
}
pub fn point(secret: H256) -> Result<H512, Error> {
let sec = SecretKey::from_slice(&SECP256K1, secret.as_bytes())
let sec = SecretKey::from_slice(&SECP256K1, &*secret)
.map_err(|_| Error::InvalidPoint)?;
let public_sec = PublicKey::from_secret_key(&SECP256K1, &sec)
.map_err(|_| Error::InvalidPoint)?;
let serialized = public_sec.serialize_vec(&SECP256K1, false);
Ok(H512::from_slice(&serialized[1..65]))
Ok(H512::from(&serialized[1..65]))
}
pub fn seed_pair(seed: &[u8]) -> (H256, H256) {
@@ -377,13 +377,12 @@ mod tests {
use super::{ExtendedSecret, ExtendedPublic, ExtendedKeyPair};
use secret::Secret;
use std::str::FromStr;
use ethereum_types::{H128, H256, H512};
use ethereum_types::{H128, H256};
use super::{derivation, Derivation};
fn master_chain_basic() -> (H256, H256) {
let seed = H128::from_str("000102030405060708090a0b0c0d0e0f")
.expect("Seed should be valid H128")
.as_bytes()
.to_vec();
derivation::seed_pair(&*seed)
@@ -399,39 +398,27 @@ mod tests {
#[test]
fn smoky() {
let secret = Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65").unwrap();
let extended_secret = ExtendedSecret::with_code(secret.clone(), H256::zero());
let extended_secret = ExtendedSecret::with_code(secret.clone(), 0u64.into());
// hardened
assert_eq!(&**extended_secret.as_raw(), &*secret);
assert_eq!(
**extended_secret.derive(2147483648.into()).as_raw(),
H256::from_str("0927453daed47839608e414a3738dfad10aed17c459bbd9ab53f89b026c834b6").unwrap(),
);
assert_eq!(
**extended_secret.derive(2147483649.into()).as_raw(),
H256::from_str("44238b6a29c6dcbe9b401364141ba11e2198c289a5fed243a1c11af35c19dc0f").unwrap(),
);
assert_eq!(&**extended_secret.derive(2147483648.into()).as_raw(), &"0927453daed47839608e414a3738dfad10aed17c459bbd9ab53f89b026c834b6".into());
assert_eq!(&**extended_secret.derive(2147483649.into()).as_raw(), &"44238b6a29c6dcbe9b401364141ba11e2198c289a5fed243a1c11af35c19dc0f".into());
// normal
assert_eq!(**extended_secret.derive(0.into()).as_raw(), H256::from_str("bf6a74e3f7b36fc4c96a1e12f31abc817f9f5904f5a8fc27713163d1f0b713f6").unwrap());
assert_eq!(**extended_secret.derive(1.into()).as_raw(), H256::from_str("bd4fca9eb1f9c201e9448c1eecd66e302d68d4d313ce895b8c134f512205c1bc").unwrap());
assert_eq!(**extended_secret.derive(2.into()).as_raw(), H256::from_str("86932b542d6cab4d9c65490c7ef502d89ecc0e2a5f4852157649e3251e2a3268").unwrap());
assert_eq!(&**extended_secret.derive(0.into()).as_raw(), &"bf6a74e3f7b36fc4c96a1e12f31abc817f9f5904f5a8fc27713163d1f0b713f6".into());
assert_eq!(&**extended_secret.derive(1.into()).as_raw(), &"bd4fca9eb1f9c201e9448c1eecd66e302d68d4d313ce895b8c134f512205c1bc".into());
assert_eq!(&**extended_secret.derive(2.into()).as_raw(), &"86932b542d6cab4d9c65490c7ef502d89ecc0e2a5f4852157649e3251e2a3268".into());
let extended_public = ExtendedPublic::from_secret(&extended_secret).expect("Extended public should be created");
let derived_public = extended_public.derive(0.into()).expect("First derivation of public should succeed");
assert_eq!(
*derived_public.public(),
H512::from_str("f7b3244c96688f92372bfd4def26dc4151529747bab9f188a4ad34e141d47bd66522ff048bc6f19a0a4429b04318b1a8796c000265b4fa200dae5f6dda92dd94").unwrap(),
);
assert_eq!(&*derived_public.public(), &"f7b3244c96688f92372bfd4def26dc4151529747bab9f188a4ad34e141d47bd66522ff048bc6f19a0a4429b04318b1a8796c000265b4fa200dae5f6dda92dd94".into());
let keypair = ExtendedKeyPair::with_secret(
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65").unwrap(),
H256::from_low_u64_be(64),
);
assert_eq!(
**keypair.derive(2147483648u32.into()).expect("Derivation of keypair should succeed").secret().as_raw(),
H256::from_str("edef54414c03196557cf73774bc97a645c9a1df2164ed34f0c2a78d1375a930c").unwrap(),
064.into(),
);
assert_eq!(&**keypair.derive(2147483648u32.into()).expect("Derivation of keypair should succeed").secret().as_raw(), &"edef54414c03196557cf73774bc97a645c9a1df2164ed34f0c2a78d1375a930c".into());
}
#[test]
@@ -439,7 +426,7 @@ mod tests {
let secret = Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65").unwrap();
let derivation_secret = H256::from_str("51eaf04f9dbbc1417dc97e789edd0c37ecda88bac490434e367ea81b71b7b015").unwrap();
let extended_secret = ExtendedSecret::with_code(secret.clone(), H256::zero());
let extended_secret = ExtendedSecret::with_code(secret.clone(), 0u64.into());
let extended_public = ExtendedPublic::from_secret(&extended_secret).expect("Extended public should be created");
let derived_secret0 = extended_secret.derive(Derivation::Soft(derivation_secret));
@@ -454,18 +441,15 @@ mod tests {
fn h256_hard() {
let secret = Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65").unwrap();
let derivation_secret = H256::from_str("51eaf04f9dbbc1417dc97e789edd0c37ecda88bac490434e367ea81b71b7b015").unwrap();
let extended_secret = ExtendedSecret::with_code(secret.clone(), H256::from_low_u64_be(1));
let extended_secret = ExtendedSecret::with_code(secret.clone(), 1u64.into());
assert_eq!(
**extended_secret.derive(Derivation::Hard(derivation_secret)).as_raw(),
H256::from_str("2bc2d696fb744d77ff813b4a1ef0ad64e1e5188b622c54ba917acc5ebc7c5486").unwrap(),
);
assert_eq!(&**extended_secret.derive(Derivation::Hard(derivation_secret)).as_raw(), &"2bc2d696fb744d77ff813b4a1ef0ad64e1e5188b622c54ba917acc5ebc7c5486".into());
}
#[test]
fn match_() {
let secret = Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65").unwrap();
let extended_secret = ExtendedSecret::with_code(secret.clone(), H256::from_low_u64_be(1));
let extended_secret = ExtendedSecret::with_code(secret.clone(), 1.into());
let extended_public = ExtendedPublic::from_secret(&extended_secret).expect("Extended public should be created");
let derived_secret0 = extended_secret.derive(0.into());
@@ -480,7 +464,6 @@ mod tests {
fn test_seeds() {
let seed = H128::from_str("000102030405060708090a0b0c0d0e0f")
.expect("Seed should be valid H128")
.as_bytes()
.to_vec();
// private key from bitcoin test vector

View File

@@ -16,13 +16,14 @@
use std::fmt;
use secp256k1::key;
use rustc_hex::ToHex;
use keccak::Keccak256;
use super::{Secret, Public, Address, SECP256K1, Error};
use parity_crypto::Keccak256 as _;
pub fn public_to_address(public: &Public) -> Address {
let hash = public.keccak256();
let mut result = Address::zero();
result.as_bytes_mut().copy_from_slice(&hash[12..]);
let mut result = Address::default();
result.copy_from_slice(&hash[12..]);
result
}
@@ -35,9 +36,9 @@ pub struct KeyPair {
impl fmt::Display for KeyPair {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
writeln!(f, "secret: {:x}", self.secret)?;
writeln!(f, "public: {:x}", self.public)?;
write!(f, "address: {:x}", self.address())
writeln!(f, "secret: {}", self.secret.to_hex())?;
writeln!(f, "public: {}", self.public.to_hex())?;
write!(f, "address: {}", self.address().to_hex())
}
}
@@ -50,7 +51,7 @@ impl KeyPair {
let serialized = pub_key.serialize_vec(context, false);
let mut public = Public::default();
public.as_bytes_mut().copy_from_slice(&serialized[1..65]);
public.copy_from_slice(&serialized[1..65]);
let keypair = KeyPair {
secret: secret,
@@ -69,7 +70,7 @@ impl KeyPair {
let serialized = publ.serialize_vec(context, false);
let secret = Secret::from(sec);
let mut public = Public::default();
public.as_bytes_mut().copy_from_slice(&serialized[1..65]);
public.copy_from_slice(&serialized[1..65]);
KeyPair {
secret: secret,

View File

@@ -19,6 +19,7 @@
extern crate edit_distance;
extern crate parity_crypto;
extern crate ethereum_types;
extern crate memzero;
extern crate parity_wordlist;
#[macro_use]
extern crate quick_error;
@@ -27,7 +28,6 @@ extern crate rustc_hex;
extern crate secp256k1;
extern crate serde;
extern crate tiny_keccak;
extern crate zeroize;
#[macro_use]
extern crate lazy_static;

View File

@@ -17,7 +17,7 @@
use super::{SECP256K1, Public, Secret, Error};
use secp256k1::key;
use secp256k1::constants::{GENERATOR_X, GENERATOR_Y, CURVE_ORDER};
use ethereum_types::{BigEndianHash as _, U256, H256};
use ethereum_types::{U256, H256};
/// Whether the public key is valid.
pub fn public_is_valid(public: &Public) -> bool {
@@ -78,7 +78,7 @@ pub fn generation_point() -> Public {
/// Return secp256k1 elliptic curve order
pub fn curve_order() -> U256 {
H256::from_slice(&CURVE_ORDER).into_uint()
H256::from_slice(&CURVE_ORDER).into()
}
fn to_secp256k1_public(public: &Public) -> Result<key::PublicKey, Error> {
@@ -93,7 +93,7 @@ fn to_secp256k1_public(public: &Public) -> Result<key::PublicKey, Error> {
fn set_public(public: &mut Public, key_public: &key::PublicKey) {
let key_public_serialized = key_public.serialize_vec(&SECP256K1, false);
public.as_bytes_mut().copy_from_slice(&key_public_serialized[1..65]);
public.copy_from_slice(&key_public_serialized[1..65]);
}
#[cfg(test)]

View File

@@ -37,7 +37,7 @@ impl Generator for Prefix {
fn generate(&mut self) -> Result<KeyPair, Error> {
for _ in 0..self.iterations {
let keypair = Random.generate()?;
if keypair.address().as_ref().starts_with(&self.prefix) {
if keypair.address().starts_with(&self.prefix) {
return Ok(keypair)
}
}
@@ -54,6 +54,6 @@ mod tests {
fn prefix_generator() {
let prefix = vec![0xffu8];
let keypair = Prefix::new(prefix.clone(), usize::max_value()).generate().unwrap();
assert!(keypair.address().as_bytes().starts_with(&prefix));
assert!(keypair.address().starts_with(&prefix));
}
}

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
use rand::rngs::OsRng;
use rand::os::OsRng;
use super::{Generator, KeyPair, SECP256K1};
/// Randomly generates new keypair, instantiating the RNG each time.

View File

@@ -21,23 +21,17 @@ use rustc_hex::ToHex;
use secp256k1::constants::{SECRET_KEY_SIZE as SECP256K1_SECRET_KEY_SIZE};
use secp256k1::key;
use ethereum_types::H256;
use zeroize::Zeroize;
use memzero::Memzero;
use {Error, SECP256K1};
#[derive(Clone, PartialEq, Eq)]
pub struct Secret {
inner: H256,
}
impl Drop for Secret {
fn drop(&mut self) {
self.inner.0.zeroize()
}
inner: Memzero<H256>,
}
impl ToHex for Secret {
fn to_hex(&self) -> String {
format!("{:x}", self.inner)
format!("{:x}", *self.inner)
}
}
@@ -65,14 +59,14 @@ impl Secret {
if key.len() != 32 {
return None
}
let mut h = H256::zero();
h.as_bytes_mut().copy_from_slice(&key[0..32]);
Some(Secret { inner: h })
let mut h = H256::default();
h.copy_from_slice(&key[0..32]);
Some(Secret { inner: Memzero::from(h) })
}
/// Creates zero key, which is invalid for crypto operations, but valid for math operation.
pub fn zero() -> Self {
Secret { inner: H256::zero() }
Secret { inner: Memzero::from(H256::default()) }
}
/// Imports and validates the key.
@@ -220,7 +214,7 @@ impl FromStr for Secret {
impl From<[u8; 32]> for Secret {
fn from(k: [u8; 32]) -> Self {
Secret { inner: H256(k) }
Secret { inner: Memzero::from(H256(k)) }
}
}

View File

@@ -68,44 +68,24 @@ impl Signature {
/// Create a signature object from the sig.
pub fn from_rsv(r: &H256, s: &H256, v: u8) -> Self {
let mut sig = [0u8; 65];
sig[0..32].copy_from_slice(r.as_ref());
sig[32..64].copy_from_slice(s.as_ref());
sig[0..32].copy_from_slice(&r);
sig[32..64].copy_from_slice(&s);
sig[64] = v;
Signature(sig)
}
/// Check if this is a "low" signature.
pub fn is_low_s(&self) -> bool {
// "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0"
const MASK: H256 = H256([
0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x5D, 0x57, 0x6E, 0x73, 0x57, 0xA4, 0x50, 0x1D,
0xDF, 0xE9, 0x2F, 0x46, 0x68, 0x1B, 0x20, 0xA0,
]);
H256::from_slice(self.s()) <= MASK
H256::from_slice(self.s()) <= "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0".into()
}
/// Check if each component of the signature is in range.
pub fn is_valid(&self) -> bool {
// "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"
const MASK: H256 = H256([
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41,
]);
const ONE: H256 = H256([
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
]);
let r = H256::from_slice(self.r());
let s = H256::from_slice(self.s());
self.v() <= 1 &&
r < MASK && r >= ONE &&
s < MASK && s >= ONE
H256::from_slice(self.r()) < "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141".into() &&
H256::from_slice(self.r()) >= 1.into() &&
H256::from_slice(self.s()) < "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141".into() &&
H256::from_slice(self.s()) >= 1.into()
}
}
@@ -210,7 +190,7 @@ impl DerefMut for Signature {
pub fn sign(secret: &Secret, message: &Message) -> Result<Signature, Error> {
let context = &SECP256K1;
let sec = SecretKey::from_slice(context, secret.as_ref())?;
let sec = SecretKey::from_slice(context, &secret)?;
let s = context.sign_recoverable(&SecpMessage::from_slice(&message[..])?, &sec)?;
let (rec_id, data) = s.serialize_compact(context);
let mut data_arr = [0; 65];
@@ -228,7 +208,7 @@ pub fn verify_public(public: &Public, signature: &Signature, message: &Message)
let pdata: [u8; 65] = {
let mut temp = [4u8; 65];
temp[1..65].copy_from_slice(public.as_bytes());
temp[1..65].copy_from_slice(&**public);
temp
};
@@ -253,7 +233,7 @@ pub fn recover(signature: &Signature, message: &Message) -> Result<Public, Error
let serialized = pubkey.serialize_vec(context, false);
let mut public = Public::default();
public.as_bytes_mut().copy_from_slice(&serialized[1..65]);
public.copy_from_slice(&serialized[1..65]);
Ok(public)
}

View File

@@ -7,7 +7,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
log = "0.4"
libc = "0.2"
rand = "0.6"
rand = "0.4"
ethkey = { path = "../ethkey" }
serde = "1.0"
serde_json = "1.0"
@@ -17,12 +17,13 @@ tiny-keccak = "1.4"
time = "0.1.34"
itertools = "0.5"
parking_lot = "0.7"
parity-crypto = "0.4.0"
ethereum-types = "0.6.0"
parity-crypto = "0.3.0"
ethereum-types = "0.4"
dir = { path = "../../util/dir" }
smallvec = "0.6"
parity-wordlist = "1.0"
tempdir = "0.3"
lazy_static = "1.2.0"
[dev-dependencies]
matches = "0.1"

View File

@@ -22,4 +22,4 @@ path = "src/main.rs"
doc = false
[dev-dependencies]
tempdir = "0.3"
tempdir = "0.3.5"

View File

@@ -15,6 +15,7 @@
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
use std::str;
use std::num::NonZeroU32;
use ethkey::{Password, Secret};
use {json, Error, crypto};
use crypto::Keccak256;
@@ -73,12 +74,12 @@ impl From<Crypto> for String {
impl Crypto {
/// Encrypt account secret
pub fn with_secret(secret: &Secret, password: &Password, iterations: u32) -> Result<Self, crypto::Error> {
Crypto::with_plain(secret.as_ref(), password, iterations)
pub fn with_secret(secret: &Secret, password: &Password, iterations: NonZeroU32) -> Result<Self, crypto::Error> {
Crypto::with_plain(&*secret, password, iterations)
}
/// Encrypt custom plain data
pub fn with_plain(plain: &[u8], password: &Password, iterations: u32) -> Result<Self, crypto::Error> {
pub fn with_plain(plain: &[u8], password: &Password, iterations: NonZeroU32) -> Result<Self, crypto::Error> {
let salt: [u8; 32] = Random::random();
let iv: [u8; 16] = Random::random();
@@ -159,13 +160,17 @@ impl Crypto {
#[cfg(test)]
mod tests {
use ethkey::{Generator, Random};
use super::{Crypto, Error};
use super::{Crypto, Error, NonZeroU32};
lazy_static! {
static ref ITERATIONS: NonZeroU32 = NonZeroU32::new(10240).expect("10240 > 0; qed");
}
#[test]
fn crypto_with_secret_create() {
let keypair = Random.generate().unwrap();
let passwd = "this is sparta".into();
let crypto = Crypto::with_secret(keypair.secret(), &passwd, 10240).unwrap();
let crypto = Crypto::with_secret(keypair.secret(), &passwd, *ITERATIONS).unwrap();
let secret = crypto.secret(&passwd).unwrap();
assert_eq!(keypair.secret(), &secret);
}
@@ -173,7 +178,7 @@ mod tests {
#[test]
fn crypto_with_secret_invalid_password() {
let keypair = Random.generate().unwrap();
let crypto = Crypto::with_secret(keypair.secret(), &"this is sparta".into(), 10240).unwrap();
let crypto = Crypto::with_secret(keypair.secret(), &"this is sparta".into(), *ITERATIONS).unwrap();
assert_matches!(crypto.secret(&"this is sparta!".into()), Err(Error::InvalidPassword))
}
@@ -181,7 +186,7 @@ mod tests {
fn crypto_with_null_plain_data() {
let original_data = b"";
let passwd = "this is sparta".into();
let crypto = Crypto::with_plain(&original_data[..], &passwd, 10240).unwrap();
let crypto = Crypto::with_plain(&original_data[..], &passwd, *ITERATIONS).unwrap();
let decrypted_data = crypto.decrypt(&passwd).unwrap();
assert_eq!(original_data[..], *decrypted_data);
}
@@ -190,7 +195,7 @@ mod tests {
fn crypto_with_tiny_plain_data() {
let original_data = b"{}";
let passwd = "this is sparta".into();
let crypto = Crypto::with_plain(&original_data[..], &passwd, 10240).unwrap();
let crypto = Crypto::with_plain(&original_data[..], &passwd, *ITERATIONS).unwrap();
let decrypted_data = crypto.decrypt(&passwd).unwrap();
assert_eq!(original_data[..], *decrypted_data);
}
@@ -199,7 +204,7 @@ mod tests {
fn crypto_with_huge_plain_data() {
let original_data: Vec<_> = (1..65536).map(|i| (i % 256) as u8).collect();
let passwd = "this is sparta".into();
let crypto = Crypto::with_plain(&original_data, &passwd, 10240).unwrap();
let crypto = Crypto::with_plain(&original_data, &passwd, *ITERATIONS).unwrap();
let decrypted_data = crypto.decrypt(&passwd).unwrap();
assert_eq!(&original_data, &decrypted_data);
}

View File

@@ -15,6 +15,7 @@
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
use json;
use std::num::NonZeroU32;
#[derive(Debug, PartialEq, Clone)]
pub enum Prf {
@@ -23,7 +24,7 @@ pub enum Prf {
#[derive(Debug, PartialEq, Clone)]
pub struct Pbkdf2 {
pub c: u32,
pub c: NonZeroU32,
pub dklen: u32,
pub prf: Prf,
pub salt: Vec<u8>,

View File

@@ -20,6 +20,7 @@ use {json, Error};
use account::Version;
use crypto;
use super::crypto::Crypto;
use std::num::NonZeroU32;
/// Account representation.
#[derive(Debug, PartialEq, Clone)]
@@ -59,7 +60,7 @@ impl SafeAccount {
keypair: &KeyPair,
id: [u8; 16],
password: &Password,
iterations: u32,
iterations: NonZeroU32,
name: String,
meta: String
) -> Result<Self, crypto::Error> {
@@ -135,7 +136,7 @@ impl SafeAccount {
}
/// Create a new `VaultKeyFile` from the given `self`
pub fn into_vault_file(self, iterations: u32, password: &Password) -> Result<json::VaultKeyFile, Error> {
pub fn into_vault_file(self, iterations: NonZeroU32, password: &Password) -> Result<json::VaultKeyFile, Error> {
let meta_plain = json::VaultKeyMeta {
address: self.address.into(),
name: Some(self.name),
@@ -177,7 +178,7 @@ impl SafeAccount {
}
/// Change account's password.
pub fn change_password(&self, old_password: &Password, new_password: &Password, iterations: u32) -> Result<Self, Error> {
pub fn change_password(&self, old_password: &Password, new_password: &Password, iterations: NonZeroU32) -> Result<Self, Error> {
let secret = self.crypto.secret(old_password)?;
let result = SafeAccount {
id: self.id.clone(),
@@ -200,14 +201,19 @@ impl SafeAccount {
#[cfg(test)]
mod tests {
use ethkey::{Generator, Random, verify_public, Message};
use super::SafeAccount;
use super::{SafeAccount, NonZeroU32};
lazy_static! {
static ref ITERATIONS: NonZeroU32 = NonZeroU32::new(10240).expect("10240 > 0; qed");
}
#[test]
fn sign_and_verify_public() {
let keypair = Random.generate().unwrap();
let password = "hello world".into();
let message = Message::default();
let account = SafeAccount::create(&keypair, [0u8; 16], &password, 10240, "Test".to_owned(), "{}".to_owned());
let account = SafeAccount::create(&keypair, [0u8; 16], &password, *ITERATIONS, "Test".to_owned(), "{}".to_owned());
let signature = account.unwrap().sign(&password, &message).unwrap();
assert!(verify_public(keypair.public(), &signature, &message).unwrap());
}
@@ -217,10 +223,9 @@ mod tests {
let keypair = Random.generate().unwrap();
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();
let account = SafeAccount::create(&keypair, [0u8; 16], &first_password, *ITERATIONS, "Test".to_owned(), "{}".to_owned()).unwrap();
let new_account = account.change_password(&first_password, &sec_password, *ITERATIONS).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());

View File

@@ -61,6 +61,7 @@ pub fn find_unique_filename_using_random_suffix(parent_path: &Path, original_fil
/// 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<fs::File> {
use libc;
use std::os::unix::fs::OpenOptionsExt;
fs::OpenOptions::new()
@@ -82,6 +83,7 @@ pub fn create_new_file_with_permissions_to_owner(file_path: &Path) -> io::Result
/// 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<fs::File> {
use libc;
use std::os::unix::fs::PermissionsExt;
let file = fs::File::create(file_path)?;
@@ -354,11 +356,16 @@ mod test {
extern crate tempdir;
use std::{env, fs};
use std::num::NonZeroU32;
use super::{KeyDirectory, RootDiskDirectory, VaultKey};
use account::SafeAccount;
use ethkey::{Random, Generator};
use self::tempdir::TempDir;
lazy_static! {
static ref ITERATIONS: NonZeroU32 = NonZeroU32::new(1024).expect("1024 > 0; qed");
}
#[test]
fn should_create_new_account() {
// given
@@ -369,7 +376,7 @@ mod test {
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, *ITERATIONS, "Test".to_owned(), "{}".to_owned());
let res = directory.insert(account.unwrap());
// then
@@ -390,7 +397,7 @@ mod test {
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, *ITERATIONS, "Test".to_owned(), "{}".to_owned()).unwrap();
let filename = "test".to_string();
let dedup = true;
@@ -426,7 +433,7 @@ mod test {
// 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, *ITERATIONS));
// then
assert!(vault.is_ok());
@@ -434,7 +441,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, *ITERATIONS));
// then
assert!(vault.is_ok());
@@ -451,8 +458,9 @@ 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".into(), 1)).unwrap();
vault_provider.create("vault2", VaultKey::new(&"password2".into(), 1)).unwrap();
let iter = NonZeroU32::new(1).expect("1 > 0; qed");
vault_provider.create("vault1", VaultKey::new(&"password1".into(), iter)).unwrap();
vault_provider.create("vault2", VaultKey::new(&"password2".into(), iter)).unwrap();
// then
let vaults = vault_provider.list_vaults().unwrap();
@@ -474,7 +482,7 @@ mod test {
let keypair = Random.generate().unwrap();
let password = "test pass".into();
let account = SafeAccount::create(&keypair, [0u8; 16], &password, 1024, "Test".to_owned(), "{}".to_owned());
let account = SafeAccount::create(&keypair, [0u8; 16], &password, *ITERATIONS, "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");

View File

@@ -68,7 +68,7 @@ impl KeyDirectory for MemoryDirectory {
fn unique_repr(&self) -> Result<u64, Error> {
let mut val = 0u64;
let accounts = self.accounts.read();
for acc in accounts.keys() { val = val ^ acc.to_low_u64_be() }
for acc in accounts.keys() { val = val ^ acc.low_u64() }
Ok(val)
}
}

View File

@@ -17,6 +17,7 @@
//! Accounts Directory
use ethkey::Password;
use std::num::NonZeroU32;
use std::path::{PathBuf};
use {SafeAccount, Error};
@@ -41,7 +42,7 @@ pub struct VaultKey {
/// Vault password
pub password: Password,
/// Number of iterations to produce a derived key from password
pub iterations: u32,
pub iterations: NonZeroU32,
}
/// Keys directory
@@ -96,7 +97,7 @@ pub use self::vault::VaultDiskDirectory;
impl VaultKey {
/// Create new vault key
pub fn new(password: &Password, iterations: u32) -> Self {
pub fn new(password: &Password, iterations: NonZeroU32) -> Self {
VaultKey {
password: password.clone(),
iterations: iterations,

View File

@@ -282,11 +282,17 @@ mod test {
use std::fs;
use std::io::Write;
use std::num::NonZeroU32;
use std::path::PathBuf;
use super::VaultKey;
use super::{VAULT_FILE_NAME, check_vault_name, make_vault_dir_path, create_vault_file, read_vault_file, VaultDiskDirectory};
use self::tempdir::TempDir;
lazy_static! {
static ref ITERATIONS: NonZeroU32 = NonZeroU32::new(1024).expect("1024 > 0; qed");
}
#[test]
fn check_vault_name_succeeds() {
assert!(check_vault_name("vault"));
@@ -325,7 +331,7 @@ mod test {
fn create_vault_file_succeeds() {
// given
let temp_path = TempDir::new("").unwrap();
let key = VaultKey::new(&"password".into(), 1024);
let key = VaultKey::new(&"password".into(), *ITERATIONS);
let mut vault_dir: PathBuf = temp_path.path().into();
vault_dir.push("vault");
fs::create_dir_all(&vault_dir).unwrap();
@@ -344,7 +350,7 @@ mod test {
fn read_vault_file_succeeds() {
// given
let temp_path = TempDir::new("").unwrap();
let key = VaultKey::new(&"password".into(), 1024);
let key = VaultKey::new(&"password".into(), *ITERATIONS);
let vault_file_contents = r#"{"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"758696c8dc6378ab9b25bb42790da2f5"},"ciphertext":"54eb50683717d41caaeb12ea969f2c159daada5907383f26f327606a37dc7168","kdf":"pbkdf2","kdfparams":{"c":1024,"dklen":32,"prf":"hmac-sha256","salt":"3c320fa566a1a7963ac8df68a19548d27c8f40bf92ef87c84594dcd5bbc402b6"},"mac":"9e5c2314c2a0781962db85611417c614bd6756666b6b1e93840f5b6ed895f003"}}"#;
let dir: PathBuf = temp_path.path().into();
let mut vault_file_path: PathBuf = dir.clone();
@@ -365,7 +371,7 @@ mod test {
fn read_vault_file_fails() {
// given
let temp_path = TempDir::new("").unwrap();
let key = VaultKey::new(&"password1".into(), 1024);
let key = VaultKey::new(&"password1".into(), *ITERATIONS);
let dir: PathBuf = temp_path.path().into();
let mut vault_file_path: PathBuf = dir.clone();
vault_file_path.push(VAULT_FILE_NAME);
@@ -394,7 +400,7 @@ mod test {
fn vault_directory_can_be_created() {
// given
let temp_path = TempDir::new("").unwrap();
let key = VaultKey::new(&"password".into(), 1024);
let key = VaultKey::new(&"password".into(), *ITERATIONS);
let dir: PathBuf = temp_path.path().into();
// when
@@ -414,7 +420,7 @@ mod test {
fn vault_directory_cannot_be_created_if_already_exists() {
// given
let temp_path = TempDir::new("").unwrap();
let key = VaultKey::new(&"password".into(), 1024);
let key = VaultKey::new(&"password".into(), *ITERATIONS);
let dir: PathBuf = temp_path.path().into();
let mut vault_dir = dir.clone();
vault_dir.push("vault");
@@ -431,7 +437,7 @@ mod test {
fn vault_directory_cannot_be_opened_if_not_exists() {
// given
let temp_path = TempDir::new("").unwrap();
let key = VaultKey::new(&"password".into(), 1024);
let key = VaultKey::new(&"password".into(), *ITERATIONS);
let dir: PathBuf = temp_path.path().into();
// when

View File

@@ -15,12 +15,12 @@
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
use std::collections::{BTreeMap, HashMap};
use std::num::NonZeroU32;
use std::mem;
use std::path::PathBuf;
use parking_lot::{Mutex, RwLock};
use std::time::{Instant, Duration};
use crypto::KEY_ITERATIONS;
use random::Random;
use ethkey::{self, Signature, Password, Address, Message, Secret, Public, KeyPair, ExtendedKeyPair};
use accounts_dir::{KeyDirectory, VaultKeyDirectory, VaultKey, SetKeyError};
@@ -29,6 +29,12 @@ use presale::PresaleWallet;
use json::{self, Uuid, OpaqueKeyFile};
use {import, Error, SimpleSecretStore, SecretStore, SecretVaultRef, StoreAccountRef, Derivation, OpaqueSecret};
lazy_static! {
static ref KEY_ITERATIONS: NonZeroU32 =
NonZeroU32::new(crypto::KEY_ITERATIONS as u32).expect("KEY_ITERATIONS > 0; qed");
}
/// Accounts store.
pub struct EthStore {
store: EthMultiStore,
@@ -37,11 +43,11 @@ pub struct EthStore {
impl EthStore {
/// Open a new accounts store with given key directory backend.
pub fn open(directory: Box<KeyDirectory>) -> Result<Self, Error> {
Self::open_with_iterations(directory, KEY_ITERATIONS as u32)
Self::open_with_iterations(directory, *KEY_ITERATIONS)
}
/// Open a new account store with given key directory backend and custom number of iterations.
pub fn open_with_iterations(directory: Box<KeyDirectory>, iterations: u32) -> Result<Self, Error> {
pub fn open_with_iterations(directory: Box<KeyDirectory>, iterations: NonZeroU32) -> Result<Self, Error> {
Ok(EthStore {
store: EthMultiStore::open_with_iterations(directory, iterations)?,
})
@@ -257,7 +263,7 @@ impl SecretStore for EthStore {
/// Similar to `EthStore` but may store many accounts (with different passwords) for the same `Address`
pub struct EthMultiStore {
dir: Box<KeyDirectory>,
iterations: u32,
iterations: NonZeroU32,
// order lock: cache, then vaults
cache: RwLock<BTreeMap<StoreAccountRef, Vec<SafeAccount>>>,
vaults: Mutex<HashMap<String, Box<VaultKeyDirectory>>>,
@@ -273,11 +279,11 @@ struct Timestamp {
impl EthMultiStore {
/// Open new multi-accounts store with given key directory backend.
pub fn open(directory: Box<KeyDirectory>) -> Result<Self, Error> {
Self::open_with_iterations(directory, KEY_ITERATIONS as u32)
Self::open_with_iterations(directory, *KEY_ITERATIONS)
}
/// Open new multi-accounts store with given key directory backend and custom number of iterations for new keys.
pub fn open_with_iterations(directory: Box<KeyDirectory>, iterations: u32) -> Result<Self, Error> {
pub fn open_with_iterations(directory: Box<KeyDirectory>, iterations: NonZeroU32) -> Result<Self, Error> {
let store = EthMultiStore {
dir: directory,
vaults: Mutex::new(HashMap::new()),
@@ -1084,7 +1090,7 @@ mod tests {
SecretVaultRef::Root,
&address,
&"test".into(),
Derivation::HardHash(H256::zero()),
Derivation::HardHash(H256::from(0)),
).unwrap();
// there should be 2 accounts in the store

View File

@@ -41,7 +41,7 @@ impl str::FromStr for Crypto {
impl From<Crypto> for String {
fn from(c: Crypto) -> Self {
serde_json::to_string(&c).expect("Serialization cannot fail, because all crypto keys are strings")
serde_json::to_string(&c).expect("serialization cannot fail, cause all crypto keys are strings")
}
}

View File

@@ -15,6 +15,7 @@
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
use std::fmt;
use std::num::NonZeroU32;
use serde::{Serialize, Serializer, Deserialize, Deserializer};
use serde::de::{Visitor, Error as SerdeError};
use super::{Error, Bytes};
@@ -108,7 +109,7 @@ impl<'a> Visitor<'a> for PrfVisitor {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Pbkdf2 {
pub c: u32,
pub c: NonZeroU32,
pub dklen: u32,
pub prf: Prf,
pub salt: Bytes,

View File

@@ -41,6 +41,11 @@ impl VaultFile {
mod test {
use serde_json;
use json::{VaultFile, Crypto, Cipher, Aes128Ctr, Kdf, Pbkdf2, Prf};
use std::num::NonZeroU32;
lazy_static! {
static ref ITERATIONS: NonZeroU32 = NonZeroU32::new(1024).expect("1024 > 0; qed");
}
#[test]
fn to_and_from_json() {
@@ -51,7 +56,7 @@ mod test {
}),
ciphertext: "4d6938a1f49b7782".into(),
kdf: Kdf::Pbkdf2(Pbkdf2 {
c: 1024,
c: *ITERATIONS,
dklen: 32,
prf: Prf::HmacSha256,
salt: "b6a9338a7ccd39288a86dba73bfecd9101b4f3db9c9830e7c76afdbd4f6872e5".into(),
@@ -76,7 +81,7 @@ mod test {
}),
ciphertext: "4d6938a1f49b7782".into(),
kdf: Kdf::Pbkdf2(Pbkdf2 {
c: 1024,
c: *ITERATIONS,
dklen: 32,
prf: Prf::HmacSha256,
salt: "b6a9338a7ccd39288a86dba73bfecd9101b4f3db9c9830e7c76afdbd4f6872e5".into(),

View File

@@ -106,6 +106,11 @@ mod test {
use serde_json;
use json::{VaultKeyFile, Version, Crypto, Cipher, Aes128Ctr, Kdf, Pbkdf2, Prf,
insert_vault_name_to_json_meta, remove_vault_name_from_json_meta};
use std::num::NonZeroU32;
lazy_static! {
static ref ITERATIONS: NonZeroU32 = NonZeroU32::new(10240).expect("10240 > 0; qed");
}
#[test]
fn to_and_from_json() {
@@ -118,7 +123,7 @@ mod test {
}),
ciphertext: "4befe0a66d9a4b6fec8e39eb5c90ac5dafdeaab005fff1af665fd1f9af925c91".into(),
kdf: Kdf::Pbkdf2(Pbkdf2 {
c: 10240,
c: *ITERATIONS,
dklen: 32,
prf: Prf::HmacSha256,
salt: "f17731e84ecac390546692dbd4ccf6a3a2720dc9652984978381e61c28a471b2".into(),
@@ -131,7 +136,7 @@ mod test {
}),
ciphertext: "fef0d113d7576c1702daf380ad6f4c5408389e57991cae2a174facd74bd549338e1014850bddbab7eb486ff5f5c9c5532800c6a6d4db2be2212cd5cd3769244ab230e1f369e8382a9e6d7c0a".into(),
kdf: Kdf::Pbkdf2(Pbkdf2 {
c: 10240,
c: *ITERATIONS,
dklen: 32,
prf: Prf::HmacSha256,
salt: "aca82865174a82249a198814b263f43a631f272cbf7ed329d0f0839d259c652a".into(),

View File

@@ -36,6 +36,8 @@ extern crate ethereum_types;
extern crate ethkey as _ethkey;
extern crate parity_wordlist;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[macro_use]

View File

@@ -15,6 +15,7 @@
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
use std::fs;
use std::num::NonZeroU32;
use std::path::Path;
use json;
use ethkey::{Address, Secret, KeyPair, Password};
@@ -58,7 +59,8 @@ impl PresaleWallet {
let mut derived_key = [0u8; 32];
let salt = pbkdf2::Salt(password.as_bytes());
let sec = pbkdf2::Secret(password.as_bytes());
pbkdf2::sha256(2000, salt, sec, &mut derived_key);
let iter = NonZeroU32::new(2000).expect("2000 > 0; qed");
pbkdf2::sha256(iter, salt, sec, &mut derived_key);
let mut key = vec![0; self.ciphertext.len()];
let len = crypto::aes::decrypt_128_cbc(&derived_key[0..16], &self.iv, &self.ciphertext, &mut key)

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
use rand::{Rng, RngCore, rngs::OsRng, distributions::Alphanumeric};
use rand::{Rng, OsRng};
pub trait Random {
fn random() -> Self where Self: Sized;
@@ -41,5 +41,5 @@ impl Random for [u8; 32] {
/// Generate a random string of given length.
pub fn random_string(length: usize) -> String {
let mut rng = OsRng::new().expect("Not able to operate without random source.");
rng.sample_iter(&Alphanumeric).take(length).collect()
rng.gen_ascii_chars().take(length).collect()
}

View File

@@ -16,7 +16,6 @@
extern crate rand;
extern crate ethstore;
extern crate ethereum_types;
mod util;
@@ -24,8 +23,6 @@ use ethstore::{EthStore, SimpleSecretStore, SecretVaultRef, StoreAccountRef};
use ethstore::ethkey::{Random, Generator, Secret, KeyPair, verify_address};
use ethstore::accounts_dir::RootDiskDirectory;
use util::TransientDir;
use ethereum_types::Address;
use std::str::FromStr;
#[test]
fn secret_store_create() {
@@ -117,9 +114,9 @@ fn secret_store_laod_geth_files() {
let dir = RootDiskDirectory::at(test_path());
let store = EthStore::open(Box::new(dir)).unwrap();
assert_eq!(store.accounts().unwrap(), vec![
StoreAccountRef::root(Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap()),
StoreAccountRef::root(Address::from_str("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf").unwrap()),
StoreAccountRef::root(Address::from_str("63121b431a52f8043c16fcf0d1df9cb7b5f66649").unwrap()),
StoreAccountRef::root("3f49624084b67849c7b4e805c5988c21a430f9d9".into()),
StoreAccountRef::root("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf".into()),
StoreAccountRef::root("63121b431a52f8043c16fcf0d1df9cb7b5f66649".into()),
]);
}
@@ -128,8 +125,8 @@ fn secret_store_load_pat_files() {
let dir = RootDiskDirectory::at(pat_path());
let store = EthStore::open(Box::new(dir)).unwrap();
assert_eq!(store.accounts().unwrap(), vec![
StoreAccountRef::root(Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap()),
StoreAccountRef::root(Address::from_str("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf").unwrap()),
StoreAccountRef::root("3f49624084b67849c7b4e805c5988c21a430f9d9".into()),
StoreAccountRef::root("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf".into()),
]);
}
@@ -143,8 +140,8 @@ fn test_decrypting_files_with_short_ciphertext() {
let store = EthStore::open(Box::new(dir)).unwrap();
let accounts = store.accounts().unwrap();
assert_eq!(accounts, vec![
StoreAccountRef::root(Address::from_str("31e9d1e6d844bd3a536800ef8d8be6a9975db509").unwrap()),
StoreAccountRef::root(Address::from_str("d1e64e5480bfaf733ba7d48712decb8227797a4e").unwrap()),
StoreAccountRef::root("31e9d1e6d844bd3a536800ef8d8be6a9975db509".into()),
StoreAccountRef::root("d1e64e5480bfaf733ba7d48712decb8227797a4e".into()),
]);
let message = Default::default();

View File

@@ -16,7 +16,7 @@
use std::path::PathBuf;
use std::{env, fs};
use rand::{RngCore, rngs::OsRng};
use rand::{Rng, OsRng};
use ethstore::accounts_dir::{KeyDirectory, RootDiskDirectory};
use ethstore::{Error, SafeAccount};

View File

@@ -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 <admin@parity.io>"]
[dependencies]
ethereum-types = "0.4"
ethkey = { path = "../../accounts/ethkey" }

View File

@@ -0,0 +1,101 @@
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
// This file is part of Parity Ethereum.
// Parity Ethereum 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 Ethereum 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 Ethereum. If not, see <http://www.gnu.org/licenses/>.
//! 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<Address>,
/// Value
pub value: U256,
/// Data
pub data: Vec<u8>,
/// Chain ID
pub chain_id: Option<u64>,
}
pub enum KeyPath {
/// Ethereum.
Ethereum,
/// Ethereum classic.
EthereumClassic,
}
/// `HardwareWalletManager` for devices with no `hardware wallet`
pub struct HardwareWalletManager;
impl HardwareWalletManager {
pub fn new() -> Result<Self, Error> {
Err(Error::NoWallet)
}
pub fn set_key_path(&self, _key_path: KeyPath) {}
pub fn wallet_info(&self, _: &Address) -> Option<WalletInfo> {
None
}
pub fn list_wallets(&self) -> Vec<WalletInfo> {
Vec::with_capacity(0)
}
pub fn list_locked_wallets(&self) -> Result<Vec<String>, Error> {
Err(Error::NoWallet)
}
pub fn pin_matrix_ack(&self, _: &str, _: &str) -> Result<bool, Error> {
Err(Error::NoWallet)
}
pub fn sign_transaction(&self, _address: &Address, _transaction: &TransactionInfo, _rlp_transaction: &[u8]) -> Result<Signature, Error> {
Err(Error::NoWallet) }
pub fn sign_message(&self, _address: &Address, _msg: &[u8]) -> Result<Signature, Error> {
Err(Error::NoWallet)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "No hardware wallet!!")
}
}

21
accounts/hw/Cargo.toml Normal file
View File

@@ -0,0 +1,21 @@
[package]
description = "Hardware wallet support."
homepage = "http://parity.io"
license = "GPL-3.0"
name = "hardware-wallet"
version = "1.12.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
log = "0.4"
parking_lot = "0.7"
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.4"
semver = "0.9"
[dev-dependencies]
rustc-hex = "1.0"

534
accounts/hw/src/ledger.rs Normal file

File diff suppressed because one or more lines are too long

402
accounts/hw/src/lib.rs Normal file
View File

@@ -0,0 +1,402 @@
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
// This file is part of Parity Ethereum.
// Parity Ethereum 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 Ethereum 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 Ethereum. If not, see <http://www.gnu.org/licenses/>.
//! Hardware wallet management.
#![warn(missing_docs)]
#![warn(warnings)]
extern crate ethereum_types;
extern crate ethkey;
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 std::sync::{Arc, atomic, atomic::AtomicBool, Weak};
use std::{fmt, time::Duration};
use std::thread;
use ethereum_types::U256;
use ethkey::{Address, Signature};
use parking_lot::Mutex;
const HID_GLOBAL_USAGE_PAGE: u16 = 0xFF00;
const HID_USB_DEVICE_CLASS: u8 = 0;
const MAX_POLLING_DURATION: Duration = Duration::from_millis(500);
const USB_EVENT_POLLING_INTERVAL: 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;
/// Transaction data format
type Transaction;
/// Sign transaction data with wallet managing `address`.
fn sign_transaction(&self, address: &Address, transaction: Self::Transaction) -> Result<Signature, Self::Error>;
/// 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, device_direction: DeviceDirection) -> Result<usize, Self::Error>;
/// Read device info
fn read_device(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result<Device, Self::Error>;
/// List connected and acknowledged wallets
fn list_devices(&self) -> Vec<WalletInfo>;
/// List locked wallets
/// This may be moved if it is the wrong assumption, for example this is not supported by Ledger
/// Then this method return a empty vector
fn list_locked_devices(&self) -> Vec<String>;
/// Get wallet info.
fn get_wallet(&self, address: &Address) -> Option<WalletInfo>;
/// Generate ethereum address for a Wallet
fn get_address(&self, device: &hidapi::HidDevice) -> Result<Option<Address>, Self::Error>;
/// Open a device using `device path`
/// Note, f - is a closure that borrows HidResult<HidDevice>
/// HidDevice is in turn a type alias for a `c_void function pointer`
/// For further information see:
/// * <https://github.com/paritytech/hidapi-rs>
/// * <https://github.com/rust-lang/libc>
fn open_path<R, F>(&self, f: F) -> Result<R, Self::Error>
where F: Fn() -> Result<R, &'static str>;
}
/// Hardware wallet error.
#[derive(Debug)]
pub enum Error {
/// Ledger device error.
LedgerDevice(ledger::Error),
/// Trezor device error
TrezorDevice(trezor::Error),
/// USB error.
Usb(libusb::Error),
/// HID error
Hid(String),
/// Hardware wallet not found for specified key.
KeyNotFound,
}
/// 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
/// import ethcore here as that would be a circular dependency.
pub struct TransactionInfo {
/// Nonce
pub nonce: U256,
/// Gas price
pub gas_price: U256,
/// Gas limit
pub gas_limit: U256,
/// Receiver
pub to: Option<Address>,
/// Value
pub value: U256,
/// Data
pub data: Vec<u8>,
/// Chain ID
pub chain_id: Option<u64>,
}
/// Hardware wallet information.
#[derive(Debug, Clone)]
pub struct WalletInfo {
/// Wallet device name.
pub name: String,
/// Wallet device manufacturer.
pub manufacturer: String,
/// Wallet device serial number.
pub serial: String,
/// Ethereum address.
pub address: Address,
}
/// Key derivation paths used on hardware wallets.
#[derive(Debug, Clone, Copy)]
pub enum KeyPath {
/// Ethereum.
Ethereum,
/// Ethereum classic.
EthereumClassic,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
Error::KeyNotFound => write!(f, "Key not found for given address."),
Error::LedgerDevice(ref e) => write!(f, "{}", e),
Error::TrezorDevice(ref e) => write!(f, "{}", e),
Error::Usb(ref e) => write!(f, "{}", e),
Error::Hid(ref e) => write!(f, "{}", e),
}
}
}
impl From<ledger::Error> for Error {
fn from(err: ledger::Error) -> Self {
match err {
ledger::Error::KeyNotFound => Error::KeyNotFound,
_ => Error::LedgerDevice(err),
}
}
}
impl From<trezor::Error> for Error {
fn from(err: trezor::Error) -> Self {
match err {
trezor::Error::KeyNotFound => Error::KeyNotFound,
_ => Error::TrezorDevice(err),
}
}
}
impl From<libusb::Error> for 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, PartialEq)]
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<AtomicBool>,
ledger: Arc<ledger::Manager>,
trezor: Arc<trezor::Manager>,
}
impl HardwareWalletManager {
/// Hardware wallet constructor
pub fn new() -> Result<Self, Error> {
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());
let trezor = trezor::Manager::new(hidapi.clone());
let usb_context = Arc::new(libusb::Context::new()?);
let l = ledger.clone();
let t = trezor.clone();
let exit = exiting.clone();
// Subscribe to all vendor IDs (VIDs) and product IDs (PIDs)
// This means that the `HardwareWalletManager` is responsible to validate the detected device
usb_context.register_callback(
None, None, Some(HID_USB_DEVICE_CLASS),
Box::new(EventHandler::new(
Arc::downgrade(&ledger),
Arc::downgrade(&trezor)
))
)?;
// Hardware event subscriber thread
thread::Builder::new()
.name("hw_wallet_manager".to_string())
.spawn(move || {
if let Err(e) = l.update_devices(DeviceDirection::Arrived) {
debug!(target: "hw", "Ledger couldn't connect at startup, error: {}", e);
}
if let Err(e) = t.update_devices(DeviceDirection::Arrived) {
debug!(target: "hw", "Trezor couldn't connect at startup, error: {}", e);
}
while !exit.load(atomic::Ordering::Acquire) {
if let Err(e) = usb_context.handle_events(Some(USB_EVENT_POLLING_INTERVAL)) {
debug!(target: "hw", "HardwareWalletManager event handler error: {}", e);
}
}
})
.ok();
Ok(Self {
exiting,
trezor,
ledger,
})
}
/// Select key derivation path for a chain.
/// Currently, only one hard-coded keypath is supported
/// It is managed by `ethcore/account_provider`
pub fn set_key_path(&self, key_path: KeyPath) {
self.ledger.set_key_path(key_path);
self.trezor.set_key_path(key_path);
}
/// List connected wallets. This only returns wallets that are ready to be used.
pub fn list_wallets(&self) -> Vec<WalletInfo> {
let mut wallets = Vec::new();
wallets.extend(self.ledger.list_devices());
wallets.extend(self.trezor.list_devices());
wallets
}
/// Return a list of paths to locked hardware wallets
/// This is only applicable to Trezor because Ledger only appears as
/// a device when it is unlocked
pub fn list_locked_wallets(&self) -> Result<Vec<String>, Error> {
Ok(self.trezor.list_locked_devices())
}
/// Get connected wallet info.
pub fn wallet_info(&self, address: &Address) -> Option<WalletInfo> {
if let Some(info) = self.ledger.get_wallet(address) {
Some(info)
} else {
self.trezor.get_wallet(address)
}
}
/// Sign a message with the wallet (only supported by Ledger)
pub fn sign_message(&self, address: &Address, msg: &[u8]) -> Result<Signature, Error> {
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<Signature, Error> {
if self.ledger.get_wallet(address).is_some() {
Ok(self.ledger.sign_transaction(address, encoded_transaction)?)
} else if self.trezor.get_wallet(address).is_some() {
Ok(self.trezor.sign_transaction(address, t_info)?)
} else {
Err(Error::KeyNotFound)
}
}
/// Send a pin to a device at a certain path to unlock it
/// This is only applicable to Trezor because Ledger only appears as
/// a device when it is unlocked
pub fn pin_matrix_ack(&self, path: &str, pin: &str) -> Result<bool, Error> {
self.trezor.pin_matrix_ack(path, pin).map_err(Error::TrezorDevice)
}
}
impl Drop for HardwareWalletManager {
fn drop(&mut self) {
// Indicate to the USB Hotplug handler that it
// shall terminate but don't wait for it to terminate.
// If it doesn't terminate for some reason USB Hotplug events will be handled
// even if the HardwareWalletManger has been dropped
self.exiting.store(true, atomic::Ordering::Release);
}
}
/// Hardware wallet event handler
///
/// Note, that this runs to completion and race-conditions can't occur but it can
/// stop other events for being processed with an infinite loop or similar
struct EventHandler {
ledger: Weak<ledger::Manager>,
trezor: Weak<trezor::Manager>,
}
impl EventHandler {
/// Trezor event handler constructor
pub fn new(ledger: Weak<ledger::Manager>, trezor: Weak<trezor::Manager>) -> Self {
Self { ledger, trezor }
}
fn extract_device_info(device: &libusb::Device) -> Result<(u16, u16), Error> {
let desc = device.device_descriptor()?;
Ok((desc.vendor_id(), desc.product_id()))
}
}
impl libusb::Hotplug for EventHandler {
fn device_arrived(&mut self, device: libusb::Device) {
// Upgrade reference to an Arc
if let (Some(ledger), Some(trezor)) = (self.ledger.upgrade(), self.trezor.upgrade()) {
// Version ID and Product ID are available
if let Ok((vid, pid)) = Self::extract_device_info(&device) {
if trezor::is_valid_trezor(vid, pid) {
if !trezor::try_connect_polling(&trezor, &MAX_POLLING_DURATION, DeviceDirection::Arrived) {
trace!(target: "hw", "Trezor device was detected but connection failed");
}
} else if ledger::is_valid_ledger(vid, pid) {
if !ledger::try_connect_polling(&ledger, &MAX_POLLING_DURATION, DeviceDirection::Arrived) {
trace!(target: "hw", "Ledger device was detected but connection failed");
}
}
}
}
}
fn device_left(&mut self, device: libusb::Device) {
// Upgrade reference to an Arc
if let (Some(ledger), Some(trezor)) = (self.ledger.upgrade(), self.trezor.upgrade()) {
// Version ID and Product ID are available
if let Ok((vid, pid)) = Self::extract_device_info(&device) {
if trezor::is_valid_trezor(vid, pid) {
if !trezor::try_connect_polling(&trezor, &MAX_POLLING_DURATION, DeviceDirection::Left) {
trace!(target: "hw", "Trezor device was detected but disconnection failed");
}
} else if ledger::is_valid_ledger(vid, pid) {
if !ledger::try_connect_polling(&ledger, &MAX_POLLING_DURATION, DeviceDirection::Left) {
trace!(target: "hw", "Ledger device was detected but disconnection failed");
}
}
}
}
}
}
/// Helper to determine if a device is a valid HID
pub fn is_valid_hid_device(usage_page: u16, interface_number: i32) -> bool {
usage_page == HID_GLOBAL_USAGE_PAGE || interface_number == HID_USB_DEVICE_CLASS as i32
}

463
accounts/hw/src/trezor.rs Normal file
View File

@@ -0,0 +1,463 @@
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
// This file is part of Parity Ethereum.
// Parity Ethereum 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 Ethereum 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 Ethereum. If not, see <http://www.gnu.org/licenses/>.
//! 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>
//! for protocol details.
use std::cmp::{min, max};
use std::sync::Arc;
use std::time::{Duration, Instant};
use std::fmt;
use ethereum_types::{U256, H256, Address};
use ethkey::Signature;
use hidapi;
use libusb;
use parking_lot::{Mutex, RwLock};
use protobuf::{self, Message, ProtobufEnum};
use super::{DeviceDirection, WalletInfo, TransactionInfo, KeyPath, Wallet, Device, is_valid_hid_device};
use trezor_sys::messages::{EthereumAddress, PinMatrixAck, MessageType, EthereumTxRequest, EthereumSignTx, EthereumGetAddress, EthereumTxAck, ButtonAck};
/// Trezor v1 vendor ID
const TREZOR_VID: u16 = 0x534c;
/// Trezor product IDs
const TREZOR_PIDS: [u16; 1] = [0x0001];
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)]
pub enum Error {
/// Ethereum wallet protocol error.
Protocol(&'static str),
/// Hidapi error.
Usb(hidapi::HidError),
/// Libusb error
LibUsb(libusb::Error),
/// Device with request key is not available.
KeyNotFound,
/// Signing has been cancelled by user.
UserCancel,
/// The Message Type given in the trezor RPC call is not something we recognize
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,
/// Invalid PID or VID
InvalidDevice,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
Error::Protocol(ref s) => write!(f, "Trezor protocol error: {}", s),
Error::Usb(ref e) => write!(f, "USB communication error: {}", e),
Error::LibUsb(ref e) => write!(f, "LibUSB communication error: {}", e),
Error::KeyNotFound => write!(f, "Key not found"),
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"),
Error::InvalidDevice => write!(f, "Device with non-supported product ID or vendor ID was detected"),
}
}
}
impl From<hidapi::HidError> for Error {
fn from(err: hidapi::HidError) -> Self {
Error::Usb(err)
}
}
impl From<libusb::Error> for Error {
fn from(err: libusb::Error) -> Self {
Error::LibUsb(err)
}
}
impl From<protobuf::ProtobufError> for Error {
fn from(_: protobuf::ProtobufError) -> Self {
Error::Protocol(&"Could not read response from Trezor Device")
}
}
/// Trezor device manager
pub struct Manager {
usb: Arc<Mutex<hidapi::HidApi>>,
devices: RwLock<Vec<Device>>,
locked_devices: RwLock<Vec<String>>,
key_path: RwLock<KeyPath>,
}
/// HID Version used for the Trezor device
enum HidVersion {
V1,
V2,
}
impl Manager {
/// Create a new instance.
pub fn new(usb: Arc<Mutex<hidapi::HidApi>>) -> Arc<Self> {
Arc::new(Self {
usb,
devices: RwLock::new(Vec::new()),
locked_devices: RwLock::new(Vec::new()),
key_path: RwLock::new(KeyPath::Ethereum),
})
}
pub fn pin_matrix_ack(&self, device_path: &str, pin: &str) -> Result<bool, Error> {
let unlocked = {
let usb = self.usb.lock();
let device = self.open_path(|| usb.open_path(&device_path))?;
let t = MessageType::MessageType_PinMatrixAck;
let mut m = PinMatrixAck::new();
m.set_pin(pin.to_string());
self.send_device_message(&device, t, &m)?;
let (resp_type, _) = self.read_device_response(&device)?;
match resp_type {
// Getting an Address back means it's unlocked, this is undocumented behavior
MessageType::MessageType_EthereumAddress => Ok(true),
// Getting anything else means we didn't unlock it
_ => Ok(false),
}
};
self.update_devices(DeviceDirection::Arrived)?;
unlocked
}
fn u256_to_be_vec(&self, val: &U256) -> Vec<u8> {
let mut buf = [0_u8; 32];
val.to_big_endian(&mut buf);
buf.iter().skip_while(|x| **x == 0).cloned().collect()
}
fn signing_loop(&self, handle: &hidapi::HidDevice, chain_id: &Option<u64>, data: &[u8]) -> Result<Signature, Error> {
let (resp_type, bytes) = self.read_device_response(&handle)?;
match resp_type {
MessageType::MessageType_Cancel => Err(Error::UserCancel),
MessageType::MessageType_ButtonRequest => {
self.send_device_message(handle, MessageType::MessageType_ButtonAck, &ButtonAck::new())?;
// Signing loop goes back to the top and reading blocks
// for up to 5 minutes waiting for response from the device
// if the user doesn't click any button within 5 minutes you
// get a signing error and the device sort of locks up on the signing screen
self.signing_loop(handle, chain_id, data)
}
MessageType::MessageType_EthereumTxRequest => {
let resp: EthereumTxRequest = protobuf::core::parse_from_bytes(&bytes)?;
if resp.has_data_length() {
let mut msg = EthereumTxAck::new();
let len = resp.get_data_length() as usize;
msg.set_data_chunk(data[..len].to_vec());
self.send_device_message(handle, MessageType::MessageType_EthereumTxAck, &msg)?;
self.signing_loop(handle, chain_id, &data[len..])
} else {
let v = resp.get_signature_v();
let r = H256::from_slice(resp.get_signature_r());
let s = H256::from_slice(resp.get_signature_s());
if let Some(c_id) = *chain_id {
// If there is a chain_id supplied, Trezor will return a v
// part of the signature that is already adjusted for EIP-155,
// so v' = v + 2 * chain_id + 35, but code further down the
// pipeline will already do this transformation, so remove it here
let adjustment = 35 + 2 * c_id as u32;
Ok(Signature::from_rsv(&r, &s, (max(v, adjustment) - adjustment) as u8))
} else {
// If there isn't a chain_id, v will be returned as v + 27
let adjusted_v = if v < 27 { v } else { v - 27 };
Ok(Signature::from_rsv(&r, &s, adjusted_v as u8))
}
}
}
MessageType::MessageType_Failure => Err(Error::Protocol("Last message sent to Trezor failed")),
_ => Err(Error::Protocol("Unexpected response from Trezor device.")),
}
}
fn send_device_message(&self, device: &hidapi::HidDevice, msg_type: MessageType, msg: &Message) -> Result<usize, Error> {
let msg_id = msg_type as u16;
let mut message = msg.write_to_bytes()?;
let msg_size = message.len();
let mut data = Vec::new();
let hid_version = self.probe_hid_version(device)?;
// Magic constants
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);
// Convert msg_size to BE and split into bytes
data.push(((msg_size >> 24) & 0xFF) as u8);
data.push(((msg_size >> 16) & 0xFF) as u8);
data.push(((msg_size >> 8) & 0xFF) as u8);
data.push((msg_size & 0xFF) as u8);
data.append(&mut message);
while data.len() % 63 > 0 {
data.push(0);
}
let mut total_written = 0;
for chunk in data.chunks(63) {
let mut padded_chunk = match hid_version {
HidVersion::V1 => vec![b'?'],
HidVersion::V2 => vec![0, b'?'],
};
padded_chunk.extend_from_slice(&chunk);
total_written += device.write(&padded_chunk)?;
}
Ok(total_written)
}
fn probe_hid_version(&self, device: &hidapi::HidDevice) -> Result<HidVersion, Error> {
let mut buf2 = [0xFF_u8; 65];
buf2[0] = 0;
buf2[1] = 63;
let mut buf1 = [0xFF_u8; 64];
buf1[0] = 63;
if device.write(&buf2)? == 65 {
Ok(HidVersion::V2)
} else if device.write(&buf1)? == 64 {
Ok(HidVersion::V1)
} else {
Err(Error::Usb("Unable to determine HID Version"))
}
}
fn read_device_response(&self, device: &hidapi::HidDevice) -> Result<(MessageType, Vec<u8>), Error> {
let protocol_err = Error::Protocol(&"Unexpected wire response from Trezor Device");
let mut buf = vec![0; 64];
let first_chunk = device.read_timeout(&mut buf, 300_000)?;
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)?;
let msg_size = ((buf[5] as u32 & 0xFF) << 24) + ((buf[6] as u32 & 0xFF) << 16) + ((buf[7] as u32 & 0xFF) << 8) + (buf[8] as u32 & 0xFF);
let mut data = Vec::new();
data.extend_from_slice(&buf[9..]);
while data.len() < (msg_size as usize) {
device.read_timeout(&mut buf, 10_000)?;
data.extend_from_slice(&buf[1..]);
}
Ok((msg_type, data[..msg_size as usize].to_vec()))
}
}
impl<'a> Wallet<'a> for Manager {
type Error = Error;
type Transaction = &'a TransactionInfo;
fn sign_transaction(&self, address: &Address, t_info: Self::Transaction) ->
Result<Signature, Error> {
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 msg_type = MessageType::MessageType_EthereumSignTx;
let mut message = EthereumSignTx::new();
match *self.key_path.read() {
KeyPath::Ethereum => message.set_address_n(ETH_DERIVATION_PATH.to_vec()),
KeyPath::EthereumClassic => message.set_address_n(ETC_DERIVATION_PATH.to_vec()),
}
message.set_nonce(self.u256_to_be_vec(&t_info.nonce));
message.set_gas_limit(self.u256_to_be_vec(&t_info.gas_limit));
message.set_gas_price(self.u256_to_be_vec(&t_info.gas_price));
message.set_value(self.u256_to_be_vec(&t_info.value));
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];
message.set_data_initial_chunk(chunk.to_vec());
message.set_data_length(t_info.data.len() as u32);
if let Some(c_id) = t_info.chain_id {
message.set_chain_id(c_id as u32);
}
self.send_device_message(&handle, msg_type, &message)?;
self.signing_loop(&handle, &t_info.chain_id, &t_info.data[first_chunk_length..])
}
fn set_key_path(&self, key_path: KeyPath) {
*self.key_path.write() = key_path;
}
fn update_devices(&self, device_direction: DeviceDirection) -> Result<usize, Error> {
let mut usb = self.usb.lock();
usb.refresh_devices();
let devices = usb.devices();
let num_prev_devices = self.devices.read().len();
let detected_devices = devices.iter()
.filter(|&d| is_valid_trezor(d.vendor_id, d.product_id) &&
is_valid_hid_device(d.usage_page, d.interface_number)
)
.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)
}
}
DeviceDirection::Left => {
if num_prev_devices > num_curr_devices {
Ok(num_prev_devices - num_curr_devices)
} else {
Err(Error::NoDeviceLeft)
}
}
}
}
fn read_device(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result<Device, Error> {
let handle = self.open_path(|| usb.open_path(&dev_info.path))?;
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,
manufacturer,
serial,
address: addr,
},
})
}
Ok(None) => Err(Error::LockedDevice(dev_info.path.clone())),
Err(e) => Err(e),
}
}
fn list_devices(&self) -> Vec<WalletInfo> {
self.devices.read().iter().map(|d| d.info.clone()).collect()
}
fn list_locked_devices(&self) -> Vec<String> {
(*self.locked_devices.read()).clone()
}
fn get_wallet(&self, address: &Address) -> Option<WalletInfo> {
self.devices.read().iter().find(|d| &d.info.address == address).map(|d| d.info.clone())
}
fn get_address(&self, device: &hidapi::HidDevice) -> Result<Option<Address>, Error> {
let typ = MessageType::MessageType_EthereumGetAddress;
let mut message = EthereumGetAddress::new();
match *self.key_path.read() {
KeyPath::Ethereum => message.set_address_n(ETH_DERIVATION_PATH.to_vec()),
KeyPath::EthereumClassic => message.set_address_n(ETC_DERIVATION_PATH.to_vec()),
}
message.set_show_display(false);
self.send_device_message(&device, typ, &message)?;
let (resp_type, bytes) = self.read_device_response(&device)?;
match resp_type {
MessageType::MessageType_EthereumAddress => {
let response: EthereumAddress = protobuf::core::parse_from_bytes(&bytes)?;
Ok(Some(From::from(response.get_address())))
}
_ => Ok(None),
}
}
fn open_path<R, F>(&self, f: F) -> Result<R, Error>
where F: Fn() -> Result<R, &'static str>
{
f().map_err(Into::into)
}
}
/// Poll the device in maximum `max_polling_duration` if it doesn't succeed
pub fn try_connect_polling(trezor: &Manager, duration: &Duration, dir: DeviceDirection) -> bool {
let start_time = Instant::now();
while start_time.elapsed() <= *duration {
if let Ok(num_devices) = trezor.update_devices(dir) {
trace!(target: "hw", "{} Trezor devices {}", num_devices, dir);
return true
}
}
false
}
/// Check if the detected device is a Trezor device by checking both the product ID and the vendor ID
pub fn is_valid_trezor(vid: u16, pid: u16) -> bool {
vid == TREZOR_VID && TREZOR_PIDS.contains(&pid)
}
#[test]
#[ignore]
/// This test can't be run without an actual trezor device connected
/// (and unlocked) attached to the machine that's running the test
fn test_signature() {
use ethereum_types::Address;
use MAX_POLLING_DURATION;
use super::HardwareWalletManager;
let manager = HardwareWalletManager::new().unwrap();
assert_eq!(try_connect_polling(&manager.trezor, &MAX_POLLING_DURATION, DeviceDirection::Arrived), true);
let addr: Address = manager.list_wallets()
.iter()
.filter(|d| d.name == "TREZOR".to_string() && d.manufacturer == "SatoshiLabs".to_string())
.nth(0)
.map(|d| d.address)
.unwrap();
let t_info = TransactionInfo {
nonce: U256::from(1),
gas_price: U256::from(100),
gas_limit: U256::from(21_000),
to: Some(Address::from(1337)),
chain_id: Some(1),
value: U256::from(1_000_000),
data: (&[1u8; 3000]).to_vec(),
};
let signature = manager.trezor.sign_transaction(&addr, &t_info);
assert!(signature.is_ok());
}

View File

@@ -17,6 +17,7 @@
use std::fmt;
use ethstore::{Error as SSError};
use hardware_wallet::{Error as HardwareError};
/// Signing error
#[derive(Debug)]
@@ -25,6 +26,8 @@ pub enum SignError {
NotUnlocked,
/// Account does not exist.
NotFound,
/// Low-level hardware device error.
Hardware(HardwareError),
/// Low-level error from store
SStore(SSError),
}
@@ -34,11 +37,18 @@ impl fmt::Display for SignError {
match *self {
SignError::NotUnlocked => write!(f, "Account is locked"),
SignError::NotFound => write!(f, "Account does not exist"),
SignError::Hardware(ref e) => write!(f, "{}", e),
SignError::SStore(ref e) => write!(f, "{}", e),
}
}
}
impl From<HardwareError> for SignError {
fn from(e: HardwareError) -> Self {
SignError::Hardware(e)
}
}
impl From<SSError> for SignError {
fn from(e: SSError) -> Self {
SignError::SStore(e)

View File

@@ -22,23 +22,28 @@ mod account_data;
mod error;
mod stores;
#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
extern crate fake_hardware_wallet as hardware_wallet;
use self::account_data::{Unlock, AccountData};
use self::stores::AddressBook;
use std::collections::HashMap;
use std::time::{Instant, Duration};
use common_types::transaction::{Action, Transaction};
use ethkey::{Address, Message, Public, Secret, Password, Random, Generator};
use ethstore::accounts_dir::MemoryDirectory;
use ethstore::{
SimpleSecretStore, SecretStore, EthStore, EthMultiStore,
random_string, SecretVaultRef, StoreAccountRef, OpaqueSecret,
};
use log::warn;
use log::{warn, debug};
use parking_lot::RwLock;
pub use ethkey::Signature;
pub use ethstore::{Derivation, IndexDerivation, KeyFile, Error};
pub use hardware_wallet::{Error as HardwareError, HardwareWalletManager, KeyPath, TransactionInfo};
pub use self::account_data::AccountMeta;
pub use self::error::SignError;
@@ -48,6 +53,10 @@ type AccountToken = Password;
/// Account management settings.
#[derive(Debug, Default)]
pub struct AccountProviderSettings {
/// Enable hardware wallet support.
pub enable_hardware_wallets: bool,
/// Use the classic chain key on the hardware wallet.
pub hardware_wallet_classic_key: bool,
/// Store raw account secret when unlocking the account permanently.
pub unlock_keep_secret: bool,
/// Disallowed accounts.
@@ -67,6 +76,8 @@ pub struct AccountProvider {
sstore: Box<SecretStore>,
/// Accounts unlocked with rolling tokens
transient_sstore: EthMultiStore,
/// Accounts in hardware wallets.
hardware_store: Option<HardwareWalletManager>,
/// When unlocking account permanently we additionally keep a raw secret in memory
/// to increase the performance of transaction signing.
unlock_keep_secret: bool,
@@ -81,6 +92,18 @@ fn transient_sstore() -> EthMultiStore {
impl AccountProvider {
/// Creates new account provider.
pub fn new(sstore: Box<SecretStore>, settings: AccountProviderSettings) -> Self {
let mut hardware_store = None;
if settings.enable_hardware_wallets {
match HardwareWalletManager::new() {
Ok(manager) => {
manager.set_key_path(if settings.hardware_wallet_classic_key { KeyPath::EthereumClassic } else { KeyPath::Ethereum });
hardware_store = Some(manager)
},
Err(e) => debug!("Error initializing hardware wallets: {}", e),
}
}
if let Ok(accounts) = sstore.accounts() {
for account in accounts.into_iter().filter(|a| settings.blacklisted_accounts.contains(&a.address)) {
warn!("Local Account {} has a blacklisted (known to be weak) address and will be ignored",
@@ -98,8 +121,9 @@ impl AccountProvider {
unlocked_secrets: RwLock::new(HashMap::new()),
unlocked: RwLock::new(HashMap::new()),
address_book: RwLock::new(address_book),
sstore,
sstore: sstore,
transient_sstore: transient_sstore(),
hardware_store: hardware_store,
unlock_keep_secret: settings.unlock_keep_secret,
blacklisted_accounts: settings.blacklisted_accounts,
}
@@ -113,6 +137,7 @@ impl AccountProvider {
address_book: RwLock::new(AddressBook::transient()),
sstore: Box::new(EthStore::open(Box::new(MemoryDirectory::default())).expect("MemoryDirectory load always succeeds; qed")),
transient_sstore: transient_sstore(),
hardware_store: None,
unlock_keep_secret: false,
blacklisted_accounts: vec![],
}
@@ -194,6 +219,34 @@ impl AccountProvider {
Ok(self.accounts()?.first().cloned().unwrap_or_default())
}
/// Returns addresses of hardware accounts.
pub fn hardware_accounts(&self) -> Result<Vec<Address>, Error> {
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(Error::Custom("No hardware wallet accounts were found".into()))
}
/// Get a list of paths to locked hardware wallets
pub fn locked_hardware_accounts(&self) -> Result<Vec<String>, SignError> {
match self.hardware_store.as_ref().map(|h| h.list_locked_wallets()) {
None => Err(SignError::NotFound),
Some(Err(e)) => Err(SignError::Hardware(e)),
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<bool, SignError> {
match self.hardware_store.as_ref().map(|h| h.pin_matrix_ack(path, pin)) {
None => Err(SignError::NotFound),
Some(Err(e)) => Err(SignError::Hardware(e)),
Some(Ok(s)) => Ok(s),
}
}
/// Returns each address along with metadata.
pub fn addresses_info(&self) -> HashMap<Address, AccountMeta> {
self.address_book.read().get()
@@ -224,14 +277,36 @@ impl AccountProvider {
Ok(r)
}
/// Returns each hardware account along with name and meta.
pub fn hardware_accounts_info(&self) -> Result<HashMap<Address, AccountMeta>, Error> {
let r = self.hardware_accounts()?
.into_iter()
.map(|address| (address.clone(), self.account_meta(address).ok().unwrap_or_default()))
.collect();
Ok(r)
}
/// Returns each hardware account along with name and meta.
pub fn is_hardware_address(&self, address: &Address) -> bool {
self.hardware_store.as_ref().and_then(|s| s.wallet_info(address)).is_some()
}
/// Returns each account along with name and meta.
pub fn account_meta(&self, address: Address) -> Result<AccountMeta, Error> {
let account = self.sstore.account_ref(&address)?;
Ok(AccountMeta {
name: self.sstore.name(&account)?,
meta: self.sstore.meta(&account)?,
uuid: self.sstore.uuid(&account).ok().map(Into::into), // allowed to not have a Uuid
})
if let Some(info) = self.hardware_store.as_ref().and_then(|s| s.wallet_info(&address)) {
Ok(AccountMeta {
name: info.name,
meta: info.manufacturer,
uuid: None,
})
} else {
let account = self.sstore.account_ref(&address)?;
Ok(AccountMeta {
name: self.sstore.name(&account)?,
meta: self.sstore.meta(&account)?,
uuid: self.sstore.uuid(&account).ok().map(Into::into), // allowed to not have a Uuid
})
}
}
/// Returns account public key.
@@ -295,7 +370,10 @@ impl AccountProvider {
let _ = self.sstore.sign(&account, &password, &Default::default())?;
}
let data = AccountData { unlock, password };
let data = AccountData {
unlock: unlock,
password: password,
};
unlocked.insert(account, data);
Ok(())
@@ -497,6 +575,36 @@ impl AccountProvider {
self.sstore.set_vault_meta(name, meta)
.map_err(Into::into)
}
/// Sign message with hardware wallet.
pub fn sign_message_with_hardware(&self, address: &Address, message: &[u8]) -> Result<Signature, SignError> {
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_transaction_with_hardware(&self, address: &Address, transaction: &Transaction, chain_id: Option<u64>, rlp_encoded_transaction: &[u8]) -> Result<Signature, SignError> {
let t_info = TransactionInfo {
nonce: transaction.nonce,
gas_price: transaction.gas_price,
gas_limit: transaction.gas,
to: match transaction.action {
Action::Create => None,
Action::Call(ref to) => Some(to.clone()),
},
value: transaction.value,
data: transaction.data.to_vec(),
chain_id: chain_id,
};
match self.hardware_store.as_ref().map(|s| s.sign_transaction(&address, &t_info, rlp_encoded_transaction)) {
None | Some(Err(HardwareError::KeyNotFound)) => Err(SignError::NotFound),
Some(Err(e)) => Err(From::from(e)),
Some(Ok(s)) => Ok(s),
}
}
}
#[cfg(test)]
@@ -528,7 +636,7 @@ mod tests {
let derived_addr = ap.derive_account(
&kp.address(),
None,
Derivation::SoftHash(H256::from_low_u64_be(999)),
Derivation::SoftHash(H256::from(999)),
false,
).expect("Derivation should not fail");
@@ -546,7 +654,7 @@ mod tests {
let derived_addr = ap.derive_account(
&kp.address(),
None,
Derivation::SoftHash(H256::from_low_u64_be(999)),
Derivation::SoftHash(H256::from(999)),
true,
).expect("Derivation should not fail");
@@ -567,7 +675,7 @@ mod tests {
let derived_addr = ap.derive_account(
&kp.address(),
None,
Derivation::SoftHash(H256::from_low_u64_be(1999)),
Derivation::SoftHash(H256::from(1999)),
true,
).expect("Derivation should not fail");
ap.unlock_account_permanently(derived_addr, "base".into())
@@ -579,7 +687,7 @@ mod tests {
let signed_msg2 = ap.sign_derived(
&kp.address(),
None,
Derivation::SoftHash(H256::from_low_u64_be(1999)),
Derivation::SoftHash(H256::from(1999)),
msg,
).expect("Derived signing with existing unlocked account should not fail");

View File

@@ -153,7 +153,7 @@ impl<K: hash::Hash + Eq, V> DiskMap<K, V> {
#[cfg(test)]
mod tests {
use super::{AddressBook, Address};
use super::AddressBook;
use std::collections::HashMap;
use tempdir::TempDir;
use crate::account_data::AccountMeta;
@@ -162,12 +162,12 @@ mod tests {
fn should_save_and_reload_address_book() {
let tempdir = TempDir::new("").unwrap();
let mut b = AddressBook::new(tempdir.path());
b.set_name(Address::from_low_u64_be(1), "One".to_owned());
b.set_meta(Address::from_low_u64_be(1), "{1:1}".to_owned());
b.set_name(1.into(), "One".to_owned());
b.set_meta(1.into(), "{1:1}".to_owned());
let b = AddressBook::new(tempdir.path());
assert_eq!(b.get(), vec![
(Address::from_low_u64_be(1), AccountMeta {name: "One".to_owned(), meta: "{1:1}".to_owned(), uuid: None})
].into_iter().collect::<HashMap<_, _>>());
(1, AccountMeta {name: "One".to_owned(), meta: "{1:1}".to_owned(), uuid: None})
].into_iter().map(|(a, b)| (a.into(), b)).collect::<HashMap<_, _>>());
}
#[test]
@@ -175,15 +175,15 @@ mod tests {
let tempdir = TempDir::new("").unwrap();
let mut b = AddressBook::new(tempdir.path());
b.set_name(Address::from_low_u64_be(1), "One".to_owned());
b.set_name(Address::from_low_u64_be(2), "Two".to_owned());
b.set_name(Address::from_low_u64_be(3), "Three".to_owned());
b.remove(Address::from_low_u64_be(2).into());
b.set_name(1.into(), "One".to_owned());
b.set_name(2.into(), "Two".to_owned());
b.set_name(3.into(), "Three".to_owned());
b.remove(2.into());
let b = AddressBook::new(tempdir.path());
assert_eq!(b.get(), vec![
(Address::from_low_u64_be(1), AccountMeta{name: "One".to_owned(), meta: "{}".to_owned(), uuid: None}),
(Address::from_low_u64_be(3), AccountMeta{name: "Three".to_owned(), meta: "{}".to_owned(), uuid: None}),
].into_iter().collect::<HashMap<_, _>>());
(1, AccountMeta{name: "One".to_owned(), meta: "{}".to_owned(), uuid: None}),
(3, AccountMeta{name: "Three".to_owned(), meta: "{}".to_owned(), uuid: None}),
].into_iter().map(|(a, b)| (a.into(), b)).collect::<HashMap<_, _>>());
}
}

View File

@@ -7,7 +7,7 @@ version = "1.4.0"
authors = ["Parity <admin@parity.io>"]
[dependencies]
ethereum-types = "0.6.0"
ethereum-types = "0.4"
futures = "0.1"
rpassword = "1.0"
parity-rpc = { path = "../rpc" }

View File

@@ -7,7 +7,7 @@ version = "1.4.0"
authors = ["Parity <admin@parity.io>"]
[dependencies]
ethereum-types = "0.6.0"
ethereum-types = "0.4"
futures = "0.1"
log = "0.4"
serde = "1.0"
@@ -15,7 +15,7 @@ serde_json = "1.0"
url = "1.2.0"
matches = "0.1"
parking_lot = "0.7"
jsonrpc-core = "12.0.0"
jsonrpc-ws-server = "12.0.0"
jsonrpc-core = "10.0.1"
jsonrpc-ws-server = "10.0.1"
parity-rpc = { path = "../../rpc" }
keccak-hash = "0.2.0"
keccak-hash = "0.1"

View File

@@ -7,8 +7,8 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
crunchy = "0.1.0"
either = "1.0.0"
ethereum-types = "0.6.0"
keccak-hash = "0.2.0"
ethereum-types = "0.4"
keccak-hash = "0.1"
log = "0.4"
memmap = "0.6"
parking_lot = "0.7"

View File

@@ -52,14 +52,14 @@ mod progpow;
pub use cache::{NodeCacheBuilder, OptimizeFor};
pub use compute::{ProofOfWork, quick_get_difficulty, slow_hash_block_number};
use compute::Light;
use ethereum_types::{BigEndianHash, U256, U512};
use ethereum_types::{U256, U512};
use keccak::H256;
use parking_lot::Mutex;
pub use seed_compute::SeedHashCompute;
pub use shared::ETHASH_EPOCH_LENGTH;
use std::mem;
use std::path::{Path, PathBuf};
use std::convert::TryFrom;
use std::sync::Arc;
struct LightCache {
@@ -161,12 +161,12 @@ impl EthashManager {
/// Convert an Ethash boundary to its original difficulty. Basically just `f(x) = 2^256 / x`.
pub fn boundary_to_difficulty(boundary: &ethereum_types::H256) -> U256 {
difficulty_to_boundary_aux(&boundary.into_uint())
difficulty_to_boundary_aux(&**boundary)
}
/// Convert an Ethash difficulty to the target boundary. Basically just `f(x) = 2^256 / x`.
pub fn difficulty_to_boundary(difficulty: &U256) -> ethereum_types::H256 {
BigEndianHash::from_uint(&difficulty_to_boundary_aux(difficulty))
difficulty_to_boundary_aux(difficulty).into()
}
fn difficulty_to_boundary_aux<T: Into<U512>>(difficulty: T) -> ethereum_types::U256 {
@@ -177,8 +177,8 @@ fn difficulty_to_boundary_aux<T: Into<U512>>(difficulty: T) -> ethereum_types::U
if difficulty == U512::one() {
U256::max_value()
} else {
const PROOF: &str = "difficulty > 1, so result never overflows 256 bits; qed";
U256::try_from((U512::one() << 256) / difficulty).expect(PROOF)
// difficulty > 1, so result should never overflow 256 bits
U256::from((U512::one() << 256) / difficulty)
}
}
@@ -203,10 +203,10 @@ fn test_lru() {
#[test]
fn test_difficulty_to_boundary() {
use ethereum_types::{H256, BigEndianHash};
use ethereum_types::H256;
use std::str::FromStr;
assert_eq!(difficulty_to_boundary(&U256::from(1)), BigEndianHash::from_uint(&U256::max_value()));
assert_eq!(difficulty_to_boundary(&U256::from(1)), H256::from(U256::max_value()));
assert_eq!(difficulty_to_boundary(&U256::from(2)), H256::from_str("8000000000000000000000000000000000000000000000000000000000000000").unwrap());
assert_eq!(difficulty_to_boundary(&U256::from(4)), H256::from_str("4000000000000000000000000000000000000000000000000000000000000000").unwrap());
assert_eq!(difficulty_to_boundary(&U256::from(32)), H256::from_str("0800000000000000000000000000000000000000000000000000000000000000").unwrap());
@@ -220,18 +220,9 @@ fn test_difficulty_to_boundary_regression() {
// https://github.com/paritytech/parity-ethereum/issues/8397
for difficulty in 1..9 {
assert_eq!(U256::from(difficulty), boundary_to_difficulty(&difficulty_to_boundary(&difficulty.into())));
assert_eq!(
H256::from_low_u64_be(difficulty),
difficulty_to_boundary(&boundary_to_difficulty(&H256::from_low_u64_be(difficulty))),
);
assert_eq!(
U256::from(difficulty),
boundary_to_difficulty(&BigEndianHash::from_uint(&boundary_to_difficulty(&H256::from_low_u64_be(difficulty)))),
);
assert_eq!(
H256::from_low_u64_be(difficulty),
difficulty_to_boundary(&difficulty_to_boundary(&difficulty.into()).into_uint()),
);
assert_eq!(H256::from(difficulty), difficulty_to_boundary(&boundary_to_difficulty(&difficulty.into())));
assert_eq!(U256::from(difficulty), boundary_to_difficulty(&boundary_to_difficulty(&difficulty.into()).into()));
assert_eq!(H256::from(difficulty), difficulty_to_boundary(&difficulty_to_boundary(&difficulty.into()).into()));
}
}
@@ -244,5 +235,5 @@ fn test_difficulty_to_boundary_panics_on_zero() {
#[test]
#[should_panic]
fn test_boundary_to_difficulty_panics_on_zero() {
boundary_to_difficulty(&ethereum_types::H256::zero());
boundary_to_difficulty(&ethereum_types::H256::from(0));
}

View File

@@ -14,22 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! ProgPoW (Programmatic Proof-of-Work) is the Ethereum network's proposed new Application-Specific Integrated
//! Circuit (ASIC) resistant Proof-of-Work mining algorithm.
//!
//! ProgPoW's aim is to reduce the efficiencies of specialized mining devices known as ASIC chips
//! (and accelerated GPU-based setups), and to maximize the performance of General Purpose Hardware (GPUs) to enable
//! more users to compete for new cryptocurrency awarded by the protocol.
//!
//! ASIC chips are those that are tailored to efficiently mining cryptocurrency based on a specific hashing algorithm.
//!
//! GPU mining setups are less specialised are struggle to compete for mining rewards.
//!
//! It would be a change from Ethereum's current PoW mining algorithm known as Ethash.
//!
//! ProgPoW audits have been proposed to analyse the efficiency of a ProgPoW ASICs over
//! GPUs and analysis of the economic impact on the Ethereum protocol.
use compute::{FNV_PRIME, calculate_dag_item};
use keccak::H256;
use shared::{ETHASH_ACCESSES, ETHASH_MIX_BYTES, Node, get_data_size};

View File

@@ -7,17 +7,17 @@ version = "1.12.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
account-db = { path = "account-db" }
ansi_term = "0.11"
ansi_term = "0.10"
blooms-db = { path = "../util/blooms-db", optional = true }
bn = { git = "https://github.com/paritytech/bn", default-features = false }
byteorder = "1.0"
common-types = { path = "types" }
crossbeam-utils = "0.6"
derive_more = "0.14.0"
env_logger = { version = "0.5", optional = true }
ethabi = "8.0"
ethabi-contract = "8.0"
ethabi-derive = "8.0"
error-chain = { version = "0.12", default-features = false }
ethabi = "6.0"
ethabi-contract = "6.0"
ethabi-derive = "6.0"
ethash = { path = "../ethash" }
ethcore-blockchain = { path = "./blockchain" }
ethcore-bloom-journal = { path = "../util/bloom" }
@@ -26,16 +26,15 @@ ethcore-db = { path = "./db" }
ethcore-io = { path = "../util/io" }
ethcore-miner = { path = "../miner" }
ethcore-stratum = { path = "../miner/stratum", optional = true }
ethereum-types = "0.6.0"
ethereum-types = "0.4"
ethjson = { path = "../json" }
ethkey = { path = "../accounts/ethkey" }
evm = { path = "evm" }
futures = "0.1"
hash-db = "0.12.4"
parity-util-mem = "0.1"
hash-db = "0.11.0"
heapsize = "0.4"
itertools = "0.5"
journaldb = { path = "../util/journaldb" }
keccak-hash = "0.2.0"
keccak-hash = "0.1"
keccak-hasher = { path = "../util/keccak-hasher" }
kvdb = "0.1"
kvdb-memorydb = "0.1"
@@ -46,26 +45,24 @@ log = "0.4"
lru-cache = "0.1"
macros = { path = "../util/macros" }
memory-cache = { path = "../util/memory-cache" }
memory-db = "0.12.4"
memory-db = "0.11.0"
num = { version = "0.1", default-features = false, features = ["bigint"] }
num_cpus = "1.2"
parity-bytes = "0.1"
parity-crypto = "0.4.0"
parity-crypto = "0.3.0"
parity-snappy = "0.1"
parking_lot = "0.7"
pod-account = { path = "pod-account" }
trie-db = "0.12.4"
trie-db = "0.11.0"
patricia-trie-ethereum = { path = "../util/patricia-trie-ethereum" }
rand = "0.6"
rand = "0.4"
rayon = "1.1"
rlp = "0.4.0"
rlp = { version = "0.3.0", features = ["ethereum"] }
rlp_derive = { path = "../util/rlp-derive" }
rustc-hex = "1.0"
serde = "1.0"
serde_derive = "1.0"
state-account = { path = "state-account" }
stats = { path = "../util/stats" }
tempdir = { version = "0.3", optional = true }
tempdir = {version="0.3", optional = true}
time-utils = { path = "../util/time-utils" }
trace-time = "0.1"
triehash-ethereum = { version = "0.2", path = "../util/triehash-ethereum" }
@@ -73,7 +70,6 @@ unexpected = { path = "../util/unexpected" }
using_queue = { path = "../miner/using-queue" }
vm = { path = "vm" }
wasm = { path = "wasm" }
rand_xorshift = "0.1.1"
[dev-dependencies]
blooms-db = { path = "../util/blooms-db" }
@@ -84,9 +80,8 @@ fetch = { path = "../util/fetch" }
kvdb-rocksdb = "0.1.3"
parity-runtime = { path = "../util/runtime" }
rlp_compress = { path = "../util/rlp-compress" }
serde_json = "1.0"
tempdir = "0.3"
trie-standardmap = "0.12.4"
trie-standardmap = "0.1"
[features]
parity = ["work-notify", "price-info", "stratum"]

View File

@@ -1,14 +0,0 @@
[package]
description = "DB backend wrapper for Account trie"
name = "account-db"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
[dependencies]
ethereum-types = "0.6"
hash-db = "0.12.4"
keccak-hash = "0.2.0"
keccak-hasher = { path = "../../util/keccak-hasher" }
kvdb = "0.1"
rlp = "0.4"

View File

@@ -28,13 +28,13 @@ extern crate rustc_hex;
use criterion::{Criterion, Bencher};
use bytes::BytesRef;
use ethcore::builtin::Builtin;
use ethcore::machine::Machine;
use ethereum_types::H160;
use ethcore::machine::EthereumMachine;
use ethereum_types::U256;
use ethcore::ethereum::new_byzantium_test_machine;
use rustc_hex::FromHex;
lazy_static! {
static ref BYZANTIUM_MACHINE: Machine = new_byzantium_test_machine();
static ref BYZANTIUM_MACHINE: EthereumMachine = new_byzantium_test_machine();
}
struct BuiltinBenchmark<'a> {
@@ -46,9 +46,8 @@ struct BuiltinBenchmark<'a> {
impl<'a> BuiltinBenchmark<'a> {
fn new(builtin_address: &'static str, input: &str, expected: &str) -> BuiltinBenchmark<'a> {
let builtins = BYZANTIUM_MACHINE.builtins();
use std::str::FromStr;
let addr = H160::from_str(builtin_address).unwrap();
let builtin = builtins.get(&addr).unwrap().clone();
let builtin = builtins.get(&builtin_address.into()).unwrap().clone();
let input = FromHex::from_hex(input).unwrap();
let expected = FromHex::from_hex(expected).unwrap();
@@ -57,6 +56,10 @@ impl<'a> BuiltinBenchmark<'a> {
}
}
fn gas_cost(&self) -> U256 {
self.builtin.cost(&self.input)
}
fn run(&self, b: &mut Bencher) {
let mut output = vec![0; self.expected.len()];

View File

@@ -8,26 +8,26 @@ authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
[dependencies]
ansi_term = "0.11"
ansi_term = "0.10"
blooms-db = { path = "../../util/blooms-db" }
common-types = { path = "../types" }
ethcore-db = { path = "../db" }
ethereum-types = "0.6.0"
parity-util-mem = "0.1"
ethereum-types = "0.4"
heapsize = "0.4"
itertools = "0.5"
kvdb = "0.1"
log = "0.4"
parity-bytes = "0.1"
parking_lot = "0.7"
rayon = "1.1"
rlp = "0.4.0"
rlp = { version = "0.3.0", features = ["ethereum"] }
rlp_compress = { path = "../../util/rlp-compress" }
rlp_derive = { path = "../../util/rlp-derive" }
[dev-dependencies]
env_logger = "0.5"
ethkey = { path = "../../accounts/ethkey" }
keccak-hash = "0.2.0"
keccak-hash = "0.1"
rustc-hex = "1.0"
tempdir = "0.3"
kvdb-memorydb = "0.1"

View File

@@ -24,8 +24,7 @@ use common_types::header::Header;
/// For GHOST fork-choice rule it would typically describe the block with highest
/// combined difficulty (usually the block with the highest block number).
///
/// Sometimes referred as 'latest block'.
#[derive(Debug)]
/// Sometimes refered as 'latest block'.
pub struct BestBlock {
/// Best block decoded header.
pub header: Header,
@@ -36,7 +35,7 @@ pub struct BestBlock {
}
/// Best ancient block info. If the blockchain has a gap this keeps track of where it starts.
#[derive(Debug, Default)]
#[derive(Default)]
pub struct BestAncientBlock {
/// Best block hash.
pub hash: H256,

View File

@@ -39,10 +39,10 @@ use ethcore_db::cache_manager::CacheManager;
use ethcore_db::keys::{BlockReceipts, BlockDetails, TransactionAddress, EPOCH_KEY_PREFIX, EpochTransitions};
use ethcore_db::{self as db, Writable, Readable, CacheUpdatePolicy};
use ethereum_types::{H256, Bloom, BloomRef, U256};
use util_mem::{MallocSizeOf, allocators::new_malloc_size_ops};
use heapsize::HeapSizeOf;
use itertools::Itertools;
use kvdb::{DBTransaction, KeyValueDB};
use log::{trace, debug, warn, info};
use log::{trace, warn, info};
use parity_bytes::Bytes;
use parking_lot::{Mutex, RwLock};
use rayon::prelude::*;
@@ -57,7 +57,7 @@ use crate::{CacheSize, ImportRoute, Config};
/// Database backing `BlockChain`.
pub trait BlockChainDB: Send + Sync {
/// Generic key value store.
fn key_value(&self) -> &Arc<dyn KeyValueDB>;
fn key_value(&self) -> &Arc<KeyValueDB>;
/// Header blooms database.
fn blooms(&self) -> &blooms_db::Database;
@@ -85,7 +85,7 @@ pub trait BlockChainDB: Send + Sync {
/// predefined config.
pub trait BlockChainDBHandler: Send + Sync {
/// Open the predefined key-value database.
fn open(&self, path: &Path) -> io::Result<Arc<dyn BlockChainDB>>;
fn open(&self, path: &Path) -> io::Result<Arc<BlockChainDB>>;
}
/// Interface for querying blocks by hash and by number.
@@ -228,7 +228,7 @@ pub struct BlockChain {
transaction_addresses: RwLock<HashMap<H256, TransactionAddress>>,
block_receipts: RwLock<HashMap<H256, BlockReceipts>>,
db: Arc<dyn BlockChainDB>,
db: Arc<BlockChainDB>,
cache_man: Mutex<CacheManager<CacheId>>,
@@ -284,7 +284,7 @@ impl BlockProvider for BlockChain {
}
// Read from DB and populate cache
let b = self.db.key_value().get(db::COL_HEADERS, hash.as_bytes())
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());
@@ -314,7 +314,7 @@ impl BlockProvider for BlockChain {
}
// Read from DB and populate cache
let b = self.db.key_value().get(db::COL_BODIES, hash.as_bytes())
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());
@@ -469,7 +469,7 @@ impl<'a> Iterator for AncestryWithMetadataIter<'a> {
})
},
_ => {
self.current = H256::zero();
self.current = H256::default();
None
},
}
@@ -481,7 +481,7 @@ impl<'a> Iterator for AncestryWithMetadataIter<'a> {
/// Returns epoch transitions.
pub struct EpochTransitionIter<'a> {
chain: &'a BlockChain,
prefix_iter: Box<dyn Iterator<Item=(Box<[u8]>, Box<[u8]>)> + 'a>,
prefix_iter: Box<Iterator<Item=(Box<[u8]>, Box<[u8]>)> + 'a>,
}
impl<'a> Iterator for EpochTransitionIter<'a> {
@@ -521,7 +521,7 @@ 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<dyn BlockChainDB>) -> BlockChain {
pub fn new(config: Config, genesis: &[u8], db: Arc<BlockChainDB>) -> BlockChain {
// 400 is the average size of the key
let cache_man = CacheManager::new(config.pref_cache_size, config.max_cache_size, 400);
@@ -572,13 +572,13 @@ impl BlockChain {
};
let mut batch = DBTransaction::new();
batch.put(db::COL_HEADERS, hash.as_bytes(), block.header_rlp().as_raw());
batch.put(db::COL_BODIES, hash.as_bytes(), &Self::block_to_body(genesis));
batch.put(db::COL_HEADERS, &hash, block.header_rlp().as_raw());
batch.put(db::COL_BODIES, &hash, &Self::block_to_body(genesis));
batch.write(db::COL_EXTRA, &hash, &details);
batch.write(db::COL_EXTRA, &header.number(), &hash);
batch.put(db::COL_EXTRA, b"best", hash.as_bytes());
batch.put(db::COL_EXTRA, b"best", &hash);
bc.db.key_value().write(batch).expect("Low level database error when fetching 'best' block. Some issue with disk?");
hash
}
@@ -639,7 +639,7 @@ impl BlockChain {
if hash != bc.genesis_hash() {
trace!("First block calculated: {:?}", hash);
let mut batch = db.key_value().transaction();
batch.put(db::COL_EXTRA, b"first", hash.as_bytes());
batch.put(db::COL_EXTRA, b"first", &hash);
db.key_value().write(batch).expect("Low level database error when writing 'first' block. Some issue with disk?");
bc.first_block = Some(hash);
}
@@ -652,7 +652,10 @@ impl BlockChain {
// and write them
if let (Some(hash), Some(number)) = (best_ancient, best_ancient_number) {
let mut best_ancient_block = bc.best_ancient_block.write();
*best_ancient_block = Some(BestAncientBlock { hash, number });
*best_ancient_block = Some(BestAncientBlock {
hash: hash,
number: number,
});
}
}
@@ -755,8 +758,8 @@ impl BlockChain {
Some(TreeRoute {
blocks: from_branch,
ancestor: current_from,
index,
is_from_route_finalized,
index: index,
is_from_route_finalized: is_from_route_finalized,
})
}
@@ -785,8 +788,8 @@ impl BlockChain {
let compressed_body = compress(&Self::block_to_body(block.raw()), blocks_swapper());
// store block in db
batch.put(db::COL_HEADERS, hash.as_bytes(), &compressed_header);
batch.put(db::COL_BODIES, hash.as_bytes(), &compressed_body);
batch.put(db::COL_HEADERS, &hash, &compressed_header);
batch.put(db::COL_BODIES, &hash, &compressed_body);
let maybe_parent = self.block_details(&block_parent_hash);
@@ -929,7 +932,7 @@ impl BlockChain {
*pending_best_ancient_block = Some(None);
} else if block_number > ancient_number {
trace!(target: "blockchain", "Updating the best ancient block to {}.", block_number);
batch.put(db::COL_EXTRA, b"ancient", block_hash.as_bytes());
batch.put(db::COL_EXTRA, b"ancient", &block_hash);
*pending_best_ancient_block = Some(Some(BestAncientBlock {
hash: *block_hash,
number: block_number,
@@ -960,7 +963,6 @@ impl BlockChain {
/// Iterate over all epoch transitions.
/// This will only return transitions within the canonical chain.
pub fn epoch_transitions(&self) -> EpochTransitionIter {
debug!(target: "blockchain", "Iterating over all epoch transitions");
let iter = self.db.key_value().iter_from_prefix(db::COL_EXTRA, &EPOCH_KEY_PREFIX[..]);
EpochTransitionIter {
chain: self,
@@ -986,9 +988,7 @@ impl BlockChain {
pub fn epoch_transition_for(&self, parent_hash: H256) -> Option<EpochTransition> {
// slow path: loop back block by block
for hash in self.ancestry_iter(parent_hash)? {
trace!(target: "blockchain", "Got parent hash {} from ancestry_iter", hash);
let details = self.block_details(&hash)?;
trace!(target: "blockchain", "Block #{}: Got block details for parent hash {}", details.number, hash);
// look for transition in database.
if let Some(transition) = self.epoch_transition(details.number, hash) {
@@ -1000,22 +1000,11 @@ impl BlockChain {
//
// if `block_hash` is canonical it will only return transitions up to
// the parent.
match self.block_hash(details.number) {
Some(h) if h == hash => {
return self.epoch_transitions()
.map(|(_, t)| t)
.take_while(|t| t.block_number <= details.number)
.last()
},
Some(h) => {
warn!(target: "blockchain", "Block #{}: Found non-canonical block hash {} (expected {})", details.number, h, hash);
trace!(target: "blockchain", "Block #{} Mismatched hashes. Ancestor {} != Own {}", details.number, hash, h);
trace!(target: "blockchain", " Ancestor {}: #{:#?}", hash, details);
trace!(target: "blockchain", " Own {}: #{:#?}", h, self.block_details(&h));
},
None => trace!(target: "blockchain", "Block #{}: hash {} not found in cache or DB", details.number, hash),
if self.block_hash(details.number)? == hash {
return self.epoch_transitions()
.map(|(_, t)| t)
.take_while(|t| t.block_number <= details.number)
.last()
}
}
@@ -1083,8 +1072,8 @@ impl BlockChain {
let compressed_body = compress(&Self::block_to_body(block.raw()), blocks_swapper());
// store block in db
batch.put(db::COL_HEADERS, hash.as_bytes(), &compressed_header);
batch.put(db::COL_BODIES, hash.as_bytes(), &compressed_body);
batch.put(db::COL_HEADERS, &hash, &compressed_header);
batch.put(db::COL_BODIES, &hash, &compressed_body);
let info = self.block_info(&block.header_view(), route, &extras);
@@ -1183,7 +1172,7 @@ 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.as_bytes());
batch.put(db::COL_EXTRA, b"best", &update.info.hash);
*best_block = Some(BestBlock {
total_difficulty: update.info.total_difficulty,
header: update.block.decode_header(),
@@ -1270,7 +1259,7 @@ impl BlockChain {
current: if self.is_known(&first) {
first
} else {
H256::zero() // zero hash
H256::default() // zero hash
},
chain: self
}
@@ -1486,12 +1475,11 @@ impl BlockChain {
/// Get current cache size.
pub fn cache_size(&self) -> CacheSize {
let mut ops = new_malloc_size_ops();
CacheSize {
blocks: self.block_headers.size_of(&mut ops) + self.block_bodies.size_of(&mut ops),
block_details: self.block_details.size_of(&mut ops),
transaction_addresses: self.transaction_addresses.size_of(&mut ops),
block_receipts: self.block_receipts.size_of(&mut ops),
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(),
block_receipts: self.block_receipts.read().heap_size_of_children(),
}
}
@@ -1526,13 +1514,12 @@ impl BlockChain {
transaction_addresses.shrink_to_fit();
block_receipts.shrink_to_fit();
let mut ops = new_malloc_size_ops();
block_headers.size_of(&mut ops) +
block_bodies.size_of(&mut ops) +
block_details.size_of(&mut ops) +
block_hashes.size_of(&mut ops) +
transaction_addresses.size_of(&mut ops) +
block_receipts.size_of(&mut ops)
block_headers.heap_size_of_children() +
block_bodies.heap_size_of_children() +
block_details.heap_size_of_children() +
block_hashes.heap_size_of_children() +
transaction_addresses.heap_size_of_children() +
block_receipts.heap_size_of_children()
});
}
@@ -1584,18 +1571,17 @@ mod tests {
use keccak_hash::keccak;
use rustc_hex::FromHex;
use tempdir::TempDir;
use std::str::FromStr;
struct TestBlockChainDB {
_blooms_dir: TempDir,
_trace_blooms_dir: TempDir,
blooms: blooms_db::Database,
trace_blooms: blooms_db::Database,
key_value: Arc<dyn KeyValueDB>,
key_value: Arc<KeyValueDB>,
}
impl BlockChainDB for TestBlockChainDB {
fn key_value(&self) -> &Arc<dyn KeyValueDB> {
fn key_value(&self) -> &Arc<KeyValueDB> {
&self.key_value
}
@@ -1609,7 +1595,7 @@ mod tests {
}
/// Creates new test instance of `BlockChainDB`
pub fn new_db() -> Arc<dyn BlockChainDB> {
pub fn new_db() -> Arc<BlockChainDB> {
let blooms_dir = TempDir::new("").unwrap();
let trace_blooms_dir = TempDir::new("").unwrap();
@@ -1624,15 +1610,15 @@ mod tests {
Arc::new(db)
}
fn new_chain(genesis: encoded::Block, db: Arc<dyn BlockChainDB>) -> BlockChain {
fn new_chain(genesis: encoded::Block, db: Arc<BlockChainDB>) -> BlockChain {
BlockChain::new(Config::default(), genesis.raw(), db)
}
fn insert_block(db: &Arc<dyn BlockChainDB>, bc: &BlockChain, block: encoded::Block, receipts: Vec<Receipt>) -> ImportRoute {
fn insert_block(db: &Arc<BlockChainDB>, bc: &BlockChain, block: encoded::Block, receipts: Vec<Receipt>) -> ImportRoute {
insert_block_commit(db, bc, block, receipts, true)
}
fn insert_block_commit(db: &Arc<dyn BlockChainDB>, bc: &BlockChain, block: encoded::Block, receipts: Vec<Receipt>, commit: bool) -> ImportRoute {
fn insert_block_commit(db: &Arc<BlockChainDB>, bc: &BlockChain, block: encoded::Block, receipts: Vec<Receipt>, 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();
@@ -1643,6 +1629,8 @@ mod tests {
}
fn insert_block_batch(batch: &mut DBTransaction, bc: &BlockChain, block: encoded::Block, receipts: Vec<Receipt>) -> ImportRoute {
use crate::ExtrasInsert;
let fork_choice = {
let header = block.header_view();
let parent_hash = header.parent_hash();
@@ -2069,7 +2057,7 @@ mod tests {
fn find_transaction_by_hash() {
let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0af81e09f8c46ca322193edfda764fa7e88e81923f802f1d325ec0b0308ac2cd0a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200008083023e38808454c98c8142a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421880102030405060708c0c0".from_hex().unwrap();
let b1 = "f904a8f901faa0ce1f26f798dd03c8782d63b3e42e79a64eaea5694ea686ac5d7ce3df5171d1aea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0a65c2364cd0f1542d761823dc0109c6b072f14c20459598c5455c274601438f4a070616ebd7ad2ed6fb7860cf7e9df00163842351c38a87cac2c1cb193895035a2a05c5b4fc43c2d45787f54e1ae7d27afdb4ad16dfc567c5692070d5c4556e0b1d7b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200000183023ec683021536845685109780a029f07836e4e59229b3a065913afc27702642c683bba689910b2b2fd45db310d3888957e6d004a31802f902a7f85f800a8255f094aaaf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca0575da4e21b66fa764be5f74da9389e67693d066fb0d1312e19e17e501da00ecda06baf5a5327595f6619dfc2fcb3f2e6fb410b5810af3cb52d0e7508038e91a188f85f010a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba04fa966bf34b93abc1bcd665554b7f316b50f928477b50be0f3285ead29d18c5ba017bba0eeec1625ab433746955e125d46d80b7fdc97386c51266f842d8e02192ef85f020a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca004377418ae981cc32b1312b4a427a1d69a821b28db8584f5f2bd8c6d42458adaa053a1dba1af177fac92f3b6af0a9fa46a22adf56e686c93794b6a012bf254abf5f85f030a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca04fe13febd28a05f4fcb2f451d7ddc2dda56486d9f8c79a62b0ba4da775122615a0651b2382dd402df9ebc27f8cb4b2e0f3cea68dda2dca0ee9603608f0b6f51668f85f040a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba078e6a0ba086a08f8450e208a399bb2f2d2a0d984acd2517c7c7df66ccfab567da013254002cd45a97fac049ae00afbc43ed0d9961d0c56a3b2382c80ce41c198ddf85f050a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba0a7174d8f43ea71c8e3ca9477691add8d80ac8e0ed89d8d8b572041eef81f4a54a0534ea2e28ec4da3b5b944b18c51ec84a5cf35f5b3343c5fb86521fd2d388f506f85f060a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba034bd04065833536a10c77ee2a43a5371bc6d34837088b861dd9d4b7f44074b59a078807715786a13876d3455716a6b9cb2186b7a4887a5c31160fc877454958616c0".from_hex().unwrap();
let b1_hash = H256::from_str("f53f268d23a71e85c7d6d83a9504298712b84c1a2ba220441c86eeda0bf0b6e3").unwrap();
let b1_hash: H256 = "f53f268d23a71e85c7d6d83a9504298712b84c1a2ba220441c86eeda0bf0b6e3".into();
let db = new_db();
let bc = new_chain(encoded::Block::new(genesis), db.clone());
@@ -2142,7 +2130,7 @@ mod tests {
let db = new_db();
let bc = new_chain(genesis.last().encoded(), db.clone());
insert_block(&db, &bc, b1.last().encoded(), vec![Receipt {
outcome: TransactionOutcome::StateRoot(H256::zero()),
outcome: TransactionOutcome::StateRoot(H256::default()),
gas_used: 10_000.into(),
log_bloom: Default::default(),
logs: vec![
@@ -2151,7 +2139,7 @@ mod tests {
],
},
Receipt {
outcome: TransactionOutcome::StateRoot(H256::zero()),
outcome: TransactionOutcome::StateRoot(H256::default()),
gas_used: 10_000.into(),
log_bloom: Default::default(),
logs: vec![
@@ -2160,7 +2148,7 @@ mod tests {
}]);
insert_block(&db, &bc, b2.last().encoded(), vec![
Receipt {
outcome: TransactionOutcome::StateRoot(H256::zero()),
outcome: TransactionOutcome::StateRoot(H256::default()),
gas_used: 10_000.into(),
log_bloom: Default::default(),
logs: vec![
@@ -2170,7 +2158,7 @@ mod tests {
]);
insert_block(&db, &bc, b3.last().encoded(), vec![
Receipt {
outcome: TransactionOutcome::StateRoot(H256::zero()),
outcome: TransactionOutcome::StateRoot(H256::default()),
gas_used: 10_000.into(),
log_bloom: Default::default(),
logs: vec![
@@ -2249,11 +2237,11 @@ mod tests {
#[test]
fn test_bloom_filter_simple() {
let bloom_b1 = Bloom::from_str("00000020000000000000000000000000000000000000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000002000").unwrap();
let bloom_b1: Bloom = "00000020000000000000000000000000000000000000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000002000".into();
let bloom_b2 = Bloom::from_str("00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
let bloom_b2: Bloom = "00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into();
let bloom_ba = Bloom::from_str("00000000000000000000000000000000000000000000020000000800000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
let bloom_ba: Bloom = "00000000000000000000000000000000000000000000020000000800000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into();
let genesis = BlockBuilder::genesis();
let b1 = genesis.add_block_with(|| BlockOptions {
@@ -2317,11 +2305,11 @@ mod tests {
#[test]
fn test_insert_unordered() {
let bloom_b1 = Bloom::from_str("00000020000000000000000000000000000000000000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000002000").unwrap();
let bloom_b1: Bloom = "00000020000000000000000000000000000000000000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000002000".into();
let bloom_b2 = Bloom::from_str("00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
let bloom_b2: Bloom = "00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into();
let bloom_b3 = Bloom::from_str("00000000000000000000000000000000000000000000020000000800000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
let bloom_b3: Bloom = "00000000000000000000000000000000000000000000020000000800000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into();
let genesis = BlockBuilder::genesis();
let b1 = genesis.add_block_with_bloom(bloom_b1);

View File

@@ -68,7 +68,7 @@ impl From<BlockInfo> for ImportRoute {
#[cfg(test)]
mod tests {
use ethereum_types::{U256, BigEndianHash};
use ethereum_types::{H256, U256};
use crate::block_info::{BlockInfo, BlockLocation, BranchBecomingCanonChainData};
use super::ImportRoute;
@@ -84,7 +84,7 @@ mod tests {
#[test]
fn import_route_branch() {
let info = BlockInfo {
hash: BigEndianHash::from_uint(&U256::from(1)),
hash: H256::from(U256::from(1)),
number: 0,
total_difficulty: U256::from(0),
location: BlockLocation::Branch,
@@ -93,14 +93,14 @@ mod tests {
assert_eq!(ImportRoute::from(info), ImportRoute {
retracted: vec![],
enacted: vec![],
omitted: vec![BigEndianHash::from_uint(&U256::from(1))],
omitted: vec![H256::from(U256::from(1))],
});
}
#[test]
fn import_route_canon_chain() {
let info = BlockInfo {
hash: BigEndianHash::from_uint(&U256::from(1)),
hash: H256::from(U256::from(1)),
number: 0,
total_difficulty: U256::from(0),
location: BlockLocation::CanonChain,
@@ -108,7 +108,7 @@ mod tests {
assert_eq!(ImportRoute::from(info), ImportRoute {
retracted: vec![],
enacted: vec![BigEndianHash::from_uint(&U256::from(1))],
enacted: vec![H256::from(U256::from(1))],
omitted: vec![],
});
}
@@ -116,19 +116,19 @@ mod tests {
#[test]
fn import_route_branch_becoming_canon_chain() {
let info = BlockInfo {
hash: BigEndianHash::from_uint(&U256::from(2)),
hash: H256::from(U256::from(2)),
number: 0,
total_difficulty: U256::from(0),
location: BlockLocation::BranchBecomingCanonChain(BranchBecomingCanonChainData {
ancestor: BigEndianHash::from_uint(&U256::from(0)),
enacted: vec![BigEndianHash::from_uint(&U256::from(1))],
retracted: vec![BigEndianHash::from_uint(&U256::from(3)), BigEndianHash::from_uint(&U256::from(4))],
ancestor: H256::from(U256::from(0)),
enacted: vec![H256::from(U256::from(1))],
retracted: vec![H256::from(U256::from(3)), H256::from(U256::from(4))],
})
};
assert_eq!(ImportRoute::from(info), ImportRoute {
retracted: vec![BigEndianHash::from_uint(&U256::from(3)), BigEndianHash::from_uint(&U256::from(4))],
enacted: vec![BigEndianHash::from_uint(&U256::from(1)), BigEndianHash::from_uint(&U256::from(2))],
retracted: vec![H256::from(U256::from(3)), H256::from(U256::from(4))],
enacted: vec![H256::from(U256::from(1)), H256::from(U256::from(2))],
omitted: vec![],
});
}

View File

@@ -18,9 +18,6 @@
#![warn(missing_docs)]
extern crate parity_util_mem as util_mem;
extern crate parity_util_mem as malloc_size_of;
mod best_block;
mod block_info;
mod blockchain;

View File

@@ -8,5 +8,5 @@ edition = "2018"
[dependencies]
types = { path = "../types", package = "common-types" }
ethereum-types = "0.6.0"
ethereum-types = "0.4"
bytes = { version = "0.1", package = "parity-bytes" }

View File

@@ -9,9 +9,9 @@ edition = "2018"
[dependencies]
common-types = { path = "../types" }
ethereum-types = "0.6.0"
ethereum-types = "0.4"
heapsize = "0.4"
kvdb = "0.1"
parity-util-mem = "0.1"
parking_lot = "0.7"
rlp = "0.4.0"
rlp = { version = "0.3.0", features = ["ethereum"] }
rlp_derive = { path = "../../util/rlp-derive" }

View File

@@ -16,7 +16,7 @@
//! Database utilities and definitions.
use std::convert::AsRef;
use std::ops::Deref;
use std::hash::Hash;
use std::collections::HashMap;
use parking_lot::RwLock;
@@ -82,7 +82,7 @@ impl<K, V> Cache<K, V> for HashMap<K, V> where K: Hash + Eq {
/// Should be used to get database key associated with given value.
pub trait Key<T> {
/// The db key associated with this value.
type Target: AsRef<[u8]>;
type Target: Deref<Target = [u8]>;
/// Returns db key.
fn key(&self) -> Self::Target;
@@ -91,16 +91,16 @@ pub trait Key<T> {
/// Should be used to write value into database.
pub trait Writable {
/// Writes the value into the database.
fn write<T, R>(&mut self, col: Option<u32>, key: &Key<T, Target = R>, value: &T) where T: rlp::Encodable, R: AsRef<[u8]>;
fn write<T, R>(&mut self, col: Option<u32>, key: &Key<T, Target = R>, value: &T) where T: rlp::Encodable, R: Deref<Target = [u8]>;
/// Deletes key from the databse.
fn delete<T, R>(&mut self, col: Option<u32>, key: &Key<T, Target = R>) where T: rlp::Encodable, R: AsRef<[u8]>;
fn delete<T, R>(&mut self, col: Option<u32>, key: &Key<T, Target = R>) where T: rlp::Encodable, R: Deref<Target = [u8]>;
/// Writes the value into the database and updates the cache.
fn write_with_cache<K, T, R>(&mut self, col: Option<u32>, cache: &mut Cache<K, T>, key: K, value: T, policy: CacheUpdatePolicy) where
K: Key<T, Target = R> + Hash + Eq,
T: rlp::Encodable,
R: AsRef<[u8]> {
R: Deref<Target = [u8]> {
self.write(col, &key, &value);
match policy {
CacheUpdatePolicy::Overwrite => {
@@ -116,7 +116,7 @@ pub trait Writable {
fn extend_with_cache<K, T, R>(&mut self, col: Option<u32>, cache: &mut Cache<K, T>, values: HashMap<K, T>, policy: CacheUpdatePolicy) where
K: Key<T, Target = R> + Hash + Eq,
T: rlp::Encodable,
R: AsRef<[u8]> {
R: Deref<Target = [u8]> {
match policy {
CacheUpdatePolicy::Overwrite => {
for (key, value) in values {
@@ -137,7 +137,7 @@ pub trait Writable {
fn extend_with_option_cache<K, T, R>(&mut self, col: Option<u32>, cache: &mut Cache<K, Option<T>>, values: HashMap<K, Option<T>>, policy: CacheUpdatePolicy) where
K: Key<T, Target = R> + Hash + Eq,
T: rlp::Encodable,
R: AsRef<[u8]> {
R: Deref<Target = [u8]> {
match policy {
CacheUpdatePolicy::Overwrite => {
for (key, value) in values {
@@ -167,7 +167,7 @@ pub trait Readable {
/// Returns value for given key.
fn read<T, R>(&self, col: Option<u32>, key: &Key<T, Target = R>) -> Option<T> where
T: rlp::Decodable,
R: AsRef<[u8]>;
R: Deref<Target = [u8]>;
/// Returns value for given key either in cache or in database.
fn read_with_cache<K, T, C>(&self, col: Option<u32>, cache: &RwLock<C>, key: &K) -> Option<T> where
@@ -189,12 +189,12 @@ pub trait Readable {
}
/// Returns true if given value exists.
fn exists<T, R>(&self, col: Option<u32>, key: &Key<T, Target = R>) -> bool where R: AsRef<[u8]>;
fn exists<T, R>(&self, col: Option<u32>, key: &Key<T, Target = R>) -> bool where R: Deref<Target= [u8]>;
/// Returns true if given value exists either in cache or in database.
fn exists_with_cache<K, T, R, C>(&self, col: Option<u32>, cache: &RwLock<C>, key: &K) -> bool where
K: Eq + Hash + Key<T, Target = R>,
R: AsRef<[u8]>,
R: Deref<Target = [u8]>,
C: Cache<K, T> {
{
let read = cache.read();
@@ -208,31 +208,31 @@ pub trait Readable {
}
impl Writable for DBTransaction {
fn write<T, R>(&mut self, col: Option<u32>, key: &Key<T, Target = R>, value: &T) where T: rlp::Encodable, R: AsRef<[u8]> {
self.put(col, key.key().as_ref(), &rlp::encode(value));
fn write<T, R>(&mut self, col: Option<u32>, key: &Key<T, Target = R>, value: &T) where T: rlp::Encodable, R: Deref<Target = [u8]> {
self.put(col, &key.key(), &rlp::encode(value));
}
fn delete<T, R>(&mut self, col: Option<u32>, key: &Key<T, Target = R>) where T: rlp::Encodable, R: AsRef<[u8]> {
self.delete(col, key.key().as_ref());
fn delete<T, R>(&mut self, col: Option<u32>, key: &Key<T, Target = R>) where T: rlp::Encodable, R: Deref<Target = [u8]> {
self.delete(col, &key.key());
}
}
impl<KVDB: KeyValueDB + ?Sized> Readable for KVDB {
fn read<T, R>(&self, col: Option<u32>, key: &Key<T, Target = R>) -> Option<T>
where T: rlp::Decodable, R: AsRef<[u8]> {
self.get(col, key.key().as_ref())
.expect(&format!("db get failed, key: {:?}", key.key().as_ref()))
where T: rlp::Decodable, R: Deref<Target = [u8]> {
self.get(col, &key.key())
.expect(&format!("db get failed, key: {:?}", &key.key() as &[u8]))
.map(|v| rlp::decode(&v).expect("decode db value failed") )
}
fn exists<T, R>(&self, col: Option<u32>, key: &Key<T, Target = R>) -> bool where R: AsRef<[u8]> {
let result = self.get(col, key.key().as_ref());
fn exists<T, R>(&self, col: Option<u32>, key: &Key<T, Target = R>) -> bool where R: Deref<Target = [u8]> {
let result = self.get(col, &key.key());
match result {
Ok(v) => v.is_some(),
Err(err) => {
panic!("db get failed, key: {:?}, err: {:?}", key.key().as_ref(), err);
panic!("db get failed, key: {:?}, err: {:?}", &key.key() as &[u8], err);
}
}
}

View File

@@ -17,13 +17,13 @@
//! Blockchain DB extras.
use std::io::Write;
use std::convert::AsRef;
use std::ops;
use common_types::BlockNumber;
use common_types::engines::epoch::Transition as EpochTransition;
use common_types::receipt::Receipt;
use ethereum_types::{H256, H264, U256};
use parity_util_mem::MallocSizeOf;
use heapsize::HeapSizeOf;
use kvdb::PREFIX_LEN as DB_PREFIX_LEN;
use rlp;
use rlp_derive::{RlpEncodableWrapper, RlpDecodableWrapper, RlpEncodable, RlpDecodable};
@@ -49,17 +49,19 @@ pub enum ExtrasIndex {
fn with_index(hash: &H256, i: ExtrasIndex) -> H264 {
let mut result = H264::default();
result.as_bytes_mut()[0] = i as u8;
result.as_bytes_mut()[1..].clone_from_slice(hash.as_bytes());
result[0] = i as u8;
(*result)[1..].clone_from_slice(hash);
result
}
/// Wrapper for block number used as a DB key.
pub struct BlockNumberKey([u8; 5]);
impl AsRef<[u8]> for BlockNumberKey {
fn as_ref(&self) -> &[u8] {
&self.0[..]
impl ops::Deref for BlockNumberKey {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.0
}
}
@@ -121,8 +123,10 @@ pub const EPOCH_KEY_PREFIX: &'static [u8; DB_PREFIX_LEN] = &[
/// Epoch transitions key
pub struct EpochTransitionsKey([u8; EPOCH_KEY_LEN]);
impl AsRef<[u8]> for EpochTransitionsKey {
fn as_ref(&self) -> &[u8] { &self.0[..] }
impl ops::Deref for EpochTransitionsKey {
type Target = [u8];
fn deref(&self) -> &[u8] { &self.0[..] }
}
impl Key<EpochTransitions> for u64 {
@@ -140,7 +144,7 @@ impl Key<EpochTransitions> for u64 {
}
/// Familial details concerning a block
#[derive(Debug, Clone, MallocSizeOf)]
#[derive(Debug, Clone)]
pub struct BlockDetails {
/// Block number
pub number: BlockNumber,
@@ -195,8 +199,14 @@ impl rlp::Decodable for BlockDetails {
}
}
impl HeapSizeOf for BlockDetails {
fn heap_size_of_children(&self) -> usize {
self.children.heap_size_of_children()
}
}
/// Represents address of certain transaction within block
#[derive(Debug, PartialEq, Clone, RlpEncodable, RlpDecodable, MallocSizeOf)]
#[derive(Debug, PartialEq, Clone, RlpEncodable, RlpDecodable)]
pub struct TransactionAddress {
/// Block hash
pub block_hash: H256,
@@ -204,8 +214,12 @@ pub struct TransactionAddress {
pub index: usize
}
impl HeapSizeOf for TransactionAddress {
fn heap_size_of_children(&self) -> usize { 0 }
}
/// Contains all block receipts.
#[derive(Debug, Clone, RlpEncodableWrapper, RlpDecodableWrapper, MallocSizeOf)]
#[derive(Clone, RlpEncodableWrapper, RlpDecodableWrapper)]
pub struct BlockReceipts {
/// Block receipts
pub receipts: Vec<Receipt>,
@@ -214,7 +228,15 @@ pub struct BlockReceipts {
impl BlockReceipts {
/// Create new block receipts wrapper.
pub fn new(receipts: Vec<Receipt>) -> Self {
BlockReceipts { receipts }
BlockReceipts {
receipts: receipts
}
}
}
impl HeapSizeOf for BlockReceipts {
fn heap_size_of_children(&self) -> usize {
self.receipts.heap_size_of_children()
}
}

View File

@@ -18,9 +18,6 @@
#![warn(missing_docs)]
extern crate parity_util_mem as mem;
extern crate parity_util_mem as malloc_size_of;
mod db;
pub mod keys;

View File

@@ -7,14 +7,15 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
bit-set = "0.4"
parity-bytes = "0.1"
ethereum-types = "0.6.0"
parity-util-mem = "0.1"
ethereum-types = "0.4"
heapsize = "0.4"
lazy_static = "1.0"
log = "0.4"
vm = { path = "../vm" }
keccak-hash = "0.2.0"
keccak-hash = "0.1"
parking_lot = "0.7"
memory-cache = { path = "../../util/memory-cache" }
num-bigint = "0.2"
[dev-dependencies]
rustc-hex = "1.0"

View File

@@ -21,7 +21,7 @@ extern crate criterion;
extern crate bit_set;
extern crate ethereum_types;
extern crate parking_lot;
extern crate parity_util_mem as mem;
extern crate heapsize;
extern crate vm;
extern crate evm;
extern crate keccak_hash as hash;

View File

@@ -15,7 +15,7 @@
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
use std::cmp;
use ethereum_types::{BigEndianHash, U256};
use ethereum_types::{U256, H256};
use super::u256_to_address;
use {evm, vm};
@@ -121,12 +121,12 @@ impl<Gas: evm::CostType> Gasometer<Gas> {
Request::Gas(Gas::from(1))
},
instructions::SSTORE => {
let address = BigEndianHash::from_uint(stack.peek(0));
let address = H256::from(stack.peek(0));
let newval = stack.peek(1);
let val = ext.storage_at(&address)?.into_uint();
let val = U256::from(&*ext.storage_at(&address)?);
let gas = if schedule.eip1283 {
let orig = ext.initial_storage_at(&address)?.into_uint();
let orig = U256::from(&*ext.initial_storage_at(&address)?);
calculate_eip1283_sstore_gas(schedule, &orig, &val, &newval)
} else {
if val.is_zero() && !newval.is_zero() {

View File

@@ -26,11 +26,10 @@ mod shared_cache;
use std::marker::PhantomData;
use std::{cmp, mem};
use std::sync::Arc;
use std::convert::TryFrom;
use hash::keccak;
use bytes::Bytes;
use ethereum_types::{U256, U512, H256, Address, BigEndianHash};
use ethereum_types::{U256, H256, Address};
use num_bigint::BigUint;
use vm::{
self, ActionParams, ParamsType, ActionValue, CallType, MessageCallResult,
@@ -63,6 +62,17 @@ const TWO_POW_96: U256 = U256([0, 0x100000000, 0, 0]); //0x1 00000000 00000000 0
const TWO_POW_224: U256 = U256([0, 0, 0, 0x100000000]); //0x1 00000000 00000000 00000000 00000000 00000000 00000000 00000000
const TWO_POW_248: U256 = U256([0, 0, 0, 0x100000000000000]); //0x1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 000000
fn to_biguint(x: U256) -> BigUint {
let mut bytes = [0u8; 32];
x.to_little_endian(&mut bytes);
BigUint::from_bytes_le(&bytes)
}
fn from_biguint(x: BigUint) -> U256 {
let bytes = x.to_bytes_le();
U256::from_little_endian(&bytes)
}
/// Abstraction over raw vector of Bytes. Easier state management of PC.
struct CodeReader {
position: ProgramCounter,
@@ -109,6 +119,8 @@ enum InstructionResult<Gas> {
Trap(TrapKind),
}
enum Never {}
/// ActionParams without code, so that it can be feed into CodeReader.
#[derive(Debug)]
struct InterpreterParams {
@@ -166,6 +178,12 @@ pub enum InterpreterResult {
Trap(TrapKind),
}
impl From<vm::Error> for InterpreterResult {
fn from(error: vm::Error) -> InterpreterResult {
InterpreterResult::Done(Err(error))
}
}
/// Intepreter EVM implementation
pub struct Interpreter<Cost: CostType> {
mem: Vec<u8>,
@@ -298,7 +316,7 @@ impl<Cost: CostType> Interpreter<Cost> {
} else if self.reader.len() == 0 {
InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.as_ref().expect("Gasometer None case is checked above; qed").current_gas.as_u256())))
} else {
self.step_inner(ext)
self.step_inner(ext).err().expect("step_inner never returns Ok(()); qed")
};
if let &InterpreterResult::Done(_) = &result {
@@ -310,7 +328,7 @@ impl<Cost: CostType> Interpreter<Cost> {
/// Inner helper function for step.
#[inline(always)]
fn step_inner(&mut self, ext: &mut dyn vm::Ext) -> InterpreterResult {
fn step_inner(&mut self, ext: &mut vm::Ext) -> Result<Never, InterpreterResult> {
let result = match self.resume_result.take() {
Some(result) => result,
None => {
@@ -325,28 +343,22 @@ impl<Cost: CostType> Interpreter<Cost> {
let instruction = match instruction {
Some(i) => i,
None => return InterpreterResult::Done(Err(vm::Error::BadInstruction {
None => return Err(InterpreterResult::Done(Err(vm::Error::BadInstruction {
instruction: opcode
})),
}))),
};
let info = instruction.info();
self.last_stack_ret_len = info.ret;
if let Err(e) = self.verify_instruction(ext, instruction, info) {
return InterpreterResult::Done(Err(e));
};
self.verify_instruction(ext, instruction, info)?;
// Calculate gas cost
let requirements = match self.gasometer.as_mut().expect(GASOMETER_PROOF).requirements(ext, instruction, info, &self.stack, self.mem.size()) {
Ok(t) => t,
Err(e) => return InterpreterResult::Done(Err(e)),
};
let requirements = self.gasometer.as_mut().expect(GASOMETER_PROOF).requirements(ext, instruction, info, &self.stack, self.mem.size())?;
if self.do_trace {
ext.trace_prepare_execute(self.reader.position - 1, opcode, requirements.gas_cost.as_u256(), Self::mem_written(instruction, &self.stack), Self::store_written(instruction, &self.stack));
}
if let Err(e) = self.gasometer.as_mut().expect(GASOMETER_PROOF).verify_gas(&requirements.gas_cost) {
return InterpreterResult::Done(Err(e));
}
self.gasometer.as_mut().expect(GASOMETER_PROOF).verify_gas(&requirements.gas_cost)?;
self.mem.expand(requirements.memory_required_size);
self.gasometer.as_mut().expect(GASOMETER_PROOF).current_mem_gas = requirements.memory_total_gas;
self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas = self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas - requirements.gas_cost;
@@ -355,19 +367,18 @@ impl<Cost: CostType> Interpreter<Cost> {
// Execute instruction
let current_gas = self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas;
let result = match self.exec_instruction(
let result = self.exec_instruction(
current_gas, ext, instruction, requirements.provide_gas
) {
Err(x) => return InterpreterResult::Done(Err(x)),
Ok(x) => x,
};
)?;
evm_debug!({ self.informant.after_instruction(instruction) });
result
},
};
if let InstructionResult::Trap(trap) = result {
return InterpreterResult::Trap(trap);
return Err(InterpreterResult::Trap(trap));
}
if let InstructionResult::UnusedGas(ref gas) = result {
@@ -389,31 +400,28 @@ impl<Cost: CostType> Interpreter<Cost> {
self.valid_jump_destinations = Some(self.cache.jump_destinations(&self.params.code_hash, &self.reader.code));
}
let jump_destinations = self.valid_jump_destinations.as_ref().expect("jump_destinations are initialized on first jump; qed");
let pos = match self.verify_jump(position, jump_destinations) {
Ok(x) => x,
Err(e) => return InterpreterResult::Done(Err(e))
};
let pos = self.verify_jump(position, jump_destinations)?;
self.reader.position = pos;
},
InstructionResult::StopExecutionNeedsReturn {gas, init_off, init_size, apply} => {
let mem = mem::replace(&mut self.mem, Vec::new());
return InterpreterResult::Done(Ok(GasLeft::NeedsReturn {
return Err(InterpreterResult::Done(Ok(GasLeft::NeedsReturn {
gas_left: gas.as_u256(),
data: mem.into_return_data(init_off, init_size),
apply_state: apply
}));
})));
},
InstructionResult::StopExecution => {
return InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas.as_u256())));
return Err(InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas.as_u256()))));
},
_ => {},
}
if self.reader.position >= self.reader.len() {
return InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas.as_u256())));
return Err(InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas.as_u256()))));
}
InterpreterResult::Continue
Err(InterpreterResult::Continue)
}
fn verify_instruction(&self, ext: &vm::Ext, instruction: Instruction, info: &InstructionInfo) -> vm::Result<()> {
@@ -512,7 +520,7 @@ impl<Cost: CostType> Interpreter<Cost> {
let init_size = self.stack.pop_back();
let address_scheme = match instruction {
instructions::CREATE => CreateContractAddress::FromSenderAndNonce,
instructions::CREATE2 => CreateContractAddress::FromSenderSaltAndCodeHash(BigEndianHash::from_uint(&self.stack.pop_back())),
instructions::CREATE2 => CreateContractAddress::FromSenderSaltAndCodeHash(self.stack.pop_back().into()),
_ => unreachable!("instruction can only be CREATE/CREATE2 checked above; qed"),
};
@@ -669,7 +677,7 @@ impl<Cost: CostType> Interpreter<Cost> {
let size = self.stack.pop_back();
let topics = self.stack.pop_n(no_of_topics)
.iter()
.map(BigEndianHash::from_uint)
.map(H256::from)
.collect();
ext.log(topics, self.mem.read_slice(offset, size))?;
},
@@ -706,21 +714,21 @@ impl<Cost: CostType> Interpreter<Cost> {
let offset = self.stack.pop_back();
let size = self.stack.pop_back();
let k = keccak(self.mem.read_slice(offset, size));
self.stack.push(k.into_uint());
self.stack.push(U256::from(&*k));
},
instructions::SLOAD => {
let key = BigEndianHash::from_uint(&self.stack.pop_back());
let word = ext.storage_at(&key)?.into_uint();
let key = H256::from(&self.stack.pop_back());
let word = U256::from(&*ext.storage_at(&key)?);
self.stack.push(word);
},
instructions::SSTORE => {
let address = BigEndianHash::from_uint(&self.stack.pop_back());
let address = H256::from(&self.stack.pop_back());
let val = self.stack.pop_back();
let current_val = ext.storage_at(&address)?.into_uint();
let current_val = U256::from(&*ext.storage_at(&address)?);
// Increase refund for clear
if ext.schedule().eip1283 {
let original_val = ext.initial_storage_at(&address)?.into_uint();
let original_val = U256::from(&*ext.initial_storage_at(&address)?);
gasometer::handle_eip1283_sstore_clears_refund(ext, &original_val, &current_val, &val);
} else {
if !current_val.is_zero() && val.is_zero() {
@@ -728,7 +736,7 @@ impl<Cost: CostType> Interpreter<Cost> {
ext.add_sstore_refund(sstore_clears_schedule);
}
}
ext.set_storage(address, BigEndianHash::from_uint(&val))?;
ext.set_storage(address, H256::from(&val))?;
},
instructions::PC => {
self.stack.push(U256::from(self.reader.position - 1));
@@ -789,7 +797,7 @@ impl<Cost: CostType> Interpreter<Cost> {
instructions::EXTCODEHASH => {
let address = u256_to_address(&self.stack.pop_back());
let hash = ext.extcodehash(&address)?.unwrap_or_else(H256::zero);
self.stack.push(hash.into_uint());
self.stack.push(U256::from(hash));
},
instructions::CALLDATACOPY => {
Self::copy_data_to_memory(&mut self.mem, &mut self.stack, &self.params.data.as_ref().map_or_else(|| &[] as &[u8], |d| &*d as &[u8]));
@@ -823,7 +831,7 @@ impl<Cost: CostType> Interpreter<Cost> {
instructions::BLOCKHASH => {
let block_number = self.stack.pop_back();
let block_hash = ext.blockhash(&block_number);
self.stack.push(block_hash.into_uint());
self.stack.push(U256::from(&*block_hash));
},
instructions::COINBASE => {
self.stack.push(address_to_u256(ext.env_info().author.clone()));
@@ -1013,12 +1021,12 @@ impl<Cost: CostType> Interpreter<Cost> {
let c = self.stack.pop_back();
self.stack.push(if !c.is_zero() {
let a_512 = U512::from(a);
let b_512 = U512::from(b);
let c_512 = U512::from(c);
let res = a_512 + b_512;
let x = res % c_512;
U256::try_from(x).expect("U512 % U256 fits U256; qed")
let a_num = to_biguint(a);
let b_num = to_biguint(b);
let c_num = to_biguint(c);
let res = a_num + b_num;
let x = res % c_num;
from_biguint(x)
} else {
U256::zero()
});
@@ -1029,12 +1037,12 @@ impl<Cost: CostType> Interpreter<Cost> {
let c = self.stack.pop_back();
self.stack.push(if !c.is_zero() {
let a_512 = U512::from(a);
let b_512 = U512::from(b);
let c_512 = U512::from(c);
let res = a_512 * b_512;
let x = res % c_512;
U256::try_from(x).expect("U512 % U256 fits U256; qed")
let a_num = to_biguint(a);
let b_num = to_biguint(b);
let c_num = to_biguint(c);
let res = a_num * b_num;
let x = res % c_num;
from_biguint(x)
} else {
U256::zero()
});
@@ -1174,13 +1182,12 @@ fn set_sign(value: U256, sign: bool) -> U256 {
#[inline]
fn u256_to_address(value: &U256) -> Address {
let addr: H256 = BigEndianHash::from_uint(value);
Address::from(addr)
Address::from(H256::from(value))
}
#[inline]
fn address_to_u256(value: Address) -> U256 {
H256::from(value).into_uint()
U256::from(&*H256::from(value))
}
#[cfg(test)]
@@ -1191,7 +1198,6 @@ mod tests {
use factory::Factory;
use vm::{self, Exec, ActionParams, ActionValue};
use vm::tests::{FakeExt, test_finalize};
use ethereum_types::Address;
fn interpreter(params: ActionParams, ext: &vm::Ext) -> Box<Exec> {
Factory::new(VMType::Interpreter, 1).create(params, ext.schedule(), ext.depth())
@@ -1202,13 +1208,13 @@ mod tests {
let code = "7feeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff006000527faaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa6020526000620f120660406000601773945304eb96065b2a98b57a48a06ae28d285a71b56101f4f1600055".from_hex().unwrap();
let mut params = ActionParams::default();
params.address = Address::from_low_u64_be(5);
params.address = 5.into();
params.gas = 300_000.into();
params.gas_price = 1.into();
params.value = ActionValue::Transfer(100_000.into());
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
ext.balances.insert(Address::from_low_u64_be(5), 1_000_000_000.into());
ext.balances.insert(5.into(), 1_000_000_000.into());
ext.tracing = true;
let gas_left = {
@@ -1225,12 +1231,12 @@ mod tests {
let code = "6001600160000360003e00".from_hex().unwrap();
let mut params = ActionParams::default();
params.address = Address::from_low_u64_be(5);
params.address = 5.into();
params.gas = 300_000.into();
params.gas_price = 1.into();
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new_byzantium();
ext.balances.insert(Address::from_low_u64_be(5), 1_000_000_000.into());
ext.balances.insert(5.into(), 1_000_000_000.into());
ext.tracing = true;
let err = {

View File

@@ -16,7 +16,7 @@
use std::sync::Arc;
use hash::KECCAK_EMPTY;
use parity_util_mem::{MallocSizeOf, MallocSizeOfOps};
use heapsize::HeapSizeOf;
use ethereum_types::H256;
use parking_lot::Mutex;
use memory_cache::MemoryLruCache;
@@ -25,12 +25,11 @@ use super::super::instructions::{self, Instruction};
const DEFAULT_CACHE_SIZE: usize = 4 * 1024 * 1024;
/// Stub for a sharing `BitSet` data in cache (reference counted)
/// and implementing MallocSizeOf on it.
// stub for a HeapSizeOf implementation.
struct Bits(Arc<BitSet>);
impl MallocSizeOf for Bits {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
impl HeapSizeOf for Bits {
fn heap_size_of_children(&self) -> usize {
// dealing in bits here
self.0.capacity() * 8
}

View File

@@ -19,11 +19,12 @@
extern crate bit_set;
extern crate ethereum_types;
extern crate parking_lot;
extern crate parity_util_mem;
extern crate heapsize;
extern crate vm;
extern crate keccak_hash as hash;
extern crate memory_cache;
extern crate parity_bytes as bytes;
extern crate num_bigint;
#[macro_use]
extern crate lazy_static;

View File

@@ -239,7 +239,7 @@ fn test_blockhash(factory: super::Factory) {
};
assert_eq!(gas_left, U256::from(79_974));
assert_eq!(ext.store.get(&H256::zero()).unwrap(), &blockhash);
assert_eq!(ext.store.get(&H256::new()).unwrap(), &blockhash);
}
evm_test!{test_calldataload: test_calldataload_int}
@@ -726,8 +726,8 @@ evm_test!{test_calls: test_calls_int}
fn test_calls(factory: super::Factory) {
let code = "600054602d57600160005560006000600060006050610998610100f160006000600060006050610998610100f25b".from_hex().unwrap();
let address = Address::from_low_u64_be(0x155);
let code_address = Address::from_low_u64_be(0x998);
let address = Address::from(0x155);
let code_address = Address::from(0x998);
let mut params = ActionParams::default();
params.gas = U256::from(150_000);
params.code = Some(Arc::new(code));
@@ -772,7 +772,7 @@ evm_test!{test_create_in_staticcall: test_create_in_staticcall_int}
fn test_create_in_staticcall(factory: super::Factory) {
let code = "600060006064f000".from_hex().unwrap();
let address = Address::from_low_u64_be(0x155);
let address = Address::from(0x155);
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(Arc::new(code));
@@ -1066,5 +1066,5 @@ fn assert_set_contains<T : Debug + Eq + PartialEq + Hash>(set: &HashSet<T>, val:
}
fn assert_store(ext: &FakeExt, pos: u64, val: &str) {
assert_eq!(ext.store.get(&H256::from_low_u64_be(pos)).unwrap(), &H256::from_str(val).unwrap());
assert_eq!(ext.store.get(&H256::from(pos)).unwrap(), &H256::from_str(val).unwrap());
}

View File

@@ -10,34 +10,32 @@ authors = ["Parity Technologies <admin@parity.io>"]
log = "0.4"
parity-bytes = "0.1"
common-types = { path = "../types" }
derive_more = "0.14.0"
ethcore = { path = ".."}
ethcore-db = { path = "../db" }
ethcore-blockchain = { path = "../blockchain" }
ethereum-types = "0.6.0"
memory-db = "0.12.4"
trie-db = "0.12.4"
ethereum-types = "0.4"
memory-db = "0.11.0"
trie-db = "0.11.0"
patricia-trie-ethereum = { path = "../../util/patricia-trie-ethereum" }
ethcore-network = { path = "../../util/network" }
ethcore-miner = { path = "../../miner" }
ethcore-io = { path = "../../util/io" }
hash-db = "0.12.4"
parity-util-mem = "0.1"
hash-db = "0.11.0"
heapsize = "0.4"
vm = { path = "../vm" }
fastmap = { path = "../../util/fastmap" }
failsafe = { version = "0.3.0", default-features = false, features = ["parking_lot_mutex"] }
rlp = "0.4.0"
rlp = { version = "0.3.0", features = ["ethereum"] }
rlp_derive = { path = "../../util/rlp-derive" }
smallvec = "0.6"
futures = "0.1"
rand = "0.6"
rand = "0.4"
itertools = "0.5"
bincode = "1.1"
bincode = "0.8.0"
serde = "1.0"
serde_derive = "1.0"
parking_lot = "0.7"
stats = { path = "../../util/stats" }
keccak-hash = "0.2.0"
keccak-hash = "0.1"
keccak-hasher = { path = "../../util/keccak-hasher" }
triehash-ethereum = { version = "0.2", path = "../../util/triehash-ethereum" }
kvdb = "0.1"

View File

@@ -21,12 +21,12 @@
//! vector of all gas prices from a recent range of blocks.
use std::time::{Instant, Duration};
use parity_util_mem::{MallocSizeOf, MallocSizeOfOps, MallocSizeOfExt};
use common_types::encoded;
use common_types::BlockNumber;
use common_types::receipt::Receipt;
use ethereum_types::{H256, U256};
use heapsize::HeapSizeOf;
use memory_cache::MemoryLruCache;
use stats::Corpus;
@@ -157,20 +157,18 @@ impl Cache {
/// Get the memory used.
pub fn mem_used(&self) -> usize {
self.malloc_size_of()
self.heap_size_of_children()
}
}
// This is fast method: it is possible to have a more exhaustive implementation
impl MallocSizeOf for Cache {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
impl HeapSizeOf for Cache {
fn heap_size_of_children(&self) -> usize {
self.headers.current_size()
+ self.canon_hashes.current_size()
+ self.bodies.current_size()
+ self.receipts.current_size()
+ self.chain_score.current_size()
// `self.corpus` is skipped
// TODO: + corpus
}
}

View File

@@ -95,8 +95,7 @@ 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<F>(cht_num: u64, mut fetcher: F)
-> Option<CHT<MemoryDB<KeccakHasher, memory_db::HashKey<KeccakHasher>, DBValue>>>
pub fn build<F>(cht_num: u64, mut fetcher: F) -> Option<CHT<MemoryDB<KeccakHasher, DBValue>>>
where F: FnMut(BlockId) -> Option<BlockInfo>
{
let mut db = new_memory_db();
@@ -105,7 +104,7 @@ pub fn build<F>(cht_num: u64, mut fetcher: F)
let last_num = start_number(cht_num + 1) - 1;
let mut id = BlockId::Number(last_num);
let mut root = H256::zero();
let mut root = H256::default();
{
let mut t = TrieDBMut::new(&mut db, &mut root);
@@ -155,7 +154,7 @@ pub fn compute_root<I>(cht_num: u64, iterable: I) -> Option<H256>
pub fn check_proof(proof: &[Bytes], num: u64, root: H256) -> Option<(H256, U256)> {
let mut db = new_memory_db();
for node in proof { db.insert(hash_db::EMPTY_PREFIX, &node[..]); }
for node in proof { db.insert(&node[..]); }
let res = match TrieDB::new(&db, &root) {
Err(_) => return None,
Ok(trie) => trie.get_with(&key!(num), |val: &[u8]| {

View File

@@ -21,7 +21,8 @@ use std::sync::Arc;
use common_types::encoded;
use common_types::header::Header;
use common_types::receipt::Receipt;
use ethcore::engines::{Engine, StateDependentProof};
use ethcore::engines::{EthEngine, StateDependentProof};
use ethcore::machine::EthereumMachine;
use ethereum_types::H256;
use futures::future::IntoFuture;
@@ -47,8 +48,8 @@ pub trait ChainDataFetcher: Send + Sync + 'static {
fn epoch_transition(
&self,
_hash: H256,
_engine: Arc<Engine>,
_checker: Arc<StateDependentProof>
_engine: Arc<EthEngine>,
_checker: Arc<StateDependentProof<EthereumMachine>>
) -> Self::Transition;
}
@@ -76,8 +77,8 @@ impl ChainDataFetcher for Unavailable {
fn epoch_transition(
&self,
_hash: H256,
_engine: Arc<Engine>,
_checker: Arc<StateDependentProof>
_engine: Arc<EthEngine>,
_checker: Arc<StateDependentProof<EthereumMachine>>
) -> Self::Transition {
Err("fetching epoch transition proofs unavailable")
}

View File

@@ -35,10 +35,10 @@ use common_types::encoded;
use common_types::header::Header;
use common_types::ids::BlockId;
use ethcore::engines::epoch::{Transition as EpochTransition, PendingTransition as PendingEpochTransition};
use ethcore::error::{Error, EthcoreResult, BlockError};
use ethcore::error::{Error, EthcoreResult, ErrorKind as EthcoreErrorKind, BlockError};
use ethcore::spec::{Spec, SpecHardcodedSync};
use ethereum_types::{H256, H264, U256};
use parity_util_mem::{MallocSizeOf, MallocSizeOfOps};
use heapsize::HeapSizeOf;
use kvdb::{DBTransaction, KeyValueDB};
use parking_lot::{Mutex, RwLock};
use fastmap::H256FastMap;
@@ -95,8 +95,8 @@ struct Entry {
canonical_hash: H256,
}
impl MallocSizeOf for Entry {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
impl HeapSizeOf for Entry {
fn heap_size_of_children(&self) -> usize {
if self.candidates.spilled() {
self.candidates.capacity() * ::std::mem::size_of::<Candidate>()
} else {
@@ -154,11 +154,8 @@ fn pending_transition_key(block_hash: H256) -> H264 {
let mut key = H264::default();
{
let bytes = key.as_bytes_mut();
bytes[0] = LEADING;
bytes[1..].copy_from_slice(block_hash.as_bytes());
}
key[0] = LEADING;
key.0[1..].copy_from_slice(&block_hash.0[..]);
key
}
@@ -168,11 +165,8 @@ fn transition_key(block_hash: H256) -> H264 {
let mut key = H264::default();
{
let bytes = key.as_bytes_mut();
bytes[0] = LEADING;
bytes[1..].copy_from_slice(block_hash.as_bytes());
}
key[0] = LEADING;
key.0[1..].copy_from_slice(&block_hash.0[..]);
key
}
@@ -202,21 +196,14 @@ pub enum HardcodedSync {
Deny,
}
#[derive(MallocSizeOf)]
/// Header chain. See module docs for more details.
pub struct HeaderChain {
#[ignore_malloc_size_of = "ignored for performance reason"]
genesis_header: encoded::Header, // special-case the genesis.
candidates: RwLock<BTreeMap<u64, Entry>>,
#[ignore_malloc_size_of = "ignored for performance reason"]
best_block: RwLock<BlockDescriptor>,
#[ignore_malloc_size_of = "ignored for performance reason"]
live_epoch_proofs: RwLock<H256FastMap<EpochTransition>>,
#[ignore_malloc_size_of = "ignored for performance reason"]
db: Arc<KeyValueDB>,
#[ignore_malloc_size_of = "ignored for performance reason"]
col: Option<u32>,
#[ignore_malloc_size_of = "ignored for performance reason"]
cache: Arc<Mutex<Cache>>,
}
@@ -250,7 +237,7 @@ impl HeaderChain {
for c in &entry.candidates {
let key = transition_key(c.hash);
if let Some(proof) = db.get(col, key.as_bytes())? {
if let Some(proof) = db.get(col, &*key)? {
live_epoch_proofs.insert(c.hash, EpochTransition {
block_hash: c.hash,
block_number: cur_number,
@@ -267,7 +254,7 @@ impl HeaderChain {
let best_block = {
let era = match candidates.get(&curr.best_num) {
Some(era) => era,
None => return Err("Database corrupt: highest block referenced but no data.".into()),
None => bail!("Database corrupt: highest block referenced but no data."),
};
let best = &era.candidates[0];
@@ -416,7 +403,7 @@ impl HeaderChain {
.and_then(|entry| entry.candidates.iter().find(|c| c.hash == parent_hash))
.map(|c| c.total_difficulty)
.ok_or_else(|| BlockError::UnknownParent(parent_hash))
.map_err(Error::Block)?
.map_err(EthcoreErrorKind::Block)?
};
parent_td + *header.difficulty()
@@ -444,7 +431,7 @@ impl HeaderChain {
}
if let Some(transition) = transition {
transaction.put(self.col, transition_key(hash).as_bytes(), &transition.proof);
transaction.put(self.col, &*transition_key(hash), &transition.proof);
self.live_epoch_proofs.write().insert(hash, transition);
}
@@ -521,10 +508,10 @@ impl HeaderChain {
for ancient in &era_entry.candidates {
let maybe_transition = live_epoch_proofs.remove(&ancient.hash);
if let Some(epoch_transition) = maybe_transition {
transaction.delete(self.col, transition_key(ancient.hash).as_bytes());
transaction.delete(self.col, &*transition_key(ancient.hash));
if ancient.hash == era_entry.canonical_hash {
last_canonical_transition = match self.db.get(self.col, ancient.hash.as_bytes()) {
last_canonical_transition = match self.db.get(self.col, &ancient.hash) {
Err(e) => {
warn!(target: "chain", "Error reading from DB: {}\n
", e);
@@ -539,7 +526,7 @@ impl HeaderChain {
}
}
transaction.delete(self.col, ancient.hash.as_bytes());
transaction.delete(self.col, &ancient.hash);
}
let canon = &era_entry.candidates[0];
@@ -589,7 +576,7 @@ impl HeaderChain {
} else {
let msg = format!("header of block #{} not found in DB ; database in an \
inconsistent state", h_num);
return Err(msg.into());
bail!(msg);
};
let decoded = header.decode().expect("decoding db value failed");
@@ -660,7 +647,7 @@ impl HeaderChain {
match cache.block_header(&hash) {
Some(header) => Some(header),
None => {
match self.db.get(self.col, hash.as_bytes()) {
match self.db.get(self.col, &hash) {
Ok(db_value) => {
db_value.map(|x| x.into_vec()).map(encoded::Header::new)
.and_then(|header| {
@@ -785,7 +772,7 @@ impl HeaderChain {
/// Get block status.
pub fn status(&self, hash: &H256) -> BlockStatus {
if self.db.get(self.col, hash.as_bytes()).ok().map_or(false, |x| x.is_some()) {
if self.db.get(self.col, hash).ok().map_or(false, |x| x.is_some()) {
BlockStatus::InChain
} else {
BlockStatus::Unknown
@@ -795,13 +782,13 @@ impl HeaderChain {
/// Insert a pending transition.
pub fn insert_pending_transition(&self, batch: &mut DBTransaction, hash: H256, t: &PendingEpochTransition) {
let key = pending_transition_key(hash);
batch.put(self.col, key.as_bytes(), &*::rlp::encode(t));
batch.put(self.col, &*key, &*::rlp::encode(t));
}
/// Get pending transition for a specific block hash.
pub fn pending_transition(&self, hash: H256) -> Option<PendingEpochTransition> {
let key = pending_transition_key(hash);
match self.db.get(self.col, key.as_bytes()) {
match self.db.get(self.col, &*key) {
Ok(db_fetch) => db_fetch.map(|bytes| ::rlp::decode(&bytes).expect("decoding value from db failed")),
Err(e) => {
warn!(target: "chain", "Error reading from database: {}", e);
@@ -845,6 +832,12 @@ impl HeaderChain {
}
}
impl HeapSizeOf for HeaderChain {
fn heap_size_of_children(&self) -> usize {
self.candidates.read().heap_size_of_children()
}
}
/// Iterator over a block's ancestry.
pub struct AncestryIter<'a> {
next: Option<encoded::Header>,

View File

@@ -19,7 +19,8 @@
use std::sync::{Weak, Arc};
use ethcore::client::{ClientReport, EnvInfo, ClientIoMessage};
use ethcore::engines::{epoch, Engine, EpochChange, EpochTransition, Proof};
use ethcore::engines::{epoch, EthEngine, EpochChange, EpochTransition, Proof};
use ethcore::machine::EthereumMachine;
use ethcore::error::{Error, EthcoreResult};
use ethcore::verification::queue::{self, HeaderQueue};
use ethcore::spec::{Spec, SpecHardcodedSync};
@@ -33,7 +34,6 @@ use common_types::blockchain_info::BlockChainInfo;
use common_types::encoded;
use common_types::header::Header;
use common_types::ids::BlockId;
use common_types::verification_queue_info::VerificationQueueInfo as BlockQueueInfo;
use kvdb::KeyValueDB;
@@ -91,9 +91,6 @@ pub trait LightChainClient: Send + Sync {
/// Attempt to get a block hash by block id.
fn block_hash(&self, id: BlockId) -> Option<H256>;
/// Get block queue information.
fn queue_info(&self) -> BlockQueueInfo;
/// Attempt to get block header by block id.
fn block_header(&self, id: BlockId) -> Option<encoded::Header>;
@@ -114,7 +111,7 @@ pub trait LightChainClient: Send + Sync {
fn env_info(&self, id: BlockId) -> Option<EnvInfo>;
/// Get a handle to the consensus engine.
fn engine(&self) -> &Arc<Engine>;
fn engine(&self) -> &Arc<EthEngine>;
/// Query whether a block is known.
fn is_known(&self, hash: &H256) -> bool;
@@ -128,6 +125,9 @@ pub trait LightChainClient: Send + Sync {
/// Flush the queue.
fn flush_queue(&self);
/// Get queue info.
fn queue_info(&self) -> queue::QueueInfo;
/// Get the `i`th CHT root.
fn cht_root(&self, i: usize) -> Option<H256>;
@@ -159,7 +159,7 @@ impl<T: LightChainClient> AsLightClient for T {
/// Light client implementation.
pub struct Client<T> {
queue: HeaderQueue,
engine: Arc<Engine>,
engine: Arc<EthEngine>,
chain: HeaderChain,
report: RwLock<ClientReport>,
import_lock: Mutex<()>,
@@ -361,9 +361,9 @@ impl<T: ChainDataFetcher> Client<T> {
/// Get blockchain mem usage in bytes.
pub fn chain_mem_used(&self) -> usize {
use parity_util_mem::MallocSizeOfExt;
use heapsize::HeapSizeOf;
self.chain.malloc_size_of()
self.chain.heap_size_of_children()
}
/// Set a closure to call when the client wants to be restarted.
@@ -375,7 +375,7 @@ impl<T: ChainDataFetcher> Client<T> {
}
/// Get a handle to the verification engine.
pub fn engine(&self) -> &Arc<Engine> {
pub fn engine(&self) -> &Arc<EthEngine> {
&self.engine
}
@@ -467,7 +467,7 @@ impl<T: ChainDataFetcher> Client<T> {
true
}
fn check_epoch_signal(&self, verified_header: &Header) -> Result<Option<Proof>, T::Error> {
fn check_epoch_signal(&self, verified_header: &Header) -> Result<Option<Proof<EthereumMachine>>, T::Error> {
use ethcore::machine::{AuxiliaryRequest, AuxiliaryData};
let mut block: Option<Vec<u8>> = None;
@@ -513,7 +513,7 @@ impl<T: ChainDataFetcher> Client<T> {
}
// attempts to fetch the epoch proof from the network until successful.
fn write_pending_proof(&self, header: &Header, proof: Proof) -> Result<(), T::Error> {
fn write_pending_proof(&self, header: &Header, proof: Proof<EthereumMachine>) -> Result<(), T::Error> {
let proof = match proof {
Proof::Known(known) => known,
Proof::WithState(state_dependent) => {
@@ -534,7 +534,6 @@ impl<T: ChainDataFetcher> Client<T> {
}
}
impl<T: ChainDataFetcher> LightChainClient for Client<T> {
fn add_listener(&self, listener: Weak<LightChainNotify>) {
Client::add_listener(self, listener)
@@ -542,10 +541,6 @@ impl<T: ChainDataFetcher> LightChainClient for Client<T> {
fn chain_info(&self) -> BlockChainInfo { Client::chain_info(self) }
fn queue_info(&self) -> queue::QueueInfo {
self.queue.queue_info()
}
fn queue_header(&self, header: Header) -> EthcoreResult<H256> {
self.import_header(header)
}
@@ -578,7 +573,7 @@ impl<T: ChainDataFetcher> LightChainClient for Client<T> {
Client::env_info(self, id)
}
fn engine(&self) -> &Arc<Engine> {
fn engine(&self) -> &Arc<EthEngine> {
Client::engine(self)
}
@@ -605,6 +600,10 @@ impl<T: ChainDataFetcher> LightChainClient for Client<T> {
Client::flush_queue(self);
}
fn queue_info(&self) -> queue::QueueInfo {
self.queue.queue_info()
}
fn cht_root(&self, i: usize) -> Option<H256> {
Client::cht_root(self, i)
}

View File

@@ -75,8 +75,9 @@ impl<T: ChainDataFetcher> Service<T> {
io_service.channel(),
cache,
)?);
spec.engine.register_client(Arc::downgrade(&client) as _);
io_service.register_handler(Arc::new(ImportBlocks(client.clone()))).map_err(Error::Io)?;
spec.engine.register_client(Arc::downgrade(&client) as _);
Ok(Service {
client,

View File

@@ -61,12 +61,9 @@ extern crate ethcore_io as io;
extern crate ethcore_network as network;
extern crate parity_bytes as bytes;
extern crate ethereum_types;
extern crate ethcore_miner as miner;
extern crate ethcore;
extern crate hash_db;
extern crate parity_util_mem;
extern crate parity_util_mem as mem;
extern crate parity_util_mem as malloc_size_of;
extern crate heapsize;
extern crate failsafe;
extern crate futures;
extern crate itertools;
@@ -88,7 +85,8 @@ extern crate keccak_hash as hash;
extern crate triehash_ethereum as triehash;
extern crate kvdb;
extern crate memory_cache;
extern crate derive_more;
#[macro_use]
extern crate error_chain;
#[cfg(test)]
extern crate kvdb_memorydb;

View File

@@ -199,15 +199,15 @@ pub struct FileStore(pub PathBuf);
impl SampleStore for FileStore {
fn load(&self) -> HashMap<Kind, VecDeque<u64>> {
File::open(&self.0)
.map_err(|e| Box::new(bincode::ErrorKind::Io(e)))
.and_then(|mut file| bincode::deserialize_from(&mut file))
.map_err(|e| Box::new(bincode::ErrorKind::IoError(e)))
.and_then(|mut file| bincode::deserialize_from(&mut file, bincode::Infinite))
.unwrap_or_else(|_| HashMap::new())
}
fn store(&self, samples: &HashMap<Kind, VecDeque<u64>>) {
let res = File::create(&self.0)
.map_err(|e| Box::new(bincode::ErrorKind::Io(e)))
.and_then(|mut file| bincode::serialize_into(&mut file, samples));
.map_err(|e| Box::new(bincode::ErrorKind::IoError(e)))
.and_then(|mut file| bincode::serialize_into(&mut file, samples, bincode::Infinite));
if let Err(e) = res {
warn!(target: "pip", "Error writing light request timing samples to file: {}", e);

View File

@@ -382,7 +382,7 @@ mod tests {
protocol_version: 1,
network_id: 1,
head_td: U256::default(),
head_hash: H256::zero(),
head_hash: H256::default(),
head_num: 10,
genesis_hash: H256::zero(),
last_head: None,
@@ -417,7 +417,7 @@ mod tests {
protocol_version: 1,
network_id: 1,
head_td: U256::default(),
head_hash: H256::zero(),
head_hash: H256::default(),
head_num: 10,
genesis_hash: H256::zero(),
last_head: None,
@@ -452,7 +452,7 @@ mod tests {
protocol_version: 1,
network_id: 1,
head_td: U256::default(),
head_hash: H256::zero(),
head_hash: H256::default(),
head_num: 10,
genesis_hash: H256::zero(),
last_head: None,
@@ -550,7 +550,7 @@ mod tests {
protocol_version: 1,
network_id: 1,
head_td: U256::default(),
head_hash: H256::zero(),
head_hash: H256::default(),
head_num: 10,
genesis_hash: H256::zero(),
last_head: None,

View File

@@ -22,7 +22,7 @@ use common_types::encoded;
use common_types::ids::BlockId;
use common_types::transaction::{Action, PendingTransaction};
use ethcore::client::{EachBlockWith, TestBlockChainClient};
use ethereum_types::{H256, U256, Address, BigEndianHash};
use ethereum_types::{H256, U256, Address};
use net::context::IoContext;
use net::load_timer::MOVING_SAMPLE_SIZE;
use net::status::{Capabilities, Status};
@@ -158,7 +158,7 @@ impl Provider for TestProvider {
fn contract_code(&self, req: request::CompleteCodeRequest) -> Option<request::CodeResponse> {
Some(CodeResponse {
code: req.block_hash.as_bytes().iter().chain(req.code_hash.as_bytes().iter()).cloned().collect(),
code: req.block_hash.iter().chain(req.code_hash.iter()).cloned().collect(),
})
}
@@ -261,7 +261,7 @@ fn genesis_mismatch() {
let (provider, proto) = setup(capabilities);
let mut status = status(provider.client.chain_info());
status.genesis_hash = H256::zero();
status.genesis_hash = H256::default();
let packet_body = write_handshake(&status, &capabilities, &proto);
@@ -472,16 +472,16 @@ fn get_state_proofs() {
}
let req_id = 112;
let key1: H256 = BigEndianHash::from_uint(&U256::from(11223344));
let key2: H256 = BigEndianHash::from_uint(&U256::from(99988887));
let key1: H256 = U256::from(11223344).into();
let key2: H256 = U256::from(99988887).into();
let mut builder = Builder::default();
builder.push(Request::Account(IncompleteAccountRequest {
block_hash: H256::zero().into(),
block_hash: H256::default().into(),
address_hash: key1.into(),
})).unwrap();
builder.push(Request::Storage(IncompleteStorageRequest {
block_hash: H256::zero().into(),
block_hash: H256::default().into(),
address_hash: key1.into(),
key_hash: key2.into(),
})).unwrap();
@@ -492,11 +492,11 @@ fn get_state_proofs() {
let response = {
let responses = vec![
Response::Account(provider.account_proof(CompleteAccountRequest {
block_hash: H256::zero(),
block_hash: H256::default(),
address_hash: key1,
}).unwrap()),
Response::Storage(provider.storage_proof(CompleteStorageRequest {
block_hash: H256::zero(),
block_hash: H256::default(),
address_hash: key1,
key_hash: key2,
}).unwrap()),
@@ -529,8 +529,8 @@ fn get_contract_code() {
}
let req_id = 112;
let key1: H256 = BigEndianHash::from_uint(&U256::from(11223344));
let key2: H256 = BigEndianHash::from_uint(&U256::from(99988887));
let key1: H256 = U256::from(11223344).into();
let key2: H256 = U256::from(99988887).into();
let request = Request::Code(IncompleteCodeRequest {
block_hash: key1.into(),
@@ -541,7 +541,7 @@ fn get_contract_code() {
let request_body = make_packet(req_id, &requests);
let response = {
let response = vec![Response::Code(CodeResponse {
code: key1.as_bytes().iter().chain(key2.as_bytes().iter()).cloned().collect(),
code: key1.iter().chain(key2.iter()).cloned().collect(),
})];
let new_creds = *flow_params.limit() - flow_params.compute_cost_multi(requests.requests()).unwrap();
@@ -616,9 +616,9 @@ fn proof_of_execution() {
let req_id = 112;
let mut request = Request::Execution(request::IncompleteExecutionRequest {
block_hash: H256::zero().into(),
from: Address::zero(),
action: Action::Call(Address::zero()),
block_hash: H256::default().into(),
from: Address::default(),
action: Action::Call(Address::default()),
gas: 100.into(),
gas_price: 0.into(),
value: 0.into(),
@@ -755,7 +755,7 @@ fn get_transaction_index() {
}
let req_id = 112;
let key1: H256 = BigEndianHash::from_uint(&U256::from(11223344));
let key1: H256 = U256::from(11223344).into();
let request = Request::TransactionIndex(IncompleteTransactionIndexRequest {
hash: key1.into(),

View File

@@ -66,31 +66,32 @@ pub const DEFAULT_NUM_CONSECUTIVE_FAILED_REQUESTS: usize = 1;
/// OnDemand related errors
pub mod error {
// Silence: `use of deprecated item 'std::error::Error::cause': replaced by Error::source, which can support downcasting`
// https://github.com/paritytech/parity-ethereum/issues/10302
#![allow(deprecated)]
use futures::sync::oneshot::Canceled;
/// OnDemand Error
#[derive(Debug, derive_more::Display, derive_more::From)]
pub enum Error {
/// Canceled oneshot channel
ChannelCanceled(Canceled),
/// Timeout bad response
BadResponse(String),
/// OnDemand requests limit exceeded
#[display(fmt = "OnDemand request maximum backoff iterations exceeded")]
RequestLimit,
}
error_chain! {
impl std::error::Error for Error {
fn source(&self) -> Option<&(std::error::Error + 'static)> {
match self {
Error::ChannelCanceled(err) => Some(err),
_ => None,
foreign_links {
ChannelCanceled(Canceled) #[doc = "Canceled oneshot channel"];
}
errors {
#[doc = "Timeout bad response"]
BadResponse(err: String) {
description("Max response evaluation time exceeded")
display("{}", err)
}
#[doc = "OnDemand requests limit exceeded"]
RequestLimit {
description("OnDemand request maximum backoff iterations exceeded")
display("OnDemand request maximum backoff iterations exceeded")
}
}
}
/// OnDemand Result
pub type Result<T> = std::result::Result<T, Error>;
}
/// Public interface for performing network requests `OnDemand`
@@ -271,7 +272,7 @@ impl Pending {
response_err
);
let err = self::error::Error::BadResponse(err);
let err = self::error::ErrorKind::BadResponse(err);
if self.sender.send(Err(err.into())).is_err() {
debug!(target: "on_demand", "Dropped oneshot channel receiver on no response");
}
@@ -279,7 +280,7 @@ impl Pending {
// returning a peer discovery timeout during query attempts
fn request_limit_reached(self) {
let err = self::error::Error::RequestLimit;
let err = self::error::ErrorKind::RequestLimit;
if self.sender.send(Err(err.into())).is_err() {
debug!(target: "on_demand", "Dropped oneshot channel receiver on time out");
}

View File

@@ -24,7 +24,8 @@ use common_types::basic_account::BasicAccount;
use common_types::encoded;
use common_types::receipt::Receipt;
use common_types::transaction::SignedTransaction;
use ethcore::engines::{Engine, StateDependentProof};
use ethcore::engines::{EthEngine, StateDependentProof};
use ethcore::machine::EthereumMachine;
use ethcore::state::{self, ProvedExecution};
use ethereum_types::{H256, U256, Address};
use ethtrie::{TrieError, TrieDB};
@@ -980,9 +981,9 @@ impl Account {
let state_root = header.state_root();
let mut db = journaldb::new_memory_db();
for node in proof { db.insert(hash_db::EMPTY_PREFIX, &node[..]); }
for node in proof { db.insert(&node[..]); }
match TrieDB::new(&db, &state_root).and_then(|t| t.get(keccak(&self.address).as_bytes()))? {
match TrieDB::new(&db, &state_root).and_then(|t| t.get(&keccak(&self.address)))? {
Some(val) => {
let rlp = Rlp::new(&val);
Ok(Some(BasicAccount {
@@ -1037,7 +1038,7 @@ pub struct TransactionProof {
// TODO: it's not really possible to provide this if the header is unknown.
pub env_info: EnvInfo,
/// Consensus engine.
pub engine: Arc<Engine>,
pub engine: Arc<EthEngine>,
}
impl TransactionProof {
@@ -1080,9 +1081,9 @@ pub struct Signal {
/// Block hash and number to fetch proof for.
pub hash: H256,
/// Consensus engine, used to check the proof.
pub engine: Arc<Engine>,
pub engine: Arc<EthEngine>,
/// Special checker for the proof.
pub proof_check: Arc<StateDependentProof>,
pub proof_check: Arc<StateDependentProof<EthereumMachine>>,
}
impl Signal {
@@ -1161,7 +1162,7 @@ mod tests {
#[test]
fn check_header_with_ancestors() {
let mut last_header_hash = H256::zero();
let mut last_header_hash = H256::default();
let mut headers = (0..11).map(|num| {
let mut header = Header::new();
header.set_number(num);
@@ -1277,7 +1278,7 @@ mod tests {
fn check_state_proof() {
use rlp::RlpStream;
let mut root = H256::zero();
let mut root = H256::default();
let mut db = journaldb::new_memory_db();
let mut header = Header::new();
header.set_number(123_456);
@@ -1297,17 +1298,17 @@ mod tests {
let mut trie = SecTrieDBMut::new(&mut db, &mut root);
for _ in 0..100 {
let address = Address::random();
trie.insert(address.as_bytes(), &rand_acc()).unwrap();
trie.insert(&*address, &rand_acc()).unwrap();
}
trie.insert(addr.as_bytes(), &rand_acc()).unwrap();
trie.insert(&*addr, &rand_acc()).unwrap();
}
let proof = {
let trie = SecTrieDB::new(&db, &root).unwrap();
let mut recorder = Recorder::new();
trie.get_with(addr.as_bytes(), &mut recorder).unwrap().unwrap();
trie.get_with(&*addr, &mut recorder).unwrap().unwrap();
recorder.drain().into_iter().map(|r| r.data).collect::<Vec<_>>()
};

View File

@@ -117,9 +117,9 @@ fn dummy_status() -> Status {
protocol_version: 1,
network_id: 999,
head_td: 1.into(),
head_hash: H256::zero(),
head_hash: H256::default(),
head_num: 1359,
genesis_hash: H256::zero(),
genesis_hash: H256::default(),
last_head: None,
}
}
@@ -138,7 +138,7 @@ fn detects_hangup() {
let on_demand = Harness::create().service;
let result = on_demand.request_raw(
&Context::NoOp,
vec![request::HeaderByHash(H256::zero().into()).into()],
vec![request::HeaderByHash(H256::default().into()).into()],
);
assert_eq!(on_demand.pending.read().len(), 1);
@@ -199,7 +199,7 @@ fn no_capabilities() {
let _recv = harness.service.request_raw(
&Context::NoOp,
vec![request::HeaderByHash(H256::zero().into()).into()]
vec![request::HeaderByHash(H256::default().into()).into()]
).unwrap();
assert_eq!(harness.service.pending.read().len(), 1);
@@ -395,7 +395,7 @@ fn wrong_kind() {
let _recv = harness.service.request_raw(
&Context::NoOp,
vec![request::HeaderByHash(H256::zero().into()).into()]
vec![request::HeaderByHash(H256::default().into()).into()]
).unwrap();
assert_eq!(harness.service.pending.read().len(), 1);

View File

@@ -24,15 +24,12 @@
//! address-wise manner.
use std::fmt;
use std::sync::Arc;
use std::collections::{BTreeMap, HashMap};
use std::collections::hash_map::Entry;
use common_types::transaction::{self, Condition, PendingTransaction, SignedTransaction};
use ethereum_types::{H256, U256, Address};
use fastmap::H256FastMap;
use futures::sync::mpsc;
use miner::pool::TxStatus;
// Knowledge of an account's current nonce.
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -129,13 +126,14 @@ pub enum ImportDestination {
Future,
}
type Listener = Box<Fn(&[H256]) + Send + Sync>;
/// Light transaction queue. See module docs for more details.
#[derive(Default)]
pub struct TransactionQueue {
by_account: HashMap<Address, AccountTransactions>,
by_hash: H256FastMap<PendingTransaction>,
pending_listeners: Vec<mpsc::UnboundedSender<Arc<Vec<H256>>>>,
full_listeners: Vec<mpsc::UnboundedSender<Arc<Vec<(H256, TxStatus)>>>>,
listeners: Vec<Listener>,
}
impl fmt::Debug for TransactionQueue {
@@ -143,8 +141,7 @@ impl fmt::Debug for TransactionQueue {
fmt.debug_struct("TransactionQueue")
.field("by_account", &self.by_account)
.field("by_hash", &self.by_hash)
.field("pending_listeners", &self.pending_listeners.len())
.field("full_listeners", &self.pending_listeners.len())
.field("listeners", &self.listeners.len())
.finish()
}
}
@@ -234,7 +231,7 @@ impl TransactionQueue {
};
self.by_hash.insert(hash, tx);
self.notify(&promoted, TxStatus::Added);
self.notify(&promoted);
Ok(res)
}
@@ -346,8 +343,6 @@ impl TransactionQueue {
trace!(target: "txqueue", "Culled {} old transactions from sender {} (nonce={})",
removed_hashes.len(), address, cur_nonce);
self.notify(&removed_hashes, TxStatus::Culled);
for hash in removed_hashes {
self.by_hash.remove(&hash);
}
@@ -359,40 +354,15 @@ impl TransactionQueue {
}
/// Add a transaction queue listener.
pub fn pending_transactions_receiver(&mut self) -> mpsc::UnboundedReceiver<Arc<Vec<H256>>> {
let (sender, receiver) = mpsc::unbounded();
self.pending_listeners.push(sender);
receiver
}
/// Add a transaction queue listener.
pub fn full_transactions_receiver(&mut self) -> mpsc::UnboundedReceiver<Arc<Vec<(H256, TxStatus)>>> {
let (sender, receiver) = mpsc::unbounded();
self.full_listeners.push(sender);
receiver
pub fn add_listener(&mut self, f: Listener) {
self.listeners.push(f);
}
/// Notifies all listeners about new pending transaction.
fn notify(&mut self, hashes: &[H256], status: TxStatus) {
if status == TxStatus::Added {
let to_pending_send: Arc<Vec<H256>> = Arc::new(
hashes
.into_iter()
.map(|hash| hash.clone())
.collect()
);
self.pending_listeners.retain(|listener| listener.unbounded_send(to_pending_send.clone()).is_ok());
fn notify(&self, hashes: &[H256]) {
for listener in &self.listeners {
listener(hashes)
}
let to_full_send: Arc<Vec<(H256, TxStatus)>> = Arc::new(
hashes
.into_iter()
.map(|hash| (hash.clone(), status))
.collect()
);
self.full_listeners.retain(|listener| listener.unbounded_send(to_full_send.clone()).is_ok());
}
}
@@ -404,7 +374,7 @@ mod tests {
#[test]
fn queued_senders() {
let sender = Address::zero();
let sender = Address::default();
let mut txq = TransactionQueue::default();
let tx = Transaction::default().fake_sign(sender);
@@ -420,7 +390,7 @@ mod tests {
#[test]
fn next_nonce() {
let sender = Address::zero();
let sender = Address::default();
let mut txq = TransactionQueue::default();
for i in (0..5).chain(10..15) {
@@ -451,7 +421,7 @@ mod tests {
#[test]
fn current_to_future() {
let sender = Address::zero();
let sender = Address::default();
let mut txq = TransactionQueue::default();
for i in 5..10 {
@@ -494,7 +464,7 @@ mod tests {
#[test]
fn conditional() {
let mut txq = TransactionQueue::default();
let sender = Address::zero();
let sender = Address::default();
for i in 0..5 {
let mut tx = Transaction::default();
@@ -516,7 +486,7 @@ mod tests {
#[test]
fn cull_from_future() {
let sender = Address::zero();
let sender = Address::default();
let mut txq = TransactionQueue::default();
for i in (0..1).chain(3..10) {
@@ -536,7 +506,7 @@ mod tests {
#[test]
fn import_old() {
let sender = Address::zero();
let sender = Address::default();
let mut txq = TransactionQueue::default();
let mut tx_a = Transaction::default();
@@ -553,7 +523,7 @@ mod tests {
#[test]
fn replace_is_removed() {
let sender = Address::zero();
let sender = Address::default();
let mut txq = TransactionQueue::default();
let tx_b: PendingTransaction = Transaction::default().fake_sign(sender).into();
@@ -573,7 +543,7 @@ mod tests {
#[test]
fn future_transactions() {
let sender = Address::zero();
let sender = Address::default();
let mut txq = TransactionQueue::default();
for i in (0..1).chain(3..10) {

View File

@@ -220,7 +220,7 @@ mod tests {
num: 100.into(),
})).unwrap();
builder.push(Request::Receipts(IncompleteReceiptsRequest {
hash: H256::zero().into(),
hash: H256::default().into(),
})).unwrap();
}
@@ -267,7 +267,7 @@ mod tests {
})).unwrap();
let mut batch = builder.build();
batch.requests[1].fill(|_req_idx, _out_idx| Ok(Output::Hash(H256::from_low_u64_be(42))));
batch.requests[1].fill(|_req_idx, _out_idx| Ok(Output::Hash(42.into())));
assert!(batch.next_complete().is_some());
batch.answered += 1;
@@ -289,7 +289,7 @@ mod tests {
assert!(batch.next_complete().is_some());
let hdr_proof_res = header_proof::Response {
proof: vec![],
hash: H256::from_low_u64_be(12),
hash: 12.into(),
td: 21.into(),
};
batch.supply_response_unchecked(&hdr_proof_res);
@@ -308,7 +308,7 @@ mod tests {
})).unwrap();
let mut batch = builder.build();
batch.requests[1].fill(|_req_idx, _out_idx| Ok(Output::Hash(H256::from_low_u64_be(42))));
batch.requests[1].fill(|_req_idx, _out_idx| Ok(Output::Hash(42.into())));
assert!(batch.next_complete().is_some());
batch.answered += 1;

View File

@@ -1648,7 +1648,7 @@ mod tests {
#[test]
fn hash_or_number_roundtrip() {
let hash = HashOrNumber::Hash(H256::zero());
let hash = HashOrNumber::Hash(H256::default());
let number = HashOrNumber::Number(5);
check_roundtrip(hash);
@@ -1808,7 +1808,7 @@ mod tests {
let full_req = Request::Storage(req.clone());
let res = StorageResponse {
proof: vec![vec![1, 2, 3], vec![4, 5, 6]],
value: H256::zero(),
value: H256::default(),
};
let full_res = Response::Storage(res.clone());
@@ -1909,7 +1909,7 @@ mod tests {
code_hash: Default::default(),
storage_root: Default::default()
}),
Response::Storage(StorageResponse { proof: vec![], value: H256::zero() }),
Response::Storage(StorageResponse { proof: vec![], value: H256::default() }),
Response::Code(CodeResponse { code: vec![1, 2, 3, 4, 5] }),
Response::Execution(ExecutionResponse { items: vec![] }),
];

View File

@@ -10,12 +10,12 @@ authors = ["Parity Technologies <admin@parity.io>"]
ethcore = { path = ".."}
ethcore-network = { path = "../../util/network" }
ethcore-network-devp2p = { path = "../../util/network-devp2p" }
ethereum-types = "0.6.0"
ethereum-types = "0.4"
log = "0.4"
parking_lot = "0.7"
ethabi = "8.0"
ethabi-derive = "8.0"
ethabi-contract = "8.0"
ethabi = "6.0"
ethabi-derive = "6.0"
ethabi-contract = "6.0"
lru-cache = "0.1"
[dev-dependencies]

View File

@@ -37,17 +37,13 @@ extern crate tempdir;
#[macro_use]
extern crate log;
use std::collections::{HashMap, VecDeque};
use std::sync::Weak;
use ethcore::client::{BlockChainClient, BlockId, ChainNotify, NewBlocks};
use ethcore::client::{BlockChainClient, BlockId};
use ethereum_types::{H256, Address};
use ethabi::FunctionOutputDecoder;
use network::{ConnectionFilter, ConnectionDirection};
use devp2p::NodeId;
use devp2p::MAX_NODES_IN_TABLE;
use parking_lot::RwLock;
use_contract!(peer_set, "res/peer_set.json");
@@ -55,27 +51,14 @@ use_contract!(peer_set, "res/peer_set.json");
pub struct NodeFilter {
client: Weak<BlockChainClient>,
contract_address: Address,
cache: RwLock<Cache>
}
struct Cache {
cache: HashMap<NodeId, bool>,
order: VecDeque<NodeId>
}
// Increase cache size due to possible reserved peers, which do not count in the node table size
pub const CACHE_SIZE: usize = MAX_NODES_IN_TABLE + 1024;
impl NodeFilter {
/// Create a new instance. Accepts a contract address.
pub fn new(client: Weak<BlockChainClient>, contract_address: Address) -> NodeFilter {
NodeFilter {
client,
contract_address,
cache: RwLock::new(Cache{
cache: HashMap::with_capacity(CACHE_SIZE),
order: VecDeque::with_capacity(CACHE_SIZE)
})
}
}
}
@@ -87,10 +70,6 @@ impl ConnectionFilter for NodeFilter {
None => return false,
};
if let Some(allowed) = self.cache.read().cache.get(connecting_id) {
return *allowed;
}
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]);
@@ -104,23 +83,8 @@ impl ConnectionFilter for NodeFilter {
debug!("Error callling peer set contract: {:?}", e);
false
});
let mut cache = self.cache.write();
if cache.cache.len() == CACHE_SIZE {
let popped = cache.order.pop_front().expect("the cache is full so there's at least one item we can pop; qed");
cache.cache.remove(&popped);
};
if cache.cache.insert(*connecting_id, allowed).is_none() {
cache.order.push_back(*connecting_id);
}
allowed
}
}
impl ChainNotify for NodeFilter {
fn new_blocks(&self, _new_blocks: NewBlocks) {
let mut cache = self.cache.write();
cache.cache.clear();
cache.order.clear();
allowed
}
}
@@ -135,13 +99,11 @@ mod test {
use io::IoChannel;
use super::NodeFilter;
use tempdir::TempDir;
use ethereum_types::Address;
use std::str::FromStr;
/// Contract code: https://gist.github.com/arkpar/467dbcc73cbb85b0997a7a10ffa0695f
#[test]
fn node_filter() {
let contract_addr = Address::from_str("0000000000000000000000000000000000000005").unwrap();
let contract_addr = "0000000000000000000000000000000000000005".into();
let data = include_bytes!("../res/node_filter.json");
let tempdir = TempDir::new("").unwrap();
let spec = Spec::load(&tempdir.path(), &data[..]).unwrap();
@@ -155,11 +117,11 @@ mod test {
IoChannel::disconnected(),
).unwrap();
let filter = NodeFilter::new(Arc::downgrade(&client) as Weak<BlockChainClient>, contract_addr);
let self1 = NodeId::from_str("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002").unwrap();
let self2 = NodeId::from_str("00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003").unwrap();
let node1 = NodeId::from_str("00000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012").unwrap();
let node2 = NodeId::from_str("00000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000022").unwrap();
let nodex = NodeId::from_str("77000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
let self1: NodeId = "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002".into();
let self2: NodeId = "00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003".into();
let node1: NodeId = "00000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012".into();
let node2: NodeId = "00000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000022".into();
let nodex: NodeId = "77000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into();
assert!(filter.connection_allowed(&self1, &node1, ConnectionDirection::Inbound));
assert!(filter.connection_allowed(&self1, &nodex, ConnectionDirection::Inbound));

View File

@@ -1,27 +0,0 @@
[package]
description = "Account system expressed in Plain Old Data."
name = "pod-account"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
[dependencies]
common-types = { path = "../types" }
ethereum-types = "0.6"
ethjson = { path = "../../json" }
ethtrie = { package = "patricia-trie-ethereum", path = "../../util/patricia-trie-ethereum" }
hash-db = "0.12"
itertools = "0.8"
keccak-hash = "0.2.0"
keccak-hasher = { path = "../../util/keccak-hasher" }
kvdb = "0.1"
log = "0.4"
parity-bytes = "0.1.0"
rlp = "0.4"
rustc-hex = "1"
serde = { version = "1.0", features = ["derive"] }
trie-db = "0.12.4"
triehash = { package = "triehash-ethereum", version = "0.2", path = "../../util/triehash-ethereum" }
[dev-dependencies]
macros = { path = "../../util/macros" }

View File

@@ -8,34 +8,33 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
common-types = { path = "../types" }
derive_more = "0.14.0"
ethabi = "8.0"
ethabi-contract = "8.0"
ethabi-derive = "8.0"
ethabi = "6.0"
ethabi-contract = "6.0"
ethabi-derive = "6.0"
ethcore = { path = ".." }
ethcore-call-contract = { path = "../call-contract" }
ethcore-io = { path = "../../util/io" }
ethcore-miner = { path = "../../miner" }
ethereum-types = "0.6.0"
ethereum-types = "0.4"
ethjson = { path = "../../json" }
ethkey = { path = "../../accounts/ethkey" }
fetch = { path = "../../util/fetch" }
futures = "0.1"
parity-util-mem = "0.1"
keccak-hash = "0.2.0"
heapsize = "0.4"
keccak-hash = "0.1.2"
log = "0.4"
parity-bytes = "0.1"
parity-crypto = "0.4.0"
parity-crypto = "0.3.0"
parking_lot = "0.7"
trie-db = "0.12.4"
trie-db = "0.11.0"
patricia-trie-ethereum = { path = "../../util/patricia-trie-ethereum" }
rand = "0.3"
rlp = "0.4.0"
rlp = { version = "0.3.0", features = ["ethereum"] }
rlp_derive = { path = "../../util/rlp-derive" }
rustc-hex = "1.0"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
time-utils = { path = "../../util/time-utils" }
tiny-keccak = "1.4"
transaction-pool = "2.0"
url = "1"

View File

@@ -114,7 +114,7 @@ impl SecretStoreEncryptor {
let requester = self.config.key_server_account.ok_or_else(|| Error::KeyServerAccountNotSet)?;
// key id in SS is H256 && we have H160 here => expand with assitional zeros
let contract_address_extended: H256 = (*contract_address).into();
let contract_address_extended: H256 = contract_address.into();
let base_url = self.config.base_url.clone().ok_or_else(|| Error::KeyServerNotSet)?;
// prepare request url
@@ -156,7 +156,7 @@ impl SecretStoreEncryptor {
let decrypted_key = Public::from_slice(&decrypted_bytes);
// and now take x coordinate of Public as a key
let key: Bytes = decrypted_key.as_bytes()[..INIT_VEC_LEN].into();
let key: Bytes = (*decrypted_key)[..INIT_VEC_LEN].into();
// cache the key in the session and clear expired sessions
self.sessions.lock().insert(*contract_address, EncryptionSession{
@@ -212,11 +212,11 @@ impl Encryptor for SecretStoreEncryptor {
}?;
// encrypt data
let mut cypher = Vec::with_capacity(plain_data.len() + initialisation_vector.as_bytes().len());
let mut cypher = Vec::with_capacity(plain_data.len() + initialisation_vector.len());
cypher.extend(repeat(0).take(plain_data.len()));
crypto::aes::encrypt_128_ctr(&key, initialisation_vector.as_bytes(), plain_data, &mut cypher)
crypto::aes::encrypt_128_ctr(&key, initialisation_vector, plain_data, &mut cypher)
.map_err(|e| Error::Encrypt(e.to_string()))?;
cypher.extend_from_slice(&initialisation_vector.as_bytes());
cypher.extend_from_slice(&initialisation_vector);
Ok(cypher)
}

View File

@@ -25,7 +25,6 @@ use ethkey::Error as KeyError;
use ethkey::crypto::Error as CryptoError;
use txpool::VerifiedTransaction;
use private_transactions::VerifiedPrivateTransaction;
use serde_json::{Error as SerdeError};
type TxPoolError = txpool::Error<<VerifiedPrivateTransaction as VerifiedTransaction>::Hash>;
@@ -46,9 +45,6 @@ pub enum Error {
/// Crypto error.
#[display(fmt = "Crypto Error {}", _0)]
Crypto(CryptoError),
/// Serialization error.
#[display(fmt = "Serialization Error {}", _0)]
Json(SerdeError),
/// Encryption error.
#[display(fmt = "Encryption error. ({})", _0)]
Encrypt(String),
@@ -103,15 +99,6 @@ pub enum Error {
/// Key server URL is not set.
#[display(fmt = "Key server URL is not set.")]
KeyServerNotSet,
/// Transaction not found in logs.
#[display(fmt = "Private transaction not found in logs.")]
TxNotFoundInLog,
/// Path for logging not set.
#[display(fmt = "Path for logging not set.")]
LoggingPathNotSet,
/// Timestamp overflow error.
#[display(fmt = "Timestamp overflow error.")]
TimestampOverflow,
/// VM execution error.
#[display(fmt = "VM execution error {}", _0)]
Execution(ExecutionError),
@@ -136,7 +123,6 @@ impl error::Error for Error {
Error::Decoder(e) => Some(e),
Error::Trie(e) => Some(e),
Error::TxPool(e) => Some(e),
Error::Json(e) => Some(e),
Error::Crypto(e) => Some(e),
Error::Execution(e) => Some(e),
Error::Key(e) => Some(e),
@@ -201,12 +187,6 @@ impl From<TxPoolError> for Error {
}
}
impl From<SerdeError> for Error {
fn from(err: SerdeError) -> Self {
Error::Json(err).into()
}
}
impl From<EthcoreError> for Error {
fn from(err: EthcoreError) -> Self {
Error::Ethcore(err).into()

View File

@@ -29,15 +29,15 @@ use_contract!(keys_acl_contract, "res/keys_acl.json");
/// Returns the address (of the contract), that corresponds to the key
pub fn key_to_address(key: &H256) -> Address {
Address::from_slice(&key.as_bytes()[..10])
Address::from_slice(&key.to_vec()[..10])
}
/// Returns the key from the key server associated with the contract
pub fn address_to_key(contract_address: &Address) -> H256 {
// Current solution uses contract address extended with 0 as id
let contract_address_extended: H256 = (*contract_address).into();
let contract_address_extended: H256 = contract_address.into();
H256::from_slice(contract_address_extended.as_bytes())
H256::from_slice(&contract_address_extended)
}
/// Trait for keys server keys provider.
@@ -118,7 +118,7 @@ impl Default for StoringKeyProvider {
fn default() -> Self {
StoringKeyProvider {
available_keys: RwLock::new(None),
key_server_account: Some(Address::zero()),
key_server_account: Some(Address::default()),
}
}
}
@@ -170,4 +170,4 @@ mod tests {
keys_data.update_acl_contract();
assert_eq!(keys_data.keys_acl_contract.read().unwrap(), key.address());
}
}
}

View File

@@ -16,12 +16,15 @@
//! Private transactions module.
// Recursion limit required because of
// error_chain foreign_links.
#![recursion_limit="256"]
mod encryptor;
mod key_server_keys;
mod private_transactions;
mod messages;
mod error;
mod log;
extern crate common_types as types;
extern crate ethabi;
@@ -34,7 +37,7 @@ extern crate ethjson;
extern crate ethkey;
extern crate fetch;
extern crate futures;
extern crate parity_util_mem;
extern crate heapsize;
extern crate keccak_hash as hash;
extern crate parity_bytes as bytes;
extern crate parity_crypto as crypto;
@@ -42,15 +45,11 @@ extern crate parking_lot;
extern crate trie_db as trie;
extern crate patricia_trie_ethereum as ethtrie;
extern crate rlp;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
extern crate rustc_hex;
extern crate transaction_pool as txpool;
extern crate url;
#[macro_use]
extern crate log as ethlog;
extern crate log;
#[macro_use]
extern crate ethabi_derive;
#[macro_use]
@@ -59,9 +58,6 @@ extern crate derive_more;
#[macro_use]
extern crate rlp_derive;
#[cfg(not(time_checked_add))]
extern crate time_utils;
#[cfg(test)]
extern crate rand;
#[cfg(test)]
@@ -72,11 +68,10 @@ pub use key_server_keys::{KeyProvider, SecretStoreKeys, StoringKeyProvider};
pub use private_transactions::{VerifiedPrivateTransaction, VerificationStore, PrivateTransactionSigningDesc, SigningStore};
pub use messages::{PrivateTransaction, SignedPrivateTransaction};
pub use error::Error;
pub use log::{Logging, TransactionLog, ValidatorLog, PrivateTxStatus, FileLogsSerializer};
use std::sync::{Arc, Weak};
use std::collections::{HashMap, HashSet, BTreeMap};
use ethereum_types::{H128, H256, U256, Address, BigEndianHash};
use ethereum_types::{H128, H256, U256, Address};
use hash::keccak;
use rlp::*;
use parking_lot::RwLock;
@@ -122,8 +117,6 @@ pub struct ProviderConfig {
pub validator_accounts: Vec<Address>,
/// Account used for signing public transactions created from private transactions
pub signer_account: Option<Address>,
/// Path to private tx logs
pub logs_path: Option<String>,
}
#[derive(Debug)]
@@ -184,7 +177,6 @@ pub struct Provider {
accounts: Arc<Signer>,
channel: IoChannel<ClientIoMessage>,
keys_provider: Arc<KeyProvider>,
logging: Option<Logging>,
}
#[derive(Debug)]
@@ -219,7 +211,6 @@ impl Provider {
accounts,
channel,
keys_provider,
logging: config.logs_path.map(|path| Logging::new(Arc::new(FileLogsSerializer::with_path(path)))),
}
}
@@ -266,11 +257,8 @@ impl Provider {
trace!(target: "privatetx", "Required validators: {:?}", contract_validators);
let private_state_hash = self.calculate_state_hash(&private_state, contract_nonce);
trace!(target: "privatetx", "Hashed effective private state for sender: {:?}", private_state_hash);
self.transactions_for_signing.write().add_transaction(private.hash(), signed_transaction, &contract_validators, private_state, contract_nonce)?;
self.transactions_for_signing.write().add_transaction(private.hash(), signed_transaction, contract_validators, private_state, contract_nonce)?;
self.broadcast_private_transaction(private.hash(), private.rlp_bytes());
if let Some(ref logging) = self.logging {
logging.private_tx_created(&tx_hash, &contract_validators);
}
Ok(Receipt {
hash: tx_hash,
contract_address: contract,
@@ -281,10 +269,9 @@ impl Provider {
/// Calculate hash from united private state and contract nonce
pub fn calculate_state_hash(&self, state: &Bytes, nonce: U256) -> H256 {
let state_hash = keccak(state);
let nonce_h256: H256 = BigEndianHash::from_uint(&nonce);
let mut state_buf = [0u8; 64];
state_buf[..32].clone_from_slice(state_hash.as_bytes());
state_buf[32..].clone_from_slice(nonce_h256.as_bytes());
state_buf[..32].clone_from_slice(&state_hash);
state_buf[32..].clone_from_slice(&H256::from(nonce));
keccak(&state_buf.as_ref())
}
@@ -367,9 +354,8 @@ impl Provider {
Some(desc) => desc,
};
let last = self.last_required_signature(&desc, signed_tx.signature())?;
let original_tx_hash = desc.original_transaction.hash();
if last.0 {
if last {
let mut signatures = desc.received_signatures.clone();
signatures.push(signed_tx.signature());
let rsv: Vec<Signature> = signatures.into_iter().map(|sign| sign.into_electrum().into()).collect();
@@ -387,8 +373,8 @@ impl Provider {
trace!(target: "privatetx", "Last required signature received, public transaction created: {:?}", public_tx);
// Sign and add it to the queue
let chain_id = desc.original_transaction.chain_id();
let public_tx_hash = public_tx.hash(chain_id);
let signature = self.accounts.sign(signer_account, public_tx_hash)?;
let hash = public_tx.hash(chain_id);
let signature = self.accounts.sign(signer_account, hash)?;
let signed = SignedTransaction::new(public_tx.with_signature(signature, chain_id))?;
match self.miner.import_own_transaction(&*self.client, signed.into()) {
Ok(_) => trace!(target: "privatetx", "Public transaction added to queue"),
@@ -406,11 +392,6 @@ impl Provider {
Err(err) => warn!(target: "privatetx", "Failed to send private state changed notification, error: {:?}", err),
}
}
// Store logs
if let Some(ref logging) = self.logging {
logging.signature_added(&original_tx_hash, &last.1);
logging.tx_deployed(&original_tx_hash, &public_tx_hash);
}
// Remove from store for signing
if let Err(err) = self.transactions_for_signing.write().remove(&private_hash) {
warn!(target: "privatetx", "Failed to remove transaction from signing store, error: {:?}", err);
@@ -419,12 +400,7 @@ impl Provider {
} else {
// Add signature to the store
match self.transactions_for_signing.write().add_signature(&private_hash, signed_tx.signature()) {
Ok(_) => {
trace!(target: "privatetx", "Signature stored for private transaction");
if let Some(ref logging) = self.logging {
logging.signature_added(&original_tx_hash, &last.1);
}
}
Ok(_) => trace!(target: "privatetx", "Signature stored for private transaction"),
Err(err) => {
warn!(target: "privatetx", "Failed to add signature to signing store, error: {:?}", err);
return Err(err);
@@ -444,14 +420,17 @@ impl Provider {
}
}
fn last_required_signature(&self, desc: &PrivateTransactionSigningDesc, sign: Signature) -> Result<(bool, Address), Error> {
fn last_required_signature(&self, desc: &PrivateTransactionSigningDesc, sign: Signature) -> Result<bool, Error> {
if desc.received_signatures.contains(&sign) {
return Ok(false);
}
let state_hash = self.calculate_state_hash(&desc.state, desc.contract_nonce);
match recover(&sign, &state_hash) {
Ok(public) => {
let sender = public_to_address(&public);
match desc.validators.contains(&sender) {
true => {
Ok((desc.received_signatures.len() + 1 == desc.validators.len(), sender))
Ok(desc.received_signatures.len() + 1 == desc.validators.len())
}
false => {
warn!(target: "privatetx", "Sender's state doesn't correspond to validator's");
@@ -478,13 +457,13 @@ impl Provider {
fn iv_from_transaction(transaction: &SignedTransaction) -> H128 {
let nonce = keccak(&transaction.nonce.rlp_bytes());
let (iv, _) = nonce.as_bytes().split_at(INIT_VEC_LEN);
let (iv, _) = nonce.split_at(INIT_VEC_LEN);
H128::from_slice(iv)
}
fn iv_from_address(contract_address: &Address) -> H128 {
let address = keccak(&contract_address.rlp_bytes());
let (iv, _) = address.as_bytes().split_at(INIT_VEC_LEN);
let (iv, _) = address.split_at(INIT_VEC_LEN);
H128::from_slice(iv)
}
@@ -533,8 +512,8 @@ impl Provider {
// Sort the storage to guarantee the order for all parties
let sorted_storage: BTreeMap<&H256, &H256> = storage.iter().collect();
for (key, value) in sorted_storage {
raw.extend_from_slice(key.as_bytes());
raw.extend_from_slice(value.as_bytes());
raw.extend_from_slice(key);
raw.extend_from_slice(value);
};
raw
}
@@ -618,8 +597,8 @@ impl Provider {
v[31] = s.v();
v
}).collect::<Vec<[u8; 32]>>(),
signatures.iter().map(|s| H256::from_slice(s.r())).collect::<Vec<H256>>(),
signatures.iter().map(|s| H256::from_slice(s.s())).collect::<Vec<H256>>(),
signatures.iter().map(|s| s.r()).collect::<Vec<&[u8]>>(),
signatures.iter().map(|s| s.s()).collect::<Vec<&[u8]>>()
)
}
@@ -695,14 +674,6 @@ impl Provider {
Ok(result.result)
}
/// Retrieves log information about private transaction
pub fn private_log(&self, tx_hash: H256) -> Result<TransactionLog, Error> {
match self.logging {
Some(ref logging) => logging.tx_log(&tx_hash).ok_or(Error::TxNotFoundInLog),
None => Err(Error::LoggingPathNotSet),
}
}
/// Returns private validators for a contract.
pub fn get_validators(&self, block: BlockId, address: &Address) -> Result<Vec<Address>, Error> {
let (data, decoder) = private_contract::functions::get_validators::call();

View File

@@ -1,409 +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 <http://www.gnu.org/licenses/>.
//! Private transactions logs.
use ethereum_types::{H256, Address};
use std::collections::HashMap;
use std::fs::File;
use std::path::PathBuf;
use std::sync::Arc;
use std::time::{SystemTime, Duration, Instant};
use parking_lot::RwLock;
use serde::ser::{Serializer, SerializeSeq};
use error::Error;
#[cfg(not(time_checked_add))]
use time_utils::CheckedSystemTime;
/// Maximum amount of stored private transaction logs.
const MAX_JOURNAL_LEN: usize = 1000;
/// Maximum period for storing private transaction logs.
/// Logs older than 20 days will not be processed
const MAX_STORING_TIME: Duration = Duration::from_secs(60 * 60 * 24 * 20);
/// Source of monotonic time for log timestamps
struct MonoTime {
start_time: SystemTime,
start_inst: Instant
}
impl MonoTime {
fn new(start: SystemTime) -> Self {
Self {
start_time: start,
start_inst: Instant::now()
}
}
fn elapsed(&self) -> Duration {
self.start_inst.elapsed()
}
fn to_system_time(&self) -> SystemTime {
self.start_time + self.elapsed()
}
}
impl Default for MonoTime {
fn default() -> Self {
MonoTime::new(SystemTime::now())
}
}
/// Current status of the private transaction
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
pub enum PrivateTxStatus {
/// Private tx was created but no validation received yet
Created,
/// Several validators (but not all) validated the transaction
Validating,
/// All validators has validated the private tx
/// Corresponding public tx was created and added into the pool
Deployed,
}
/// Information about private tx validation
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidatorLog {
/// Account of the validator
pub account: Address,
/// Validation timestamp, None if the transaction is not validated
pub validation_timestamp: Option<SystemTime>,
}
#[cfg(test)]
impl PartialEq for ValidatorLog {
fn eq(&self, other: &Self) -> bool {
self.account == other.account
}
}
/// Information about the private transaction
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransactionLog {
/// Original signed transaction hash (used as a source for private tx)
pub tx_hash: H256,
/// Current status of the private transaction
pub status: PrivateTxStatus,
/// Creation timestamp
pub creation_timestamp: SystemTime,
/// List of validations
pub validators: Vec<ValidatorLog>,
/// Timestamp of the resulting public tx deployment
pub deployment_timestamp: Option<SystemTime>,
/// Hash of the resulting public tx
pub public_tx_hash: Option<H256>,
}
#[cfg(test)]
impl PartialEq for TransactionLog {
fn eq(&self, other: &Self) -> bool {
self.tx_hash == other.tx_hash &&
self.status == other.status &&
self.validators == other.validators &&
self.public_tx_hash == other.public_tx_hash
}
}
/// Wrapper other JSON serializer
pub trait LogsSerializer: Send + Sync + 'static {
/// Read logs from the source
fn read_logs(&self) -> Result<Vec<TransactionLog>, Error>;
/// Write all logs to the source
fn flush_logs(&self, logs: &HashMap<H256, TransactionLog>) -> Result<(), Error>;
}
/// Logs serializer to the json file
pub struct FileLogsSerializer {
logs_dir: PathBuf,
}
impl FileLogsSerializer {
pub fn with_path<P: Into<PathBuf>>(logs_dir: P) -> Self {
FileLogsSerializer {
logs_dir: logs_dir.into(),
}
}
fn open_file(&self, to_create: bool) -> Result<File, Error> {
let file_path = self.logs_dir.with_file_name("private_tx.log");
if to_create {
File::create(&file_path).map_err(From::from)
} else {
File::open(&file_path).map_err(From::from)
}
}
}
impl LogsSerializer for FileLogsSerializer {
fn read_logs(&self) -> Result<Vec<TransactionLog>, Error> {
let log_file = self.open_file(false)?;
match serde_json::from_reader(log_file) {
Ok(logs) => Ok(logs),
Err(err) => {
error!(target: "privatetx", "Cannot deserialize logs from file: {}", err);
return Err(format!("Cannot deserialize logs from file: {:?}", err).into());
}
}
}
fn flush_logs(&self, logs: &HashMap<H256, TransactionLog>) -> Result<(), Error> {
if logs.is_empty() {
// Do not create empty file
return Ok(());
}
let log_file = self.open_file(true)?;
let mut json = serde_json::Serializer::new(log_file);
let mut json_array = json.serialize_seq(Some(logs.len()))?;
for v in logs.values() {
json_array.serialize_element(v)?;
}
json_array.end()?;
Ok(())
}
}
/// Private transactions logging
pub struct Logging {
logs: RwLock<HashMap<H256, TransactionLog>>,
logs_serializer: Arc<LogsSerializer>,
mono_time: MonoTime,
}
impl Logging {
/// Creates the logging object
pub fn new(logs_serializer: Arc<LogsSerializer>) -> Self {
let mut logging = Logging {
logs: RwLock::new(HashMap::new()),
logs_serializer,
mono_time: MonoTime::default(),
};
match logging.read_logs() {
// Initialize time source by max from current system time and max creation time from already saved logs
Ok(initial_time) => logging.mono_time = MonoTime::new(initial_time),
Err(err) => warn!(target: "privatetx", "Cannot read logs: {:?}", err),
}
logging
}
/// Retrieves log for the corresponding tx hash
pub fn tx_log(&self, tx_hash: &H256) -> Option<TransactionLog> {
self.logs.read().get(&tx_hash).cloned()
}
/// Logs the creation of the private transaction
pub fn private_tx_created(&self, tx_hash: &H256, validators: &[Address]) {
let mut validator_logs = Vec::new();
for account in validators {
validator_logs.push(ValidatorLog {
account: *account,
validation_timestamp: None,
});
}
let mut logs = self.logs.write();
if logs.len() > MAX_JOURNAL_LEN {
// Remove the oldest log
if let Some(tx_hash) = logs.values()
.min_by(|x, y| x.creation_timestamp.cmp(&y.creation_timestamp))
.map(|oldest| oldest.tx_hash)
{
logs.remove(&tx_hash);
}
}
logs.insert(*tx_hash, TransactionLog {
tx_hash: *tx_hash,
status: PrivateTxStatus::Created,
creation_timestamp: self.mono_time.to_system_time(),
validators: validator_logs,
deployment_timestamp: None,
public_tx_hash: None,
});
}
/// Logs the validation of the private transaction by one of its validators
pub fn signature_added(&self, tx_hash: &H256, validator: &Address) {
let mut logs = self.logs.write();
if let Some(transaction_log) = logs.get_mut(&tx_hash) {
if let Some(ref mut validator_log) = transaction_log.validators.iter_mut().find(|log| log.account == *validator) {
transaction_log.status = PrivateTxStatus::Validating;
validator_log.validation_timestamp = Some(self.mono_time.to_system_time());
}
}
}
/// Logs the final deployment of the resulting public transaction
pub fn tx_deployed(&self, tx_hash: &H256, public_tx_hash: &H256) {
let mut logs = self.logs.write();
if let Some(log) = logs.get_mut(&tx_hash) {
log.status = PrivateTxStatus::Deployed;
log.deployment_timestamp = Some(self.mono_time.to_system_time());
log.public_tx_hash = Some(*public_tx_hash);
}
}
fn read_logs(&self) -> Result<SystemTime, Error> {
let mut transaction_logs = self.logs_serializer.read_logs()?;
// Drop old logs
let earliest_possible = SystemTime::now().checked_sub(MAX_STORING_TIME).ok_or(Error::TimestampOverflow)?;
transaction_logs.retain(|tx_log| tx_log.creation_timestamp > earliest_possible);
// Sort logs by their creation time in order to find the most recent
transaction_logs.sort_by(|a, b| b.creation_timestamp.cmp(&a.creation_timestamp));
let initial_timestamp = transaction_logs.first()
.map_or(SystemTime::now(), |l| std::cmp::max(SystemTime::now(), l.creation_timestamp));
let mut logs = self.logs.write();
for log in transaction_logs {
logs.insert(log.tx_hash, log);
}
Ok(initial_timestamp)
}
fn flush_logs(&self) -> Result<(), Error> {
let logs = self.logs.read();
self.logs_serializer.flush_logs(&logs)
}
}
// Flush all logs on drop
impl Drop for Logging {
fn drop(&mut self) {
if let Err(err) = self.flush_logs() {
warn!(target: "privatetx", "Cannot write logs: {:?}", err);
}
}
}
#[cfg(test)]
mod tests {
use serde_json;
use error::Error;
use ethereum_types::{H256, Address};
use std::collections::{HashMap, BTreeMap};
use std::sync::Arc;
use std::time::{SystemTime, Duration};
use std::str::FromStr;
use types::transaction::Transaction;
use parking_lot::RwLock;
use super::{TransactionLog, Logging, PrivateTxStatus, LogsSerializer, ValidatorLog};
#[cfg(not(time_checked_add))]
use time_utils::CheckedSystemTime;
struct StringLogSerializer {
string_log: RwLock<String>,
}
impl StringLogSerializer {
fn new(source: String) -> Self {
StringLogSerializer {
string_log: RwLock::new(source),
}
}
fn log(&self) -> String {
let log = self.string_log.read();
log.clone()
}
}
impl LogsSerializer for StringLogSerializer {
fn read_logs(&self) -> Result<Vec<TransactionLog>, Error> {
let source = self.string_log.read();
if source.is_empty() {
return Ok(Vec::new())
}
let logs = serde_json::from_str(&source).unwrap();
Ok(logs)
}
fn flush_logs(&self, logs: &HashMap<H256, TransactionLog>) -> Result<(), Error> {
// Sort logs in order to have the same order
let sorted_logs: BTreeMap<&H256, &TransactionLog> = logs.iter().collect();
*self.string_log.write() = serde_json::to_string(&sorted_logs.values().collect::<Vec<&&TransactionLog>>())?;
Ok(())
}
}
#[test]
fn private_log_format() {
let s = r#"{
"tx_hash":"0x64f648ca7ae7f4138014f860ae56164d8d5732969b1cea54d8be9d144d8aa6f6",
"status":"Deployed",
"creation_timestamp":{"secs_since_epoch":1557220355,"nanos_since_epoch":196382053},
"validators":[{
"account":"0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1",
"validation_timestamp":{"secs_since_epoch":1557220355,"nanos_since_epoch":196382053}
}],
"deployment_timestamp":{"secs_since_epoch":1557220355,"nanos_since_epoch":196382053},
"public_tx_hash":"0x69b9c691ede7993effbcc88911c309af1c82be67b04b3882dd446b808ae146da"
}"#;
let _deserialized: TransactionLog = serde_json::from_str(s).unwrap();
}
#[test]
fn private_log_status() {
let logger = Logging::new(Arc::new(StringLogSerializer::new("".into())));
let private_tx = Transaction::default();
let hash = private_tx.hash(None);
logger.private_tx_created(&hash, &vec![Address::from_str("82a978b3f5962a5b0957d9ee9eef472ee55b42f1").unwrap()]);
logger.signature_added(&hash, &Address::from_str("82a978b3f5962a5b0957d9ee9eef472ee55b42f1").unwrap());
logger.tx_deployed(&hash, &hash);
let tx_log = logger.tx_log(&hash).unwrap();
assert_eq!(tx_log.status, PrivateTxStatus::Deployed);
}
#[test]
fn serialization() {
let current_timestamp = SystemTime::now();
let initial_validator_log = ValidatorLog {
account: Address::from_str("82a978b3f5962a5b0957d9ee9eef472ee55b42f1").unwrap(),
validation_timestamp: Some(current_timestamp.checked_add(Duration::from_secs(1)).unwrap()),
};
let initial_log = TransactionLog {
tx_hash: H256::from_str("64f648ca7ae7f4138014f860ae56164d8d5732969b1cea54d8be9d144d8aa6f6").unwrap(),
status: PrivateTxStatus::Deployed,
creation_timestamp: current_timestamp,
validators: vec![initial_validator_log],
deployment_timestamp: Some(current_timestamp.checked_add(Duration::from_secs(2)).unwrap()),
public_tx_hash: Some(H256::from_str("69b9c691ede7993effbcc88911c309af1c82be67b04b3882dd446b808ae146da").unwrap()),
};
let serializer = Arc::new(StringLogSerializer::new(serde_json::to_string(&vec![initial_log.clone()]).unwrap()));
let logger = Logging::new(serializer.clone());
let hash = H256::from_str("63c715e88f7291e66069302f6fcbb4f28a19ef5d7cbd1832d0c01e221c0061c6").unwrap();
logger.private_tx_created(&hash, &vec![Address::from_str("7ffbe3512782069be388f41be4d8eb350672d3a5").unwrap()]);
logger.signature_added(&hash, &Address::from_str("7ffbe3512782069be388f41be4d8eb350672d3a5").unwrap());
logger.tx_deployed(&hash, &H256::from_str("de2209a8635b9cab9eceb67928b217c70ab53f6498e5144492ec01e6f43547d7").unwrap());
drop(logger);
let added_validator_log = ValidatorLog {
account: Address::from_str("7ffbe3512782069be388f41be4d8eb350672d3a5").unwrap(),
validation_timestamp: Some(current_timestamp.checked_add(Duration::from_secs(7)).unwrap()),
};
let added_log = TransactionLog {
tx_hash: H256::from_str("63c715e88f7291e66069302f6fcbb4f28a19ef5d7cbd1832d0c01e221c0061c6").unwrap(),
status: PrivateTxStatus::Deployed,
creation_timestamp: current_timestamp.checked_add(Duration::from_secs(6)).unwrap(),
validators: vec![added_validator_log],
deployment_timestamp: Some(current_timestamp.checked_add(Duration::from_secs(8)).unwrap()),
public_tx_hash: Some(H256::from_str("de2209a8635b9cab9eceb67928b217c70ab53f6498e5144492ec01e6f43547d7").unwrap()),
};
let should_be_final = vec![added_log, initial_log];
let deserialized_logs: Vec<TransactionLog> = serde_json::from_str(&serializer.log()).unwrap();
assert_eq!(deserialized_logs, should_be_final);
}
}

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
use ethereum_types::{H256, U256, Address, BigEndianHash};
use ethereum_types::{H256, U256, Address};
use bytes::Bytes;
use hash::keccak;
use rlp::Encodable;
@@ -38,7 +38,7 @@ impl PrivateTransaction {
PrivateTransaction {
encrypted,
contract,
hash: H256::zero(),
hash: 0.into(),
}.compute_hash()
}
@@ -87,7 +87,7 @@ impl SignedPrivateTransaction {
r: sig.r().into(),
s: sig.s().into(),
v: add_chain_replay_protection(sig.v() as u64, chain_id),
hash: H256::zero(),
hash: 0.into(),
}.compute_hash()
}
@@ -100,11 +100,7 @@ impl SignedPrivateTransaction {
/// Construct a signature object from the sig.
pub fn signature(&self) -> Signature {
Signature::from_rsv(
&BigEndianHash::from_uint(&self.r),
&BigEndianHash::from_uint(&self.s),
self.standard_v(),
)
Signature::from_rsv(&self.r.into(), &self.s.into(), self.standard_v())
}
/// Get the hash of of the original transaction.

Some files were not shown because too many files have changed in this diff Show More