Compare commits

..

17 Commits

Author SHA1 Message Date
s3krit
06c7096054 Update CHANGELOG.md and version (#11093)
* Update CHANGELOG.md and version
2019-09-26 12:38:49 +02:00
s3krit
b2277f65e4 v2.5.9-stable (#11089)
* ethcore/res: activate Istanbul on Ropsten, Görli, Rinkeby, Kovan (#11068)

* ethcore/res: activate Istanbul on Ropsten block 6485846

* ethcore/res: activate Istanbul on Goerli block 1561651

* ethcore/res: use hex values for Istanbul specs

* ethcore/res: fix trailing comma

* ethcore/res: be pedantic about EIP-1283 in Petersburg and Istanbul test specs

* ethcore/res: activate Istanbul on Rinkeby block 5435345

* ethcore/res: activate Istanbul on Kovan block 14111141

* ethcore/res: fix kovan istanbul number to 0xd751a5

* [json-spec] make blake2 pricing spec more readable (#11034)

* [json-spec] make blake2 pricing spec more readable

* [ethcore] fix compilation

* Manual backport of #11033
2019-09-26 11:03:39 +02:00
s3krit
c52a6c8fb7 update CHANGELOG.md (#11057) 2019-09-16 12:00:04 +02:00
s3krit
7c7b181ca0 v2.5.8-stable (rev2) (#11051)
* EIP 1884 Re-pricing of trie-size dependent operations  (#10992)
* Implement EIP-1283 reenable transition, EIP-1706 and EIP-2200  (#10191)
2019-09-13 15:46:03 +02:00
David
24a4fdf405 Don't build rpc with ethcore test-helpers (#11048) 2019-09-13 11:53:49 +02:00
s3krit
45f27cec34 v2.5.8-stable (#11041)
* add more tx tests (#11038)
* Fix parallel transactions race-condition (#10995)
* Add blake2_f precompile (#11017)
* [trace] introduce trace failed to Ext (#11019)
* Edit publish-onchain.sh to use https (#11016)
* Fix deadlock in network-devp2p (#11013)
* EIP 1108: Reduce alt_bn128 precompile gas costs (#11008)
* xDai chain support and nodes list update (#10989)
* EIP 2028: transaction gas lowered from 68 to 16 (#10987)
* EIP-1344 Add CHAINID op-code (#10983)
* manual publish jobs for releases, no changes for nightlies (#10977)
* [blooms-db] Fix benchmarks (#10974)
* Verify transaction against its block during import (#10954)
* Better error message for rpc gas price errors (#10931)
* tx-pool: accept local tx with higher gas price when pool full (#10901)
* Fix fork choice (#10837)
* Cleanup unused vm dependencies (#10787)
* Fix compilation on recent nightlies (#10991)
2019-09-12 18:43:53 +02:00
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
530 changed files with 13132 additions and 11723 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

@@ -13,10 +13,6 @@ variables:
SCCACHE_DIR: "/ci-cache/${CI_PROJECT_NAME}/sccache"
CARGO_TARGET: x86_64-unknown-linux-gnu
.no_git: &no_git # disable git strategy
variables:
GIT_STRATEGY: none
GIT_SUBMODULE_STRATEGY: none
.releaseable_branches: # list of git refs for building GitLab artifacts (think "pre-release binaries")
only: &releaseable_branches
@@ -153,7 +149,7 @@ build-android:
build-linux:
<<: *build-on-linux
only: *releaseable_branches
# only: *releaseable_branches
build-linux-i386:
<<: *build-on-linux
@@ -205,11 +201,10 @@ build-windows:
publish-docker:
stage: publish
<<: *no_git
only: *releaseable_branches
except:
variables:
- $SCHEDULE_TAG == "nightly"
- nightly
when: manual
dependencies:
- build-linux
environment:
@@ -219,23 +214,24 @@ publish-docker:
services:
- docker:dind
variables:
GIT_STRATEGY: none
DOCKER_HOST: tcp://localhost:2375
DOCKER_DRIVER: overlay2
GIT_STRATEGY: none
# DOCKERFILE: tools/Dockerfile
# CONTAINER_IMAGE: parity/parity
script:
# we stopped pushing nightlies to dockerhub, will push to own registry prb.
- ./tools/publish-docker.sh
tags:
- kubernetes-parity-build
publish-snap: &publish-snap
publish-snap-nightly: &publish-snap
stage: publish
<<: *no_git
only: *releaseable_branches
only:
- nightly
image: snapcore/snapcraft
variables:
GIT_STRATEGY: none
BUILD_ARCH: amd64
cache: {}
dependencies:
@@ -245,7 +241,12 @@ publish-snap: &publish-snap
script:
- ./tools/publish-snap.sh
publish-snap-i386:
publish-snap-manually:
<<: *publish-snap
only: *releaseable_branches
when: manual
publish-snap-i386-nightly: &publish-snap-i386
<<: *publish-snap
variables:
BUILD_ARCH: i386
@@ -253,7 +254,12 @@ publish-snap-i386:
dependencies:
- build-linux-i386
publish-snap-arm64:
publish-snap-i386-manually:
<<: *publish-snap-i386
only: *releaseable_branches
when: manual
publish-snap-arm64-nightly: &publish-snap-arm64
<<: *publish-snap
variables:
BUILD_ARCH: arm64
@@ -261,7 +267,12 @@ publish-snap-arm64:
dependencies:
- build-linux-arm64
publish-snap-armhf:
publish-snap-arm64-manually:
<<: *publish-snap-arm64
only: *releaseable_branches
when: manual
publish-snap-armhf-nightly: &publish-snap-armhf
<<: *publish-snap
variables:
BUILD_ARCH: armhf
@@ -269,11 +280,18 @@ publish-snap-armhf:
dependencies:
- build-linux-armhf
publish-onchain:
stage: publish
<<: *no_git
publish-snap-armhf-manually:
<<: *publish-snap-armhf
only: *releaseable_branches
when: manual
publish-onchain-nightly: &publish-onchain
stage: publish
only:
- nightly
cache: {}
variables:
GIT_STRATEGY: none
dependencies:
- build-linux
- build-darwin
@@ -283,11 +301,18 @@ publish-onchain:
tags:
- linux-docker
publish-awss3-release:
publish-onchain-manually:
<<: *publish-onchain
only: *releaseable_branches
when: manual
publish-release-awss3-nightly: &publish-release-awss3
image: parity/awscli:latest
stage: publish
only: *releaseable_branches
<<: *no_git
only:
- nightly
variables:
GIT_STRATEGY: none
cache: {}
dependencies:
- build-linux
@@ -309,6 +334,11 @@ publish-awss3-release:
tags:
- linux-docker
publish-release-awss3-manually:
<<: *publish-release-awss3
only: *releaseable_branches
when: manual
publish-docs:
stage: publish
image: parity/parity-ci-docs:latest
@@ -316,6 +346,7 @@ publish-docs:
- tags
except:
- nightly
when: manual
cache: {}
dependencies: []
script:
@@ -326,11 +357,12 @@ publish-docs:
publish-av-whitelist:
stage: publish
<<: *no_git
variables:
GIT_STRATEGY: none
only: *releaseable_branches
except:
variables:
- $SCHEDULE_TAG == "nightly"
- nightly
when: manual
cache: {}
dependencies:
- build-windows

View File

@@ -1,185 +1,139 @@
## Parity-Ethereum [v2.6.1](https://github.com/paritytech/parity-ethereum/releases/tag/v2.6.1)
## Parity-Ethereum [v2.5.9](https://github.com/paritytech/parity-ethereum/releases/tag/v2.5.8)
Parity-Ethereum 2.6.1-beta is a patch 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.
Parity Ethereum v2.5.9-stable is a patch release that adds the block numbers for activating the Istanbul hardfork on test networks: Ropsten, Görli, Rinkeby and Kovan.
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)
* ethcore/res: activate Istanbul on Ropsten, Görli, Rinkeby, Kovan (#11068)
* [json-spec] make blake2 pricing spec more readable (#11034)
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.8](https://github.com/paritytech/parity-ethereum/releases/tag/v2.5.8)
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.8-stable is a patch release that improves security, stability and performance.
As of today, Parity-Ethereum 2.4 reaches end of life, and everyone is
encouraged to upgrade.
* The most noteworthy improvement in this release is incorporating all the EIPs required for the Istanbul hard fork.
* This release also fixes certain security and performance issues, one of which was suspected to be consensus-threatening but turned out to be benign. Thanks to Martin Holst Swende and Felix Lange from the Ethereum Foundation for bringing the suspicious issue to our attention.
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))
* add more tx tests (#11038)
* Fix parallel transactions race-condition (#10995)
* Add blake2_f precompile (#11017)
* [trace] introduce trace failed to Ext (#11019)
* Edit publish-onchain.sh to use https (#11016)
* Fix deadlock in network-devp2p (#11013)
* EIP 1108: Reduce alt_bn128 precompile gas costs (#11008)
* xDai chain support and nodes list update (#10989)
* EIP 2028: transaction gas lowered from 68 to 16 (#10987)
* EIP-1344 Add CHAINID op-code (#10983)
* manual publish jobs for releases, no changes for nightlies (#10977)
* [blooms-db] Fix benchmarks (#10974)
* Verify transaction against its block during import (#10954)
* Better error message for rpc gas price errors (#10931)
* tx-pool: accept local tx with higher gas price when pool full (#10901)
* Fix fork choice (#10837)
* Cleanup unused vm dependencies (#10787)
* Fix compilation on recent nightlies (#10991)
* Don't build rpc with ethcore test-helpers (#11048)
* EIP 1884 Re-pricing of trie-size dependent operations (#10992)
* Implement EIP-1283 reenable transition, EIP-1706 and EIP-2200 (#10191)
## Parity-Ethereum [v2.5.7](https://github.com/paritytech/parity-ethereum/releases/tag/v2.5.7)
Parity Ethereum v2.5.7-stable is a bugfix release that fixes a potential DoS attack in the trace_call RPC method. This is a critical upgrade for anyone running Parity nodes with RPC exposed to the public internet (and highly recommended for anyone else). For details see this blog post.
## Parity-Ethereum [v2.5.6](https://github.com/paritytech/parity-ethereum/releases/tag/v2.5.6)
Parity-Ethereum v2.5.6-stable is a bugfix release that improves stability.
* Allow specifying hostnames for node URLs
* Fix a bug where archive nodes were losing peers
The full list of included changes:
* 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 [v2.5.5](https://github.com/paritytech/parity-ethereum/releases/tag/v2.5.5)
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.
## 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:
* 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)

1768
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.9"
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"
memzero = { path = "../../util/memzero" }
parity-wordlist = "1.3"
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

@@ -9,7 +9,7 @@ docopt = "1.0"
env_logger = "0.5"
ethkey = { path = "../" }
panic_hook = { path = "../../../util/panic-hook" }
parity-wordlist="1.2"
parity-wordlist="1.3"
rustc-hex = "1.0"
serde = "1.0"
serde_derive = "1.0"

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"
parity-wordlist = "1.3"
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,18 @@ 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"
eip-152 = { version = "0.1", path = "../util/EIP-152" }
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 +27,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 +46,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 +71,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" }
@@ -81,12 +78,12 @@ criterion = "0.2"
env_logger = "0.5"
ethcore-accounts = { path = "../accounts" }
fetch = { path = "../util/fetch" }
hex-literal = "0.2.1"
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

@@ -12,22 +12,24 @@ ansi_term = "0.11"
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"
keccak-hash = "0.1"
kvdb = "0.1"
log = "0.4"
parity-bytes = "0.1"
parking_lot = "0.7"
rand = "0.6"
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" }
triehash-ethereum = { version = "0.2", path = "../../util/triehash-ethereum" }
[dev-dependencies]
env_logger = "0.5"
ethkey = { path = "../../accounts/ethkey" }
keccak-hash = "0.2.0"
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,
});
}
}
@@ -710,6 +713,10 @@ impl BlockChain {
///
/// If the tree route verges into pruned or unknown blocks,
/// `None` is returned.
///
/// `is_from_route_finalized` returns whether the `from` part of the
/// route contains a finalized block. This only holds if the two parts (from
/// and to) are on different branches, ie. on 2 different forks.
pub fn tree_route(&self, from: H256, to: H256) -> Option<TreeRoute> {
let mut from_branch = vec![];
let mut is_from_route_finalized = false;
@@ -723,9 +730,9 @@ impl BlockChain {
// reset from && to to the same level
while from_details.number > to_details.number {
from_branch.push(current_from);
is_from_route_finalized = is_from_route_finalized || from_details.is_finalized;
current_from = from_details.parent.clone();
from_details = self.block_details(&from_details.parent)?;
is_from_route_finalized = is_from_route_finalized || from_details.is_finalized;
}
while to_details.number > from_details.number {
@@ -739,9 +746,9 @@ impl BlockChain {
// move to shared parent
while current_from != current_to {
from_branch.push(current_from);
is_from_route_finalized = is_from_route_finalized || from_details.is_finalized;
current_from = from_details.parent.clone();
from_details = self.block_details(&from_details.parent)?;
is_from_route_finalized = is_from_route_finalized || from_details.is_finalized;
to_branch.push(current_to);
current_to = to_details.parent.clone();
@@ -755,8 +762,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 +792,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 +936,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 +967,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 +992,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 +1004,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 +1076,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 +1176,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 +1263,7 @@ impl BlockChain {
current: if self.is_known(&first) {
first
} else {
H256::zero() // zero hash
H256::default() // zero hash
},
chain: self
}
@@ -1486,12 +1479,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 +1518,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 +1575,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 +1599,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 +1614,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 +1633,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 +2061,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 +2134,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 +2143,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 +2152,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 +2162,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 +2241,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 +2309,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);
@@ -2503,4 +2495,74 @@ mod tests {
assert_eq!(bc.epoch_transition_for(fork_hash).unwrap().block_number, 0);
}
}
#[test]
fn tree_rout_with_finalization() {
let genesis = BlockBuilder::genesis();
let a = genesis.add_block();
// First branch
let a1 = a.add_block_with_random_transactions();
let a2 = a1.add_block_with_random_transactions();
let a3 = a2.add_block_with_random_transactions();
// Second branch
let b1 = a.add_block_with_random_transactions();
let b2 = b1.add_block_with_random_transactions();
let a_hash = a.last().hash();
let a1_hash = a1.last().hash();
let a2_hash = a2.last().hash();
let a3_hash = a3.last().hash();
let b2_hash = b2.last().hash();
let bootstrap_chain = |blocks: Vec<&BlockBuilder>| {
let db = new_db();
let bc = new_chain(genesis.last().encoded(), db.clone());
let mut batch = db.key_value().transaction();
for block in blocks {
insert_block_batch(&mut batch, &bc, block.last().encoded(), vec![]);
bc.commit();
}
db.key_value().write(batch).unwrap();
(db, bc)
};
let mark_finalized = |block_hash: H256, db: &Arc<dyn BlockChainDB>, bc: &BlockChain| {
let mut batch = db.key_value().transaction();
bc.mark_finalized(&mut batch, block_hash).unwrap();
bc.commit();
db.key_value().write(batch).unwrap();
};
// Case 1: fork, with finalized common ancestor
{
let (db, bc) = bootstrap_chain(vec![&a, &a1, &a2, &a3, &b1, &b2]);
assert_eq!(bc.best_block_hash(), a3_hash);
assert_eq!(bc.block_hash(2).unwrap(), a1_hash);
mark_finalized(a_hash, &db, &bc);
assert!(!bc.tree_route(a3_hash, b2_hash).unwrap().is_from_route_finalized);
assert!(!bc.tree_route(b2_hash, a3_hash).unwrap().is_from_route_finalized);
}
// Case 2: fork with a finalized block on a branch
{
let (db, bc) = bootstrap_chain(vec![&a, &a1, &a2, &a3, &b1, &b2]);
assert_eq!(bc.best_block_hash(), a3_hash);
assert_eq!(bc.block_hash(2).unwrap(), a1_hash);
mark_finalized(a2_hash, &db, &bc);
assert!(bc.tree_route(a3_hash, b2_hash).unwrap().is_from_route_finalized);
assert!(!bc.tree_route(b2_hash, a3_hash).unwrap().is_from_route_finalized);
}
// Case 3: no-fork, with a finalized block
{
let (db, bc) = bootstrap_chain(vec![&a, &a1, &a2]);
assert_eq!(bc.best_block_hash(), a2_hash);
mark_finalized(a1_hash, &db, &bc);
assert!(!bc.tree_route(a1_hash, a2_hash).unwrap().is_from_route_finalized);
assert!(!bc.tree_route(a2_hash, a1_hash).unwrap().is_from_route_finalized);
}
}
}

View File

@@ -21,11 +21,13 @@ use ethereum_types::{U256, H256, Bloom};
use common_types::encoded;
use common_types::header::Header;
use common_types::transaction::SignedTransaction;
use common_types::transaction::{SignedTransaction, Transaction, Action};
use common_types::view;
use common_types::views::BlockView;
use keccak_hash::keccak;
use rlp::encode;
use rlp_derive::RlpEncodable;
use triehash_ethereum::ordered_trie_root;
/// Helper structure, used for encoding blocks.
#[derive(Default, Clone, RlpEncodable)]
@@ -136,6 +138,29 @@ impl BlockBuilder {
})
}
/// Add a block with randomly generated transactions.
#[inline]
pub fn add_block_with_random_transactions(&self) -> Self {
// Maximum of ~50 transactions
let count = rand::random::<u8>() as usize / 5;
let transactions = std::iter::repeat_with(|| {
let data_len = rand::random::<u8>();
let data = std::iter::repeat_with(|| rand::random::<u8>())
.take(data_len as usize)
.collect::<Vec<_>>();
Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 100_000.into(),
action: Action::Create,
value: 100.into(),
data,
}.sign(&keccak("").into(), None)
}).take(count);
self.add_block_with_transactions(transactions)
}
/// Add a block with given transactions.
#[inline]
pub fn add_block_with_transactions<T>(&self, transactions: T) -> Self
@@ -166,11 +191,15 @@ impl BlockBuilder {
let mut block = Block::default();
let metadata = get_metadata();
let block_number = parent_number + 1;
let transactions = metadata.transactions;
let transactions_root = ordered_trie_root(transactions.iter().map(rlp::encode));
block.header.set_parent_hash(parent_hash);
block.header.set_number(block_number);
block.header.set_log_bloom(metadata.bloom);
block.header.set_difficulty(metadata.difficulty);
block.transactions = metadata.transactions;
block.header.set_transactions_root(transactions_root);
block.transactions = transactions;
parent_hash = block.hash();
parent_number = block_number;

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,18 +7,20 @@ 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"
criterion = "0.2"
hex-literal = "0.2.0"
[features]
evm-debug = []

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

@@ -44,12 +44,18 @@ pub trait Finalize {
impl Finalize for Result<GasLeft> {
fn finalize<E: Ext>(self, ext: E) -> Result<FinalizationResult> {
match self {
Ok(GasLeft::Known(gas_left)) => Ok(FinalizationResult { gas_left: gas_left, apply_state: true, return_data: ReturnData::empty() }),
Ok(GasLeft::NeedsReturn { gas_left, data, apply_state }) => ext.ret(&gas_left, &data, apply_state).map(|gas_left| FinalizationResult {
gas_left: gas_left,
apply_state: apply_state,
return_data: data,
}),
Ok(GasLeft::Known(gas_left)) => {
Ok(FinalizationResult {
gas_left,
apply_state: true,
return_data: ReturnData::empty()
})
},
Ok(GasLeft::NeedsReturn { gas_left, data, apply_state }) => {
ext.ret(&gas_left, &data, apply_state).map(|gas_left|
FinalizationResult { gas_left, apply_state, return_data: data }
)
},
Err(err) => Err(err),
}
}

View File

@@ -47,7 +47,7 @@ impl Factory {
/// for caching jump destinations.
pub fn new(evm: VMType, cache_size: usize) -> Self {
Factory {
evm: evm,
evm,
evm_cache: Arc::new(SharedCache::new(cache_size)),
}
}

View File

@@ -149,6 +149,10 @@ enum_with_from_u8! {
DIFFICULTY = 0x44,
#[doc = "get the block's gas limit"]
GASLIMIT = 0x45,
#[doc = "get chain ID"]
CHAINID = 0x46,
#[doc = "get balance of own account"]
SELFBALANCE = 0x47,
#[doc = "remove item from stack"]
POP = 0x50,
@@ -442,12 +446,7 @@ pub struct InstructionInfo {
impl InstructionInfo {
/// Create new instruction info.
pub fn new(name: &'static str, args: usize, ret: usize, tier: GasPriceTier) -> Self {
InstructionInfo {
name: name,
args: args,
ret: ret,
tier: tier
}
InstructionInfo { name, args, ret, tier }
}
}
@@ -504,6 +503,8 @@ lazy_static! {
arr[NUMBER as usize] = Some(InstructionInfo::new("NUMBER", 0, 1, GasPriceTier::Base));
arr[DIFFICULTY as usize] = Some(InstructionInfo::new("DIFFICULTY", 0, 1, GasPriceTier::Base));
arr[GASLIMIT as usize] = Some(InstructionInfo::new("GASLIMIT", 0, 1, GasPriceTier::Base));
arr[CHAINID as usize] = Some(InstructionInfo::new("CHAINID", 0, 1, GasPriceTier::Base));
arr[SELFBALANCE as usize] = Some(InstructionInfo::new("SELFBALANCE", 0, 1, GasPriceTier::Low));
arr[POP as usize] = Some(InstructionInfo::new("POP", 1, 0, GasPriceTier::Base));
arr[MLOAD as usize] = Some(InstructionInfo::new("MLOAD", 1, 1, GasPriceTier::VeryLow));
arr[MSTORE as usize] = Some(InstructionInfo::new("MSTORE", 2, 0, GasPriceTier::VeryLow));

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,15 @@ impl<Gas: evm::CostType> Gasometer<Gas> {
Request::Gas(Gas::from(1))
},
instructions::SSTORE => {
let address = BigEndianHash::from_uint(stack.peek(0));
if schedule.eip1706 && self.current_gas <= Gas::from(schedule.call_stipend) {
return Err(vm::Error::OutOfGas);
}
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,
@@ -276,6 +286,8 @@ impl<Cost: CostType> Interpreter<Cost> {
cache, params, reader, informant,
valid_jump_destinations, gasometer, stack,
done: false,
// Overridden in `step_inner` based on
// the result of `ext.trace_next_instruction`.
do_trace: true,
mem: Vec::new(),
return_data: ReturnData::empty(),
@@ -296,7 +308,12 @@ impl<Cost: CostType> Interpreter<Cost> {
let result = if self.gasometer.is_none() {
InterpreterResult::Done(Err(vm::Error::OutOfGas))
} 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())))
let current_gas = self.gasometer
.as_ref()
.expect("Gasometer None case is checked above; qed")
.current_gas
.as_u256();
InterpreterResult::Done(Ok(GasLeft::Known(current_gas)))
} else {
self.step_inner(ext)
};
@@ -305,7 +322,7 @@ impl<Cost: CostType> Interpreter<Cost> {
self.done = true;
self.informant.done();
}
return result;
result
}
/// Inner helper function for step.
@@ -345,6 +362,9 @@ impl<Cost: CostType> Interpreter<Cost> {
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) {
if self.do_trace {
ext.trace_failed();
}
return InterpreterResult::Done(Err(e));
}
self.mem.expand(requirements.memory_required_size);
@@ -358,7 +378,12 @@ impl<Cost: CostType> Interpreter<Cost> {
let result = match self.exec_instruction(
current_gas, ext, instruction, requirements.provide_gas
) {
Err(x) => return InterpreterResult::Done(Err(x)),
Err(x) => {
if self.do_trace {
ext.trace_failed();
}
return InterpreterResult::Done(Err(x));
},
Ok(x) => x,
};
evm_debug!({ self.informant.after_instruction(instruction) });
@@ -425,7 +450,9 @@ impl<Cost: CostType> Interpreter<Cost> {
((instruction == instructions::RETURNDATACOPY || instruction == instructions::RETURNDATASIZE) && !schedule.have_return_data) ||
(instruction == instructions::REVERT && !schedule.have_revert) ||
((instruction == instructions::SHL || instruction == instructions::SHR || instruction == instructions::SAR) && !schedule.have_bitwise_shifting) ||
(instruction == instructions::EXTCODEHASH && !schedule.have_extcodehash)
(instruction == instructions::EXTCODEHASH && !schedule.have_extcodehash) ||
(instruction == instructions::CHAINID && !schedule.have_chain_id) ||
(instruction == instructions::SELFBALANCE && !schedule.have_selfbalance)
{
return Err(vm::Error::BadInstruction {
instruction: instruction as u8
@@ -512,7 +539,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 +696,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 +733,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 +755,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 +816,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 +850,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()));
@@ -840,6 +867,12 @@ impl<Cost: CostType> Interpreter<Cost> {
instructions::GASLIMIT => {
self.stack.push(ext.env_info().gas_limit.clone());
},
instructions::CHAINID => {
self.stack.push(ext.chain_id().into())
},
instructions::SELFBALANCE => {
self.stack.push(ext.balance(&self.params.address)?);
}
// Stack instructions
@@ -1013,12 +1046,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 +1062,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 +1207,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 +1223,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 +1233,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 +1256,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;
@@ -33,6 +34,8 @@ extern crate log;
#[cfg(test)]
extern crate rustc_hex;
#[cfg(test)]
extern crate hex_literal;
pub mod evm;
pub mod interpreter;

View File

@@ -25,6 +25,7 @@ use vm::{self, ActionParams, ActionValue, Ext};
use vm::tests::{FakeExt, FakeCall, FakeCallType, test_finalize};
use factory::Factory;
use vmtype::VMType;
use hex_literal::hex;
evm_test!{test_add: test_add_int}
fn test_add(factory: super::Factory) {
@@ -108,6 +109,32 @@ fn test_origin(factory: super::Factory) {
assert_store(&ext, 0, "000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681");
}
evm_test!{test_selfbalance: test_selfbalance_int}
fn test_selfbalance(factory: super::Factory) {
let own_addr = Address::from_str("1337000000000000000000000000000000000000").unwrap();
// 47 SELFBALANCE
// 60 ff PUSH ff
// 55 SSTORE
let code = hex!("47 60 ff 55").to_vec();
let mut params = ActionParams::default();
params.address = own_addr.clone();
params.gas = U256::from(100_000);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new_istanbul();
ext.balances = {
let mut x = HashMap::new();
x.insert(own_addr, U256::from(1_025)); // 0x401
x
};
let gas_left = {
let vm = factory.create(params, ext.schedule(), ext.depth());
test_finalize(vm.exec(&mut ext).ok().unwrap()).unwrap()
};
assert_eq!(gas_left, U256::from(79_992)); // TODO[dvdplm]: do the sums here, SELFBALANCE-5 + PUSH1-3 + ONEBYTE-4 + SSTORE-?? = 100_000 - 79_992
assert_store(&ext, 0xff, "0000000000000000000000000000000000000000000000000000000000000401");
}
evm_test!{test_sender: test_sender_int}
fn test_sender(factory: super::Factory) {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
@@ -130,6 +157,27 @@ fn test_sender(factory: super::Factory) {
assert_store(&ext, 0, "000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681");
}
evm_test!{test_chain_id: test_chain_id_int}
fn test_chain_id(factory: super::Factory) {
// 46 CHAINID
// 60 00 PUSH 0
// 55 SSTORE
let code = hex!("46 60 00 55").to_vec();
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new_istanbul().with_chain_id(9);
let gas_left = {
let vm = factory.create(params, ext.schedule(), ext.depth());
test_finalize(vm.exec(&mut ext).ok().unwrap()).unwrap()
};
assert_eq!(gas_left, U256::from(79_995));
assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000009");
}
evm_test!{test_extcodecopy: test_extcodecopy_int}
fn test_extcodecopy(factory: super::Factory) {
// 33 - sender
@@ -239,7 +287,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}
@@ -262,7 +310,6 @@ fn test_calldataload(factory: super::Factory) {
assert_eq!(gas_left, U256::from(79_991));
assert_store(&ext, 0, "23ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff23");
}
evm_test!{test_author: test_author_int}
@@ -726,8 +773,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 +819,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 +1113,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,36 +8,35 @@ 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"
transaction-pool = "2.0.1"
url = "1"
[dev-dependencies]

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)
}

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