Compare commits

..

384 Commits

Author SHA1 Message Date
rakita
15b5581894 Set alpine version to 3.12.3 (#231)
Alpine version is changed in order to prevent Cmake errors. Reference: https://gitlab.alpinelinux.org/alpine/aports/-/issues/12321.

Intends to solve https://github.com/openethereum/openethereum/issues/230

Co-authored-by: Denis Granha <denis@gnosis.pm>
2021-01-19 12:36:10 +01:00
draganrakita
05ac033907 Bump to 3.1.1 2021-01-18 22:43:19 +01:00
rakita
cbf0b00c1d Added additional Sg-1,Ca-2,Ca-3 OE bootnodes (#222) 2021-01-18 22:43:19 +01:00
draganrakita
71bc62609e cicd fix v2 2020-12-21 16:13:17 +01:00
draganrakita
7336511246 cicd fix 2020-12-21 12:28:58 +01:00
draganrakita
eb9041691e Disable windows2019, remove tagged windows artifact 2020-12-21 10:49:00 +01:00
rakita
51d8ac4219 Revert "Fix CI problems (#127)" and Remove sscache (#181)
This reverts commit 12afb13e9b.
2020-12-18 09:28:05 +01:00
draganrakita
64eb48ef39 Bump to 3.1.1-rc.1 2020-12-15 17:22:03 +01:00
draganrakita
0138e5c71f Tweaks in informer log 2020-12-15 17:21:41 +01:00
adria0.eth
cf76d41bf4 Update ISSUE_TEMPLATE.md (#124)
Tell users to ask questions in discord instead of opening an issue.
2020-12-15 11:43:22 +01:00
Giacomo
2161bff690 Add custom windows runner (#162) 2020-12-15 11:43:22 +01:00
rakita
07a7281e26 Ancient target set. InvalidStateRoot bug (#69) (#149) 2020-12-15 11:43:22 +01:00
rakita
fb975731bb TypedTransaction (EIP-2718) and Optional access list (EIP-2930) (#135) 2020-12-15 11:43:22 +01:00
rakita
1bce9fa76d Fix broken doc comments (#151) 2020-12-15 11:43:21 +01:00
rakita
8f794afdb5 Add ws-max-paxload (#155) 2020-12-15 11:43:21 +01:00
rakita
f9f536cd08 Trace comment on new block inclusion (#100) 2020-12-15 11:43:21 +01:00
rakita
bfb65140d2 Remove sscache (#138) 2020-12-15 11:43:21 +01:00
rakita
5e2cadd9c7 Add flag to disable storage output in openethereum-evm tool #97 (#115) 2020-12-15 11:43:21 +01:00
adria0.eth
12afb13e9b Fix CI problems (#127)
* Temporally Fix CI compilation
2020-12-15 11:43:21 +01:00
Adria Massanet
4435e6645c Update linked-hash-map to 0.5.3 2020-12-15 11:43:21 +01:00
Lachezar Lechev
90e5eeefb8 ethstore - remove unnecessary dir & tiny-keccak dependencies from the lib (#107)
* ethstore - remove unnecessary dir & tiny-keccak dependencies
2020-12-15 11:43:20 +01:00
Giacomo
c33d7fbb45 Fix deprecated set-env declaration (#106)
* Fix deprecated set-env declaration

* Fix add-path and set-env in install-sscache.ps1
2020-12-15 11:43:20 +01:00
Giacomo
3bbb647e5f Feature/improve dockerhub deployment (#98)
* Add docker deployment for Github actions

* Add docker specs for the release of tagged and latest versions, also add specs for nightly builds

Co-authored-by: Denis Granha <denis@gnosis.pm>
2020-12-15 11:43:20 +01:00
adria0.eth
007207d8ca EIP2565 impl (#82)
EIP2565 implementation
2020-12-15 11:43:20 +01:00
adria0.eth
c8aea223ec Downgrade sccache to 1.1.2 (#93) 2020-12-15 11:43:20 +01:00
adria0.eth
d52272983a EIP2929 with journaling + Yolov3 (#79) 2020-12-15 11:43:20 +01:00
rakita
905d76b436 Sync block verification (#74)
* Synchronize block verification
* max_round_blocks_to_import set to 1
* Fixed test that rely on 12block batches

Co-authored-by: adria0.eth <5526331+adria0@users.noreply.github.com>
2020-12-15 11:43:19 +01:00
Adria Massanet
e69d2009cf Update gitactions for dev branch, deprecate stable branch 2020-12-15 11:43:19 +01:00
varasev
a95b2de645 Add wasmDisableTransition spec option (#60)
* Add wasmDisableTransition spec option
2020-12-15 11:43:19 +01:00
adria0.eth
6ecc6ddcdf Fix warnings (#64) 2020-12-15 11:43:19 +01:00
rakita
6ecb66eff9 Change wiki links (#68) 2020-12-15 11:43:19 +01:00
Denis Granha
94a784bfe9 Add docker deployment for Github actions 2020-11-06 12:02:27 +01:00
draganrakita
2072341eca Bump to 3.1.0 2020-11-02 13:28:44 +01:00
Denis Granha
36d250a420 revert actions/cache to version 1.1.2 (#80) 2020-11-02 13:20:20 +01:00
rakita
6f7548f596 Use ubuntu-16.04 for glibc compatibility (#11888) (#73) 2020-11-02 13:20:07 +01:00
adria0.eth
1ccbe5cfd4 Update gitactions master->main (#72) 2020-11-02 13:19:11 +01:00
Denis Granha
a8242ffef9 fix CD env param 2020-11-02 13:18:50 +01:00
Giacomo
fb071acb09 Set AWS_REGION as a global env variable (#67) 2020-11-02 13:18:42 +01:00
adria0.eth
51817baecd Bump to 3.1rc1 (#58) 2020-09-25 10:49:22 +02:00
rakita
15ebc98877 Drain the transaction overlay (#11654) (#59) 2020-09-25 10:46:51 +02:00
claveros
b6a25ba30a Update CHANGELOG to 3.1 (#56)
* Update CHANGELOG.md

Backport 3.1 Changelog

* Update CHANGELOG.md

3.0.0, 3.0.1, 3.1 changelog

* Update CHANGELOG.md

* Update CHANGELOG.md

* Update CHANGELOG.md

* Update CHANGELOG.md

* Added 3.0.x changelog

Co-authored-by: draganrakita <dragan0rakita@gmail.com>
2020-09-24 17:36:53 +03:00
rakita
abceaf3832 fix migration check when version_db file does no exist (#57) 2020-09-23 19:57:52 +02:00
rakita
25c2f7e7fd Dont upgrade for old versions of DB (#54) 2020-09-23 13:49:25 +02:00
rakita
27a0142af1 OpenEthereum rebranding (#31) 2020-09-22 14:53:52 +02:00
adria0.eth
698fa6e8f6 Remove classic, kotti, mordor, expanse (#52) 2020-09-22 13:45:38 +02:00
rakita
ae312bcb01 Added bad block header hash for ropsten (#49)
* Added bad block header hash for ropsten
2020-09-22 13:29:03 +02:00
Artem Vorotnikov
d17ee979b8 Remove accounts bloom (#33) 2020-09-22 12:41:04 +02:00
draganrakita
4fb4ef6d24 Bump jsonrpc-* to v15 2020-09-21 16:11:29 +00:00
adria0.eth
1c82a0733f Implement eth/64, remove eth/62 (#46)
Co-authored-by: Artem Vorotnikov <artem@vorotnikov.me>
2020-09-21 14:48:14 +02:00
adria0.eth
b54ddd027d No snapshotting by default (#11814) 2020-09-15 17:51:49 +03:00
Artem Vorotnikov
61e56aba41 Update Ellaism chainspec 2020-09-15 17:34:51 +03:00
rakita
aecc6fc862 Prometheus, heavy memory calls removed (#27) 2020-09-14 16:08:57 +02:00
adria0.eth
dd38573a28 Update ethereum/tests 2020-09-10 09:04:14 +03:00
adria0.eth
c84d82580a Implement JSON test suite (#11801) 2020-09-10 05:54:38 +03:00
rakita
506cee52e8 Fix issues during block sync (#11265) 2020-09-10 05:54:37 +03:00
rakita
c58b52c21c verification: fix race same block (#11400) 2020-09-10 05:54:37 +03:00
adria0.eth
f8326b6e27 EIP-2537: Precompile for BLS12-381 curve operations (#11707) 2020-09-10 05:54:37 +03:00
Artem Vorotnikov
ea0c13c0a4 Remove private transactions 2020-09-10 05:54:37 +03:00
rakita
a8668b371c Remove GetNodeData 2020-09-10 05:54:36 +03:00
Artem Vorotnikov
32ea4d69a3 Remove IPFS integration (#11532) 2020-09-10 05:54:36 +03:00
Artem Vorotnikov
defd24c40e Remove updater 2020-09-10 05:54:36 +03:00
Artem Vorotnikov
194101ed00 Remove light client 2020-09-10 05:54:36 +03:00
Artem Vorotnikov
2ab8c72ce3 Correct internal par protocol nomenclature 2020-09-10 05:54:30 +03:00
Artem Vorotnikov
a75ba3620c Remove C and Java bindings (#11346) 2020-09-10 05:54:10 +03:00
Artem Vorotnikov
54afb33333 Remove whisper (#10855) 2020-09-10 05:53:41 +03:00
Artem Vorotnikov
3f42b6178f Remove security audit workflow for now 2020-09-10 05:53:41 +03:00
adria0.eth
1460f6cc27 EIP-2315: Simple Subroutines for the EVM (#11629) 2020-09-10 05:53:41 +03:00
Artem Vorotnikov
751210c963 Remove deprecated flags 2020-09-10 05:53:41 +03:00
Artem Vorotnikov
7dfa57999b Remove failing test 2020-09-10 05:53:41 +03:00
Artem Vorotnikov
11fb967c6a Remove support for hardware wallets (#10678) 2020-09-10 05:53:29 +03:00
Artem Vorotnikov
c270599a23 Fix warnings: other 2020-08-07 20:47:14 +03:00
adria0
412d0307cb Fix warnings: try/? in whisper 2020-08-07 20:47:14 +03:00
adria0
33b5b36f44 Fix warnings: single tuples 2020-08-07 20:47:14 +03:00
adria0
ef7a82835a Fix warnings: future name collisions 2020-08-07 20:47:14 +03:00
adria0
ac8f65dbbf Fix warnings: iter 2020-08-07 20:47:13 +03:00
adria0
725073a683 Fix warnings: docs 2020-08-07 20:47:13 +03:00
adria0
c5aed5bab1 Fix warnings: unnecessary mut 2020-08-07 20:47:13 +03:00
adria0
cacbf256fe Fix warnings: unused 2020-08-07 20:47:13 +03:00
adria0
0cd972326c Fix warnings: mem::uninitialized 2020-08-07 20:47:13 +03:00
adria0
239cf91594 Fix warnings: range patterns 2020-08-07 20:47:13 +03:00
adria0
1700873f48 Fix warnings: dyn 2020-08-07 20:47:12 +03:00
adria0
4adb44155d Update bootnodes 2020-08-07 20:47:12 +03:00
adria0
82b37bfa0d Add github actions 2020-08-07 20:47:12 +03:00
adria0
544725a018 Fix compilation errors 2020-08-07 20:47:12 +03:00
Artem Vorotnikov
26e253e554 Ignore reformat commit in git blame 2020-08-07 20:47:09 +03:00
Artem Vorotnikov
610d9baba4 Reformat the source code 2020-08-07 20:46:52 +03:00
s3krit
253ff3f37b Update version and changelog (#11360) 2019-12-31 00:47:57 +01:00
Tomasz Drwięga
54c2d6167f Make sure to not mark block header hash as invalid if only the body is wrong. (#11356)
* Patch invalid transaction root.

* Add raw hash to bad and include fix for uncles too.

* Fix submodules.
2019-12-30 13:15:11 -08:00
David
29ebddc64f V2.5.12 stable (#11336)
* Enable EIP-2384 for ice age hard fork (#11281)
* ethcore/res: activate agharta on classic 9573000 (#11331)
* Istanbul HF in xDai (2019-12-12) (#11299)
* Istanbul HF in POA Core (2019-12-19) (#11298)
* Istanbul HF in POA Sokol (2019-12-05) (#11282)
* Activate ecip-1061 on kotti and mordor (#11338)
* Enable basic verification of local transactions (#11332)
* Disallow EIP-86 style null signatures for transactions outside tests (#11335)
2019-12-16 14:53:34 +01:00
Niklas Adolfsson
fc129b4a26 [stable backport]: add eip1344_transition for istanbul (#11301) (#11303)
* [chainspec]: add `eip1344_transition` for istanbul (#11301)

* Update version and CHANGELOG.md
2019-12-05 14:11:55 +01:00
s3krit
a071d81fe9 update CHANGELOG.md (#11263) 2019-11-14 17:42:49 +01:00
Denis S. Soldatov aka General-Beck
9f94473eaf sccache --stop-server -> sccache --show-stats (#11255) 2019-11-12 18:23:08 +01:00
s3krit
42437fbc57 fix windows libusb builds (#11251)
* fix libusb on Windows
2019-11-12 16:52:34 +01:00
Talha Cross
f3cdd7bf21 v2.5.10 stable (#11239)
* ropsten #6631425 foundation #8798209 (#11201)
* [stable] builtin, istanbul and mordor testnet backports (#11234)
  * ethcore-builtin (#10850)
  * [builtin]: support `multiple prices and activations` in chain spec (#11039)
  * [chain specs]: activate `Istanbul` on mainnet (#11228)
  * ethcore/res: add mordor testnet configuration (#11200)
* Update list of bootnodes for xDai chain (#11236)
* ethcore: remove `test-helper feat` from build (#11047)
* Secret store: fix Instant::now() related race in net_keep_alive (#11155) (#11159)
* [stable]: backport #10691 and #10683 (#11143)
  * Fix compiler warning (that will become an error) (#10683)
  * Refactor Clique stepping (#10691)
* Add Constantinople eips to the dev (instant_seal) config (#10809)
* Add cargo-remote dir to .gitignore (?)
* Insert explicit warning into the panic hook (#11225)
* Fix docker centos build (#11226)
* Update MIX bootnodes. (#11203)
* Use provided usd-per-eth value if an endpoint is specified (#11209)
* Add new line after writing block to hex file. (#10984)
* Type annotation for next_key() matching of json filter options (#11192) (but no `FilterOption` in 2.5 so…)
* Upgrade jsonrpc to latest (#11206)
* [CI] check evmbin build (#11096)
* Correct EIP-712 encoding (#11092)
* [client]: Fix for incorrectly dropped consensus messages (#11086)
* Fix block detail updating (#11015)
* Switching sccache from local to Redis (#10971)
* Made ecrecover implementation trait public (#11188)
* [dependencies]: jsonrpc `14.0.1` (#11183)
* [receipt]: add `sender` & `receiver` to `RichReceipts` (#11179)
* [ethcore/builtin]: do not panic in blake2pricer on short input (#11180)
* util Host: fix a double Read Lock bug in fn Host::session_readable() (#11175)
* ethcore client: fix a double Read Lock bug in fn Client::logs() (#11172)
* Change how RPCs eth_call and eth_estimateGas handle "Pending" (#11127)
* Cleanup stratum a bit (#11161)
* Upgrade to jsonrpc v14 (#11151)
* SecretStore: expose restore_key_public in HTTP API (#10241)
2019-11-11 21:57:38 +01:00
Niklas Adolfsson
5ee54b7298 [stable]: backports (#11114)
* [spec] fix rinkeby spec (#11108)

* use images from our registry (#11105)
2019-10-02 12:23:20 +02:00
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
Andrew Jones
d9673b0d6b tx-pool: check transaction readiness before replacing (#10526)
* Update to vanilla tx pool error

* Prevent a non ready tx replacing a ready tx

* Make tests compile

* Test ready tx not replaced by future tx

* Transaction indirection

* Use StateReadiness to calculate Ready in `should_replace`

* Test existing txs from same sender are used to compute Readiness

* private-tx: Wire up ShouldReplace

* Revert "Use StateReadiness to calculate Ready in `should_replace`"

This reverts commit af9e69c8

* Make replace generic so it works with private-tx

* Rename Replace and add missing docs

* ShouldReplace no longer mutable

* tx-pool: update to transaction-pool 2.0 from crates.io

* tx-pool: generic error type alias

* Exit early for first unmatching nonce

* Fix private-tx test, use existing write lock

* Use read lock for pool scoring
2019-04-01 10:48:51 +02:00
Niklas Adolfsson
89f828be1c fix(light account response): update tx_queue (#10545) 2019-03-31 11:54:19 +02:00
Thibaut Sardan
ec56b1f09d Update light client harcoded headers (#10547)
* kovan #10643457

* ropsten #5296129

* foundation #7460865

* classic #7747585

* indentation

* morden #3973121
2019-03-31 11:46:36 +02:00
Niklas Adolfsson
95236d25b2 fix(light eth_gasPrice): ask network if not in cache (#10535)
* fix(light eth_gasPrice): ask N/W if not in cache

* fix(bad rebase)
2019-03-31 10:40:33 +02:00
Vladyslav Lupashevskyi
7b2afdfc8c Implement caching for service transactions checker (#10088)
* Tx permission contract improvement

* Take in account zero gas price certification when doing transact_contract

* DRY in ServiceTransactionChecker

* Fix typos and regroup mod

* Introduce CertifiedAddressesCache

* Introduce refresh_cache for CertifiedAddressesCache

* Add CertifiedAddressesCache read and write on checking

* Refresh CertifiedAddressesCache on new imported block

* Separate ChainInfo trait and fix errors after merge

* Do not fire an error when service txes contract does not exist

* WIP: Shared certified addresses cache between miner and client + use HashMap instead of BTreeMap

* Refactor refresh_cache for ServiceTransactionChecker

* Refresh cache fixes

* Add cache read in check_address + log when cache is used + improve code

* Remove ChainInfo from ServiceTransaction dependencies

* DRY ServiceTransactionChecker

* Fix Client and Miner in tests

* Fix node_filter test

* Fix Client::new in add_peer_with_private_config

* WIP: Separated ChainNotify from ethcore trait and implemented ChainNotify for ServiceTransactionChecker

* Fix watcher test

* Revert "Merge branch 'master' into master"

This reverts commit 4e7371dc109d022efe3087defc33d827998ce648, reversing
changes made to bffd73e5fd58a516bbf404281b51cf26422e181e.

* Revert "Fix watcher test"

This reverts commit bffd73e5fd58a516bbf404281b51cf26422e181e.

* Revert "WIP: Separated ChainNotify from ethcore trait and implemented ChainNotify for ServiceTransactionChecker"

This reverts commit 6e73d1e61fa15dc10ffd4fab63df29eabe9c3b3a.

* Revert "Fix Client::new in add_peer_with_private_config"

This reverts commit ec610a30bee95588d58b79edcc9e43c2ff90f1ad.

* Revert "Fix node_filter test"

This reverts commit 06a4b2de86317c902f579e912b40de0b0fbf6d78.

* Revert "Fix Client and Miner in tests"

This reverts commit 51bbad330ea6e7bdfc1516208cc8705d5d11516d.

* Implement ServiceTransactionChecker in miner and delegate it to client + revert unnecessary changes

* Merge master

* Code improvements

* Merge branch 'master' of https://github.com/paritytech/parity-ethereum

# Conflicts:
#	Cargo.lock
#	ethcore/private-tx/src/lib.rs
#	ethcore/src/miner/miner.rs
#	ethcore/src/miner/pool_client.rs
2019-03-31 10:39:38 +02:00
TriplEight
440e52f410 build android with cache, win fixes (#10546)
* build android with cache!

* windows fixes

* windows fixes 2

* windows fixes 3

* windows fixes 4

* windows should have sccache variables in env variables
2019-03-30 20:29:08 +01:00
jwasinger
8840a293dd clique: make state backfill time measurement more accurate (#10551) 2019-03-30 20:28:32 +01:00
Marek Kotewicz
89d627769e updated lru-cache to 0.1.2 (#10542) 2019-03-29 12:25:15 +00:00
TriplEight
4e2e88a620 separate docker image to build docs (#10543) 2019-03-28 17:19:00 +01:00
Niklas Adolfsson
ebf51c0be0 fix(bump dependencies) (#10540)
* cargo update -p log:0.4.5

* cargo update -p regex:1.0.5

* cargo update -p parking_lot

* cargo update -p serde_derive

* cargo update -p serde_json

* cargo update -p serde

* cargo update -p lazy_static

* cargo update -p num_cpus

* cargo update -p toml
2019-03-28 15:31:06 +00:00
Wei Tang
04c6867660 Fix max_gas (#10537)
Fix max_gas
2019-03-27 15:53:06 -04:00
soc1c
0199acbece ethcore: remove eth social and easthub chain configs (#10531) 2019-03-27 15:07:38 +01:00
Denis S. Soldatov aka General-Beck
e4c2fe9e72 Initial support sccache for windows build (#10520)
* Initial support sccache for win build

* show sccache stats

* cache paths for shared runners

* sccache status is in the script.

* removed windows test for now
2019-03-27 14:47:08 +01:00
Niklas Adolfsson
407de5e8c4 fix(light): make OnDemand generic instead of using the concrete type (#10514)
* ethcore: add clique engine (#9981)

* fix broken sync

* correct seal fields

* ethcore: fix comment

* parity: remove duplicate params

* clique: fix whitespaces

* ethcore: fix goerli chain spec

* refactor signer_snapshot into pending/finalized state

* move close_block_extra_data after seal is applied

* refactor most of the logic into the signer_snapshot

* clique: refactor locking logic out of the consensus engine interface

* Fix jsonspec and add an unittest

* Replace space with tabs

* Unbroke sync

* Fix broken sync

* 1/2 state tracking without votes

* 2/2 implement vote tracking

* ci: use travis for goerli

* ci: setup a clique network

* ci: sync a görli node

* add clique deploy script

* ci: fix paths in clique deploy script

* ci: use docker compose

* ci: fix travis job names

* ci: fix build deps

* ci: massively reduce tests

* Revert "ci: massively reduce tests"

This reverts commit 6369f0b069ed2607a7e9f2e1d85489bacdc43384.

* ci: run cargo test directly

* ci: separate build and test stages

* ci: cache rust installation

* ci: simplify ci stages

* ci: make clique deploy script executable

* ci: shutdown goerli sync after 20min

* ci: remove slow sync stage

* ci: use timeout to finish jobs

* ci: fix build path

* ci: use absolute paths to end this confusion

* ci: add geth and parity to path

* ci: be more verbose

* ci: allow for more relaxed caching timeout

* ci: update repositories for custom ppa

* ci: fix typo in file name

* ci: fix docker compose file

* ci: add ethkey to docker

* ci: make sure deploy script is up to date with upstream

* ci: stop docker container after certain time

* ci: force superuser to update permissions on docker files

* ci: reduce run time of script to ~30 min

* ci: remove duplicate caching in travis

* remove trace statements

* clique: add more validation involving the recent signer list

* ethcore: enable constantinople for rinkeby

* ethcore: fix whitespaces in rinkeby spec

* ethcore: reformat goerli.json

* Revert "ci: remove duplicate caching in travis"

This reverts commit a562838d3d194d37f9871dcbe00b783637978f89.

* tmp commit

* another tmp commit

* it builds!

* add sealing capabilities

* add seal_header hook to allow separation of block seal/importing code paths

* clique: remove populate_from_parent.

* add panic

* make turn delay random

* initialize OpenBlock properly in 'enact'

* misc: remove duplicate lines

* misc: fix license headers

* misc: convert spaces to tabs

* misc: fix tabs

* Update Cargo.toml

* Update Cargo.toml

* Update Cargo.toml

* clique: ensure validator restores state before trying to seal

* clique: make 'state' return an Error.  Make some error messages more clear

* Fix compile error after rebase & toolchain upgrade

* fix a bunch of import warnings

* Refactor code

* Fix permissions

* Refactoring syncing

* Implement full validator checks

* Refactor util functions to seperate file

* mining 1

* ethcore: add chainspec for kotti

* ethcore: rename pre-goerli configs

* ethcore: load kotti chain spec

* cli: add kotti to params

* Implement working local sealing

* making sealing & syncing work together

* Relax timestamp checking

* ethcore: prepare for the real goerli to launch

* Implement NOTURN wiggle properly & cleanupnup warnings

* Implement vote casting

* Update docs & skip signing if no signer

* Optimize step-service interval

* Record state on local sealed block

* Fix script filemode

* Cleaning up codebase

* restore enact trace logging

* Delete clique.sh and move sync.sh

* remove travis.yml

* Remove dead code

* Cleanup compile warning

* address review comments

* adding more comments and removing unwrap()

* ci: remove sync script

* Address review comments

* fix compile error

* adding better debugging for timing

* Implement an dedicated thread for sealing timing

* fix(add helper for timestamp overflows) (#10330)

* fix(add helper timestamp overflows)

* fix(simplify code)

* fix(make helper private)

* snap: official image / test (#10168)

* official image / test

* fix / test

* bit more necromancy

* fix paths

* add source bin/df /test

* add source bin/df /test2

* something w paths /test

* something w paths /test

* add source-type /test

* show paths /test

* copy plugin /test

* plugin -> nil

* install rhash

* no questions while installing rhash

* publish snap only for release

* fix(docker): fix not receives SIGINT (#10059)

* fix(docker): fix not receives SIGINT

* fix: update with reviews

* update with review

* update

* update

* Don't add discovery initiators to the node table (#10305)

* Don't add discovery initiators to the node table

* Use enums for tracking state of the nodes in discovery

* Dont try to ping ourselves

* Fix minor nits

* Update timeouts when observing an outdated node

* Extracted update_bucket_record from update_node

* Fixed typo

* Fix two final nits from @todr

* change docker image based on debian instead of ubuntu due to the chan… (#10336)

* change docker image based on debian instead of ubuntu due to the changes of the build container

* role back docker build image and docker deploy image to ubuntu:xenial based (#10338)

* Bundle protocol and packet_id together in chain sync (#10315)

Define a new `enum` where devp2p subprotocol packet ids (currently eth and par) are defined. Additionally provide functionality to query id value and protocol of a given id object.

* snap: prefix version and populate candidate channel (#10343)

* snap: populate candidate releases with beta snaps to avoid stale channel

* snap: prefix version with v*

* addressing review comments

* engine: fix copyright header

* scripts: restore permissions on sign command

* ethcore: enforce tabs

* ethcore: enforce tabs

* ethcore: enforce tabs

* addressing comments

* addressing comments

* addressing more comments

* addressing more comments

* addressing more comments

* addressing more comments

* addressing more comments

* json-spec: fix clique epoch to non-zero u64

* ci: enable travis for parity goerli

* ci: don't separate build and test step

* ci: don't run c++ tests on travis

* ci: simplify cargo test to squeeze into travis timeout

* ci: don't run tests on travis at all

* style(fixes)

* fix(add tests)

* fix(recent_signer bug)

* fix(complete all tests)

* fix(nits)

* fix(simplify asserts)

* fix(cliqueState): simplify code

* fix(nits)

* docs(comments what's need to fixed)

* fix(revert unintended changes)

* fix(tests)

* fix(logs): voting logs

* fix(readability + more logs)

* fix(sync)

* docs(add missing licens header)

* fix(log): info! -> trace!

* docs(fix nits) + fix(remove assert)

* perf(use counter instead of vec)

* fix(remove needless block in match)

* fix(faulty comment)

* grumbles(docs for tests)

* fix(nits)

* fix(revert_vote): only remove vote when votes == 0

* fix(vote counter): checked arithmetics

* fix(simplify tests)

* fix(nits)

* fix(clique): err types

* fix(clique utils): make use of errors

* fix(cleanup nits)

* fix(clique sealing): don't read state no signer

* fix(replace Vec<Signers> with BTreeSet<Signers>)

* fix(tests): BTreeSet and more generic helpers

* fix(nits)

* fix(ethcore_block_seal): remove needless `Box`

* fix(faulty log): info -> trace

* fix(checked SystemTime): prevent SystemTime panics

* style(chain cfg): space after `:`

* style(fn enact): fix whitespace

* docs(clique): StepService

* docs(nit): fix faulty comment

* docs(fix typo)

* style(fix bad indentation)

* fix(bad regex match)

* grumble(on_seal_block): make `&mut` to avoid clone

* docs(on_seal_block): fix faulty documentation

* Delete .travis.yml

* docs: remove eth hf references in spec

* Update client.rs

* fix(nits)

* fix(clique step): `RwLock` -> `AtomicBool`

* fix(clique): use `Duration::as_millis`

* Clean up some Clique documentation

* Add trace information to eth_estimateGas (#10519)

* Add trace information to eth_estimateGas

* replace unwrap better version

* change vm::Error formatter to more user-friendly

* remove extra error format

* use map_or instead sequence of map/unwrap_or

* fix(light/on_demand): extract as a trait

* fix(grumble): OnDemand remove needless trait bound
2019-03-27 14:46:20 +01:00
Andrew Jones
7d26a82232 private-tx: replace error_chain (#10510)
* Update to vanilla tx pool error

* private-tx: remove error-chain, implement Error, derive Display

* private-tx: replace ErrorKind and bail!

* private-tx: add missing From impls and other compiler errors

* private-tx: use original tx-pool error

* Don't be silly cargo
2019-03-27 14:46:05 +01:00
Kirill Fomichev
3b23817936 Add trace information to eth_estimateGas (#10519)
* Add trace information to eth_estimateGas

* replace unwrap better version

* change vm::Error formatter to more user-friendly

* remove extra error format

* use map_or instead sequence of map/unwrap_or
2019-03-27 14:21:08 +01:00
5chdn
aa8487c1d0 ethcore: add clique engine (#9981)
* fix broken sync

* correct seal fields

* ethcore: fix comment

* parity: remove duplicate params

* clique: fix whitespaces

* ethcore: fix goerli chain spec

* refactor signer_snapshot into pending/finalized state

* move close_block_extra_data after seal is applied

* refactor most of the logic into the signer_snapshot

* clique: refactor locking logic out of the consensus engine interface

* Fix jsonspec and add an unittest

* Replace space with tabs

* Unbroke sync

* Fix broken sync

* 1/2 state tracking without votes

* 2/2 implement vote tracking

* ci: use travis for goerli

* ci: setup a clique network

* ci: sync a görli node

* add clique deploy script

* ci: fix paths in clique deploy script

* ci: use docker compose

* ci: fix travis job names

* ci: fix build deps

* ci: massively reduce tests

* Revert "ci: massively reduce tests"

This reverts commit 6369f0b069ed2607a7e9f2e1d85489bacdc43384.

* ci: run cargo test directly

* ci: separate build and test stages

* ci: cache rust installation

* ci: simplify ci stages

* ci: make clique deploy script executable

* ci: shutdown goerli sync after 20min

* ci: remove slow sync stage

* ci: use timeout to finish jobs

* ci: fix build path

* ci: use absolute paths to end this confusion

* ci: add geth and parity to path

* ci: be more verbose

* ci: allow for more relaxed caching timeout

* ci: update repositories for custom ppa

* ci: fix typo in file name

* ci: fix docker compose file

* ci: add ethkey to docker

* ci: make sure deploy script is up to date with upstream

* ci: stop docker container after certain time

* ci: force superuser to update permissions on docker files

* ci: reduce run time of script to ~30 min

* ci: remove duplicate caching in travis

* remove trace statements

* clique: add more validation involving the recent signer list

* ethcore: enable constantinople for rinkeby

* ethcore: fix whitespaces in rinkeby spec

* ethcore: reformat goerli.json

* Revert "ci: remove duplicate caching in travis"

This reverts commit a562838d3d194d37f9871dcbe00b783637978f89.

* tmp commit

* another tmp commit

* it builds!

* add sealing capabilities

* add seal_header hook to allow separation of block seal/importing code paths

* clique: remove populate_from_parent.

* add panic

* make turn delay random

* initialize OpenBlock properly in 'enact'

* misc: remove duplicate lines

* misc: fix license headers

* misc: convert spaces to tabs

* misc: fix tabs

* Update Cargo.toml

* Update Cargo.toml

* Update Cargo.toml

* clique: ensure validator restores state before trying to seal

* clique: make 'state' return an Error.  Make some error messages more clear

* Fix compile error after rebase & toolchain upgrade

* fix a bunch of import warnings

* Refactor code

* Fix permissions

* Refactoring syncing

* Implement full validator checks

* Refactor util functions to seperate file

* mining 1

* ethcore: add chainspec for kotti

* ethcore: rename pre-goerli configs

* ethcore: load kotti chain spec

* cli: add kotti to params

* Implement working local sealing

* making sealing & syncing work together

* Relax timestamp checking

* ethcore: prepare for the real goerli to launch

* Implement NOTURN wiggle properly & cleanupnup warnings

* Implement vote casting

* Update docs & skip signing if no signer

* Optimize step-service interval

* Record state on local sealed block

* Fix script filemode

* Cleaning up codebase

* restore enact trace logging

* Delete clique.sh and move sync.sh

* remove travis.yml

* Remove dead code

* Cleanup compile warning

* address review comments

* adding more comments and removing unwrap()

* ci: remove sync script

* Address review comments

* fix compile error

* adding better debugging for timing

* Implement an dedicated thread for sealing timing

* fix(add helper for timestamp overflows) (#10330)

* fix(add helper timestamp overflows)

* fix(simplify code)

* fix(make helper private)

* snap: official image / test (#10168)

* official image / test

* fix / test

* bit more necromancy

* fix paths

* add source bin/df /test

* add source bin/df /test2

* something w paths /test

* something w paths /test

* add source-type /test

* show paths /test

* copy plugin /test

* plugin -> nil

* install rhash

* no questions while installing rhash

* publish snap only for release

* fix(docker): fix not receives SIGINT (#10059)

* fix(docker): fix not receives SIGINT

* fix: update with reviews

* update with review

* update

* update

* Don't add discovery initiators to the node table (#10305)

* Don't add discovery initiators to the node table

* Use enums for tracking state of the nodes in discovery

* Dont try to ping ourselves

* Fix minor nits

* Update timeouts when observing an outdated node

* Extracted update_bucket_record from update_node

* Fixed typo

* Fix two final nits from @todr

* change docker image based on debian instead of ubuntu due to the chan… (#10336)

* change docker image based on debian instead of ubuntu due to the changes of the build container

* role back docker build image and docker deploy image to ubuntu:xenial based (#10338)

* Bundle protocol and packet_id together in chain sync (#10315)

Define a new `enum` where devp2p subprotocol packet ids (currently eth and par) are defined. Additionally provide functionality to query id value and protocol of a given id object.

* snap: prefix version and populate candidate channel (#10343)

* snap: populate candidate releases with beta snaps to avoid stale channel

* snap: prefix version with v*

* addressing review comments

* engine: fix copyright header

* scripts: restore permissions on sign command

* ethcore: enforce tabs

* ethcore: enforce tabs

* ethcore: enforce tabs

* addressing comments

* addressing comments

* addressing more comments

* addressing more comments

* addressing more comments

* addressing more comments

* addressing more comments

* json-spec: fix clique epoch to non-zero u64

* ci: enable travis for parity goerli

* ci: don't separate build and test step

* ci: don't run c++ tests on travis

* ci: simplify cargo test to squeeze into travis timeout

* ci: don't run tests on travis at all

* style(fixes)

* fix(add tests)

* fix(recent_signer bug)

* fix(complete all tests)

* fix(nits)

* fix(simplify asserts)

* fix(cliqueState): simplify code

* fix(nits)

* docs(comments what's need to fixed)

* fix(revert unintended changes)

* fix(tests)

* fix(logs): voting logs

* fix(readability + more logs)

* fix(sync)

* docs(add missing licens header)

* fix(log): info! -> trace!

* docs(fix nits) + fix(remove assert)

* perf(use counter instead of vec)

* fix(remove needless block in match)

* fix(faulty comment)

* grumbles(docs for tests)

* fix(nits)

* fix(revert_vote): only remove vote when votes == 0

* fix(vote counter): checked arithmetics

* fix(simplify tests)

* fix(nits)

* fix(clique): err types

* fix(clique utils): make use of errors

* fix(cleanup nits)

* fix(clique sealing): don't read state no signer

* fix(replace Vec<Signers> with BTreeSet<Signers>)

* fix(tests): BTreeSet and more generic helpers

* fix(nits)

* fix(ethcore_block_seal): remove needless `Box`

* fix(faulty log): info -> trace

* fix(checked SystemTime): prevent SystemTime panics

* style(chain cfg): space after `:`

* style(fn enact): fix whitespace

* docs(clique): StepService

* docs(nit): fix faulty comment

* docs(fix typo)

* style(fix bad indentation)

* fix(bad regex match)

* grumble(on_seal_block): make `&mut` to avoid clone

* docs(on_seal_block): fix faulty documentation

* Delete .travis.yml

* docs: remove eth hf references in spec

* Update client.rs

* fix(nits)

* fix(clique step): `RwLock` -> `AtomicBool`

* fix(clique): use `Duration::as_millis`

* Clean up some Clique documentation

Co-authored-by: soc1c <soc1c@users.noreply.github.com>
Co-authored-by: HCastano <HCastano@users.noreply.github.com>
Co-authored-by: niklasad1 <niklasad1@users.noreply.github.com>
Co-authored-by: jwasinger <jwasinger@users.noreply.github.com>
Co-authored-by: ChainSafe <ChainSafe@users.noreply.github.com>
Co-authored-by: thefallentree <thefallentree@users.noreply.github.com>
Co-authored-by: 5chdn <5chdn@users.noreply.github.com>
2019-03-27 14:13:24 +01:00
TriplEight
9cb8606103 verbose flag for cpp tests (#10524) 2019-03-26 12:37:45 +01:00
Hernando Castano
6cf3ba7efd Add a more realistic Batch test (#10511)
* Remove unrealistic tests

* Add test that more closely resembles real usage
2019-03-25 10:42:33 +01:00
Sočik
023e511f83 docs: add changelogs for 2.3.{6,7,8} and 2.4.{1,2,3} (#10494)
* docs: add changelogs for 2.3.{6,7} and 2.4.{1,2}

* docs: add changelogs for 2.4.3 beta and 2.3.8 stable

* Update docs/CHANGELOG-2.3.md

Co-Authored-By: soc1c <47772477+soc1c@users.noreply.github.com>

* Update docs/CHANGELOG-2.3.md

Co-Authored-By: soc1c <47772477+soc1c@users.noreply.github.com>

* docs: remove empty lines
2019-03-22 15:59:20 +01:00
Niklas Adolfsson
17042e9c32 fix(rpc): fix a bunch of clippy lints (#10493)
* fix(rpc): fix a bunch of clippy lints

* fix(rpc clippy): remove unused ignored lints

* fix(clippy): fix all redundant_field_names

This commit fixes all uses of `redundant_field_names` and removes the ignored lint `redundant_field_names`

* fix(brain unwrap): replace with expect
2019-03-22 12:01:11 +01:00
Denis S. Soldatov aka General-Beck
f2c34f7ca2 fix Sha3/keccak256 hash calculation for binaries (#10509)
https://github.com/paritytech/parity-ethereum/issues/10495
2019-03-22 11:46:57 +01:00
Hernando Castano
375a8daeb4 Add additional request tests (#10503) 2019-03-21 17:37:13 +01:00
Guillaume Ballet
b700ff3501 whisper/cli: add p2p port and ip parameters (#10057)
* whisper/cli: add p2p port and ip parameters

This is so that those params don't change randomly and are in sync with the URL that
is displayed.

* feedback: Result instead of panic

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

* feedback: Map error in port conversion

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

* whisper/cli: User can specify enode private key

So that the enode doesn't change at every run.

* whipser/cli: finish integrating review feedback.

* Accomodate error API change

* Update rustc-hex version in whisper/cli/Cargo.toml

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

* Update README with new whisper cli options

* Fix typo in error message

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

* Fix Cargo.lock and build issue after lib version upgrade

* Fix another typo

Co-Authored-By: gballet <gballet@gmail.com>
2019-03-21 17:45:02 +03:00
Niklas Adolfsson
9519493e32 fix(time-utils): add missing license (#10497) 2019-03-20 16:01:38 +01:00
Niklas Adolfsson
037fd1b309 fix(extract timestamp_checked_add as lib) (#10383)
* fix(extract `timestamp_checked_add` as lib)

* fix(whisper types): remove unused `EmptyTopics`

* fix(time-lib): feature-flag to use time-lib or std

This commit adds conditional compilation checks that falls back to `our time-lib` when
`time_checked_add` is not available in the standard library

Note, `time_checked_add` covers both `checked_add` and `checked_sub`

* fix(grumble): use cfg_attr to define rustc feature
2019-03-19 23:17:05 +01:00
Niklas Adolfsson
78a534633d fix(rpc): lint unused_extern_crates + fix warns (#10489) 2019-03-19 16:37:24 +01:00
Denis S. Soldatov aka General-Beck
effead9ba5 fix win&mac build (#10486)
add CARGO_HOME:                      "${CI_PROJECT_DIR}/.cargo"
2019-03-19 11:39:44 +01:00
TriplEight
a8ee3c97e6 Сaching through docker volume (#10477)
* _old codebase_ before docker update

* before docker update, testing runnr

* docker update, testing the caching

* distributed job cargo homes

* distributed job cargo homes 2

* distributed job cargo homes 3

* dockerfile with gitlab checkout, audit uses template

* dockerfile gets repo in volume

* change builds_dir

* trying docker cache for repo

* repo cached automatically

* after script is not concatenated

* check sccache non-cacheable reasons nature

* watch cache

* log sccache

* log sccache 2

* debug log sccache

* fix debug log sccache

* fix debug log sccache 2

* debug log cache 3

* debug log cache 3

* trace log all sccache

* test wo cargo cache

* test w removed cargo cache

* report non-cacheable reasons, cargo cache is back and empty

* report non-cacheable reasons, cargo cache is back and empty 2

* report non-cacheable reasons, cargo cache is back and empty 3

* wrap into after_script

* restore CI tags

`qa` -> `linux-docker`

* return to main runners, this will fail until config on runners And Dockerfile won't be updated

* typo fix CI lint

* return to docker tag
2019-03-19 03:14:59 +03:00
Marek Kotewicz
fb461659c7 OpenBlock::new take IntoIterator instead of mutable ref to Iterator (#10480) 2019-03-15 15:43:54 +01:00
Marek Kotewicz
a574df3132 simplify block module and usage (#10479)
* removed trait IsBlock and simplify block usage

* removed redundant ClosedBlock::hash function
2019-03-15 12:22:47 +00:00
Marek Kotewicz
d83143d0ba remove unused Engine::maximum_uncle_age (#10476) 2019-03-14 21:34:26 +01:00
Marek Kotewicz
f875175325 remove unused Engine::is_proposal (#10475) 2019-03-14 12:40:59 +00:00
Marek Kotewicz
c9db8ea21d further simplify machine (#10472)
* removed AuxiliaryRequest from Machin trait

* removed AncestryAction from Machine trait

* removed AuxiliaryData from Machine trait

* removed LocalizedMachine trait
2019-03-14 11:28:15 +01:00
Marek Kotewicz
a16bad4175 simplify parity machine (#10469)
* simplify ethcore machine by removing redundant traits

* further ethereum machine simplifications

* removed obsolete todo
2019-03-13 11:36:13 +01:00
Hernando Castano
595dac6c3f Ensure static validator set changes are recognized (#10467) 2019-03-12 19:16:29 +01:00
TriplEight
82a148a99b Tests parallelized (#10452)
* tests splitted, phase 1

* typo

* fix wrong launch commands

* typos

* rearrangements

* use `nproc` function for threads

* use nproc for threads

* let theads be auto, build-andriod no more in regular run

* split val chain and cargo check

* renamed some files

* wrong phase

* check rust files before test jobs

* lint error

* rust files modivied var

* test except changes

* add rust_changes except

* lint error

* fixes

* .gitlab-ci.yml can't be excluded

* pipeline shouldn't start

* pipeline must go

* pipeline must go 2

* pipeline must go 3

* pipeline must go 4

* pipeline must go 5

* pipeline must go 6

* pipeline must go 7

* pipeline must not go 1

* pipeline must go 8

* avoid skippng tests yet, reintroducing them after the caching

* test theory

* parallelized cargo check with combusting helicopters

* less uploads

* alias for cargo checks

* nice template
2019-03-11 15:26:35 +01:00
Niklas Adolfsson
4320c9bc4f docs(spec): remove link to obsolete issue (#10464) 2019-03-11 11:48:01 +01:00
Marek Kotewicz
23d977ecce simplify ethcore machine by removing redundant traits (#10454) 2019-03-11 10:37:48 +00:00
5chdn
ab27848dc4 docs: update changelogs for 2.2.{8,9,10,11}, 2.3.{1,2,3,4,5}, and 2.4.0 (#10389)
* docs: move changelog 2-3 to docs/

* docs: fix changelog 2-3 path

* docs: add changelogs for 2.2.{8,9,10,11}

* docs: add changelogs for 2.3.{1,2,3,4}

* Update CHANGELOG.md

* Update CHANGELOG-2.3.md

* Update CHANGELOG.md

* Update CHANGELOG.md
2019-03-07 21:11:58 +01:00
Denis S. Soldatov aka General-Beck
742a6007fe Revert "CI aws git checkout (#10451)" (#10456)
* Revert "CI aws git checkout (#10451)"

This reverts commit 3e1d73126c.

* Update .gitlab-ci.yml

revert aws script with small fixes

* Delete publish-aws.sh
2019-03-07 14:45:35 +03:00
Niklas Adolfsson
91933d857d perf(ethcore): micro-opt (#10405)
Mostly fixes that changes `eagerly eval` to `lazy eval`
2019-03-06 15:30:35 +01:00
Denis S. Soldatov aka General-Beck
3e1d73126c CI aws git checkout (#10451)
* Updating the CI system with the publication of releases and binary files on github

Signed-off-by: Denis S. Soldatov aka General-Beck <general.beck@gmail.com>

* move publish aws from gitlab.yml to gitlab scripts

Signed-off-by: Denis S. Soldatov aka General-Beck <general.beck@gmail.com>

* gitlab.yml cleaning
move publish AWS to gitlab scripts
remove dependencies from android build

Signed-off-by: Denis S. Soldatov aka General-Beck <general.beck@gmail.com>

* Revert "Updating the CI system with the publication of releases and binary files on github"

This reverts commit da87e06f2e4751dbca08a898b52926aef5ad0aba.

* remove no-git for aws

* microfix

* no need in no_git then
2019-03-05 18:33:10 +01:00
Axel Chalon
7014642815 Implement parity_versionInfo & parity_setChain on LC; fix parity_setChain (#10312)
* Light client: implement parity_versionInfo RPC

* Light client: implement set_exit_handler & parity_setChain RPC

* parity_setChain RPC: return an error if failed (instead of `true`)

* Implement eth_subscribe('syncing') RPC for full node & light node

* Fix indentation

* Revert commit: Implement eth_subscribe('syncing')

* Revert change to Cr callback function
2019-03-04 20:24:53 +01:00
Denis S. Soldatov aka General-Beck
1bd4564216 CI publish to aws (#10446)
* move publish aws from gitlab.yml to gitlab scripts

* gitlab.yml cleaning
move publish AWS to gitlab scripts
remove dependencies from android build
2019-03-04 21:59:20 +03:00
Andrew Jones
97cb010df8 Silence Error::cause deprecations (#10438) 2019-03-02 13:18:18 +01:00
Hernando Castano
ed18c7b54c Use correct name for documentation field in Cargo.toml (#10440) 2019-03-01 16:23:40 +00:00
Thibaut Sardan
e71598d876 Update hardcoded headers for Foundation, Ropsten, Kovan and Classic (#10417)
* update foundation to #7262209

* update kovan to #10434561

* update ropsten to #5027841

* update classic to #7555073

* Update Ropsten headers to #5101569
2019-02-27 15:50:45 +01:00
Marek Kotewicz
3d0ce10fa6 panic_hook module uses eprintln instead of raw stderr interface (#10426) 2019-02-27 09:48:40 +00:00
soc1c
cfc8df156b ci: clean up gitlab-ci.yml leftovers from previous merge (#10429) 2019-02-27 10:47:27 +01:00
Marek Kotewicz
94cb3b6e0e fix underflow in pip, closes #10419 (#10423) 2019-02-27 10:08:04 +01:00
Marek Kotewicz
fefec000fb remove redundant macro println_stderr from parity/cli/usage.rs (#10425) 2019-02-27 10:07:41 +01:00
Mohanson
c7ded6a785 Remove duplicate test cases (#10385)
Case create_account() is same as new_account()
2019-02-27 10:07:12 +01:00
Marek Kotewicz
2fbb952cdd parity/main.rs uses eprintln instead of raw stderr interface (#10427) 2019-02-27 11:41:03 +03:00
Marek Kotewicz
e2ab3e4f5b fix panic when logging directory does not exist, closes #10420 (#10424) 2019-02-26 18:14:11 +01:00
elferdo
1871275ecd Refactor ethcore::client::TransactResult to use it inside std::result::Result (#10366)
* Refactor TransactResult

* Adapt evmbin and tests
2019-02-26 13:49:33 +01:00
joshua-mir
afc1b72611 10000 > 5000 (#10422)
addresses #10418
2019-02-26 15:35:40 +03:00
Niklas Adolfsson
c5c3fb6a75 fix(rpc-types): replace uint and hash with ethereum_types v0.4 (#10217)
* fix(rpc-types): remove uint and hash wrappers

* fix(tests)

* fix(cleanup)

* grumbles(rpc-api): revert `verify_signature`

* revert change of `U64` -> `u64`

* fix(cleanup after bad merge)

* chore(bump ethereum-types)

* fix(bad merge)

* feat(tests ethereum-types): add tests

* chore(update `ethereum-types` to 0.4.2)

* feat(tests for h256)

* chore(rpc): remove `ethbloom` import

Use re-export from `ethereum-types` instead

* fix(bad merge): remove `DefaultAccount` type

* doc(add TODO with issue link)
2019-02-25 14:27:28 +01:00
5chdn
bceb883d99 snap: reenable i386, arm64, armhf architecture publishing (#10386)
* snap: reenable i386, arm64, armhf architecture publishing

* gitlab: fix indent

* gitlab: fix yml syntax

* Linker for crosscomile

* fix target to linker

* new docker image

* fix lint, add build to this PR

* calc SHA3 using rhash

* add new images for i386, armhf

* show snap target & artifacts

* set CARGO_TARGET for publish snap

* move detect Version to publish snap

* rm libc6 dep from snap-template up pub-snap script

* clean up cargo config before add linker

* move linker config to docker images
2019-02-25 14:56:38 +03:00
Antoine
fcccbf3b75 fix #10390 (#10391) 2019-02-22 15:31:34 +01:00
Wei Tang
9ad71b7baa Fix to_pod storage trie value decoding (#10368) 2019-02-22 14:00:20 +01:00
TriplEight
4311d43497 revert some changes, could be buggy (#10399) 2019-02-21 21:06:49 +01:00
5chdn
0815cc3b83 version: bump nightly to 2.5 (#10392)
* version: bump nightly to 2.5

* revert(rand 0.3.22)
2019-02-21 20:03:34 +01:00
TriplEight
b21844b371 no-git for publish jobs, empty artifacts dir (#10393)
* no-git for publish jobs, empty artifacts dir

* fix syntax

* prettiness

* fix prettiness

* should get rid of git in publishing
2019-02-21 21:14:59 +03:00
Niklas Adolfsson
f825048efa fix(jni): bump to jni to 0.11 & remove unsafe impl (#10394) 2019-02-21 19:26:01 +03:00
Niklas Adolfsson
2cbffe36e2 chore(bump ethereum-types) (#10396)
Fixes a de-serialization bug in `ethereum-tyes`
2019-02-21 15:34:41 +00:00
cheme
6bb106a784 Update to latest mem-db, hash-db and trie-db. (#10314)
* Switch to 'trie' crates, there is an unpublished deps to staging
parity-common triehash still.

* Use crates.io dependency.

* indentation

* Update util/journaldb/src/traits.rs

indentation

Co-Authored-By: cheme <emericchevalier.pro@gmail.com>

* Update ethcore/src/snapshot/tests/state.rs

Co-Authored-By: cheme <emericchevalier.pro@gmail.com>
2019-02-20 21:09:34 +03:00
Andrew Jones
4e0ec4e66b tx pool: always accept local transactions (#10375)
* tx pool: always accept local transactions

* tx pool: `choose` local txs with same sender and nonce
2019-02-20 16:49:39 +00:00
Niklas Adolfsson
b58a3ed0ad fix(trace_main! macro): don't re-export (#10384) 2019-02-20 10:52:28 +01:00
felix
b803f57db6 exchanged old(azure) bootnodes with new(ovh) ones (#10309)
* exchanged old(azure) bootnodes with new(ovh) ones

* Fix indent
2019-02-20 10:06:26 +01:00
André Silva
b457f46c81 ethash: implement Progpow (#9762)
* ethash: initial implementation of progpow

* progpow: use wrapping arithmetic

* progpow: cleanup comments

* progpow: fix keccak_f800

* progpow: reorder definitions

* progpow: general fixing

* progpow: add basic tests from geth

* progpow: generate c_dag and add test

* progpow: fix progpow_init and progpow_loop

* progpow: fix and add new test

* progpow: tabify

* progpow: add shared testvectors from geth and aleth

* progpow: add benchmarks

* progpow: don't read bytes from dag

* ethash: use criterion for progpow benchmarks

* progpow: dont borrow hash on fnv1a_hash

* progpow: don't borrow operand on progpow merge

* progpow: hardcode dag lookup function

we only support light verification anyway

* progpow: read double words directly from the dag

* progpow: inline some small functions

* progpow: remove some bounds checking from the main loop

* progpow: remove unreachable match cases

* progpow: remove bounds check in keccak_f800_round

* progpow: fix ptr::swap

* progpow: force loop unroll in keccak_f800_round

* progpow: remove unnecessary branching in progpow_loop

* progpow: force loop unroll in fill_mix

* progpow: silence unused warning

* progpow: dont run last keccak_f800_round out of the loop

rustc generates the same assembly, it unrolls the loop

* progpow: fix output of keccak_f800_short

* ethcore: support progpow in ethash engine

* ethash: fix typo

* ethcore, ethash: fix tests

* json: fix ethash spec tests

* ethash: update quick_get_difficulty for progpow

* ethash: drop light cache on progpow transition block

* ethash: fix quick_get_difficulty tests

* progpow: update to spec v0.9.0

* progpow: update to spec v0.9.1

* progpow: update to spec v0.9.2

* ethash: rename progpow benchmarks

* fix Cargo.lock bad merge

* ethash: only export modules for benchmarks

* ethash: progpow: remove unsafe unchecked indexing

* ethash: create enum for pow algorithm

* ethash: box the progpow cdag

* ethash: skip slow progpow test vectors on ci

* ethash: don't skip progpow test vectors

they don't take too long when running in release mode which is the case
for CI.

* ethash: progpow: update copyright date

Co-Authored-By: andresilva <andre.beat@gmail.com>

* ethcore: remove verification of ci-skip-tests on non-test builds
2019-02-20 10:05:11 +01:00
Leo Arias
b4520c5886 snap: add the removable-media plug (#10377)
This interface allows the snap to access the directories in /media. This is needed when the storage is in a separate disk, not part of home.
2019-02-20 09:49:54 +01:00
Psilon
ca67dc251f Add message to IO errors (#10324) 2019-02-18 20:39:38 +03:00
Niklas Adolfsson
aea289e79e chore(bump parity-daemonize): require rust >= 1.31 (#10359) 2019-02-18 13:38:46 +01:00
Svyatoslav Nikolsky
ef0eda0c39 SecretStore: use in-memory transport in cluster tests (#9850)
* fixing SS tests

* removed some redundant clones

* fixed grumbles

* replaced hash.clone() with *hash + fixed comment

* lost files
2019-02-18 13:38:19 +01:00
Hernando Castano
af7dc3676b Add fields to memzero's Cargo.toml (#10362)
* Add fields to Cargo.toml before publishing to crates.io

* Change license from MIT to GPL-3.0

* Add docs page
2019-02-15 12:32:33 +01:00
Afri Schoedon
fa570f297e snap: release untagged versions from branches to the candidate snap channel (#10357) 2019-02-14 17:24:52 +01:00
Niklas Adolfsson
9cce6a47d4 fix(compilation warns): no-default-features (#10346) 2019-02-14 17:54:44 +03:00
TriplEight
bff0bedfa9 no volumes are needed, just run -v volume:/path/in/the/container (#10345) 2019-02-14 12:45:56 +01:00
Dan Acristinii
d6c80c1672 Fixed misstype (#10351)
* Fixed misstype

BadTransactonType => BadTransactionType

* fixed other insances of transacton
2019-02-14 12:25:44 +01:00
Afri Schoedon
512343003d snap: prefix version and populate candidate channel (#10343)
* snap: populate candidate releases with beta snaps to avoid stale channel

* snap: prefix version with v*
2019-02-13 15:50:02 +01:00
elferdo
3adb640d2b Bundle protocol and packet_id together in chain sync (#10315)
Define a new `enum` where devp2p subprotocol packet ids (currently eth and par) are defined. Additionally provide functionality to query id value and protocol of a given id object.
2019-02-13 09:20:33 +01:00
gabriel klawitter
ea589a17a4 role back docker build image and docker deploy image to ubuntu:xenial based (#10338) 2019-02-12 20:52:30 +01:00
gabriel klawitter
a3883ca5d9 change docker image based on debian instead of ubuntu due to the chan… (#10336)
* change docker image based on debian instead of ubuntu due to the changes of the build container
2019-02-12 19:00:52 +01:00
Kirill Pimenov
5be0163cde Don't add discovery initiators to the node table (#10305)
* Don't add discovery initiators to the node table

* Use enums for tracking state of the nodes in discovery

* Dont try to ping ourselves

* Fix minor nits

* Update timeouts when observing an outdated node

* Extracted update_bucket_record from update_node

* Fixed typo

* Fix two final nits from @todr
2019-02-12 16:57:53 +01:00
Shude Li
55454b2f2d fix(docker): fix not receives SIGINT (#10059)
* fix(docker): fix not receives SIGINT

* fix: update with reviews

* update with review

* update

* update
2019-02-12 16:57:07 +01:00
TriplEight
a4dc85543b snap: official image / test (#10168)
* official image / test

* fix / test

* bit more necromancy

* fix paths

* add source bin/df /test

* add source bin/df /test2

* something w paths /test

* something w paths /test

* add source-type /test

* show paths /test

* copy plugin /test

* plugin -> nil

* install rhash

* no questions while installing rhash

* publish snap only for release
2019-02-12 15:37:54 +01:00
Niklas Adolfsson
d8394bded7 fix(add helper for timestamp overflows) (#10330)
* fix(add helper timestamp overflows)

* fix(simplify code)

* fix(make helper private)
2019-02-12 14:16:23 +00:00
cheme
d89b8d904f Additional error for invalid gas (#10327)
* Tag sensible place (ECHECH)

* Additional overflows checks.
2019-02-11 22:20:51 +00:00
Hernando Castano
8e866ee551 Revive parity_setMinGasPrice RPC call (#10294)
* Add function to update minimum gas price

* Update TestMinerService to handle min_gas_price changes

* Place minimum gas price test behind feature flag

* Update check for fixed gas pricer to be more explicit

* Use errors::unsupported instead of errors::request_rejected

* Add test that fails to set minimum gas price

* Fix test that should fail when setting new gas price

* Put dev dependencies behind feature flag

* Fix deadlock in set_minimal_gas_price()

* Update RPC tests with mocked error response

* Remove unnecessary cfg flag

* Remove duplicate crate imports
2019-02-11 18:08:12 +01:00
Hernando Castano
6dfc1bd474 Add Statetest support for Constantinople Fix (#10323)
* Update Ethereum tests repo to v6.0.0-beta.3 tag

* Add spec for St.Peter's / ConstantinopleFix statetests
2019-02-11 17:13:36 +01:00
Niklas Adolfsson
c84e5745fa fix(parity-clib): grumbles that were not addressed in #9920 (#10154)
* fix(remove needless unsafe blocks)

* style(nits)

* fix(parity-clib): eliminate repetitive event loops

* revert(java bindings): safe rust -> unsafe rust

These functions can still end up with `UB` thus should be unsafe

* fix(grumbles): make Callback trait `pub (crate)`
2019-02-11 15:27:46 +01:00
Niklas Adolfsson
751d15e4be fix(light-rpc): Make light_sync generic (#10238)
* fix(light-rpc): Make `light_sync` generic

The motivation behind this change is to easily mock `light-sync` to make it possible to enable `rpc-integration` tests
for the light-client.

Currently the `rpc's` requires the concrete type `sync::LightSync` which makes it very hard to do so

* fix(bad merge)
2019-02-11 10:33:16 +00:00
TriplEight
8b6c5be6a9 fix publish job (#10317)
* fix publish job

* dashes and colonels
2019-02-08 18:22:08 +01:00
Axel Chalon
3502b36232 Secure WS-RPC: grant access to all apis (#10246) 2019-02-08 14:11:55 +01:00
elferdo
046b8bbc8a Make specification of protocol in SyncRequester::send_request explicit (#10295)
* Make the specification of the protocol to which a packet_id belongs to
  explicit when calling "SyncRequester::send_packet".

* Remove "SyncIO::send" and leave only "SyncIO::send_protocol"

* Adapt tests to new code.

* Strengthen tests to check if packet_id and protocol match when sending
a devp2p packet.
2019-02-08 13:01:29 +01:00
Alexander Arlt
6fa4b2dec5 fix: parity-clib/examples/cpp/CMakeLists.txt (#10313)
* use of ${CMAKE_SHARED_LIBRARY_PREFIX} &
${CMAKE_SHARED_LIBRARY_SUFFIX} to support other operating systems.
2019-02-08 12:01:29 +03:00
TriplEight
83bcb819da CI optimizations (#10297)
* CI optimizations

* fix stripping

* new dockerfile

* no need n submodule upd

* review

* moved dockerfile

* it becomes large

* onchain update depends on s3

* fix dependency

* fix cache status

* fix cache status

* new cache status
2019-02-07 18:49:50 +01:00
elferdo
b7e8621846 Increase number of requested block bodies in chain sync (#10247)
* Increase the number of block bodies requested during Sync.

* Increase the number of block bodies requested during Sync.

* Check if our peer is an older parity client with the bug
  of not handling large requests properly

* Add a ClientVersion struct and a ClientCapabilites trait

* Make ClientVersion its own module

* Refactor and extend use of ClientVersion

* Replace strings with ClientVersion in PeerInfo

* Group further functionality in ClientCapabilities

* Move parity client version data from tuple to its own struct.

* Implement accessor methods for ParityClientData and remove them
from ClientVersion.

* Minor fixes

* Make functions specific to parity return types specific to parity.

* Test for shorter ID strings

* Fix formatting and remove unneeded dependencies.

* Roll back Cargo.lock

* Commit last Cargo.lock

* Convert from string to ClientVersion

* * When checking if peer accepts service transactions just check
  if it's parity, remove version check.

* Remove dependency on semver in ethcore-sync

* Remove unnecessary String instantiation

* Rename peer_info to peer_version

* Update RPC test helpers

* Simplify From<String>

* Parse static version string only once

* Update RPC tests to new ClientVersion struct

* Document public members

* More robust parsing of ID string

* Minor changes.

* Update version in which large block bodies requests appear.

* Update ethcore/sync/src/block_sync.rs

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

* Update util/network/src/client_version.rs

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

* Update util/network/src/client_version.rs

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

* Update tests.

* Minor fixes.
2019-02-07 15:27:09 +01:00
Tomasz Drwięga
d5c19f8719 Deprecate account management (#10213)
* Extract accounts from ethcore.

* Fix ethcore.

* Get rid of AccountProvider in test_helpers

* Fix rest of the code.

* Re-use EngineSigner, fix tests.

* Simplify EngineSigner to always have an Address.

* Fix RPC tests.

* Add deprecation notice to RPCs.

* Feature to disable accounts.

* extract accounts in RPC

* Run with accounts in tests.

* Fix RPC compilation and tests.

* Fix compilation of the binary.

* Fix compilation of the binary.

* Fix compilation with accounts enabled.

* Fix tests.

* Update submodule.

* Remove android.

* Use derive for Default

* Don't build secretstore by default.

* Add link to issue.

* Refresh Cargo.lock.

* Fix miner tests.

* Update rpc/Cargo.toml

Co-Authored-By: tomusdrw <tomusdrw@users.noreply.github.com>

* Fix private tests.
2019-02-07 14:34:24 +01:00
Wei Tang
8fa56add47 Properly handle check_epoch_end_signal errors (#10015)
* Make check_epoch_end_signal to only use immutable data

* Move check_epoch_end_signals out of commit_block

* Make check_epoch_end_signals possible to fail

* Actually return the error from check_epoch_end_signals

* Remove a clone

* Fix import error
2019-02-07 14:34:07 +01:00
Niklas Adolfsson
e45ee6cd72 fix(osx and windows builds): bump parity-daemonize (#10291) 2019-02-07 12:53:12 +01:00
Julien Bouteloup
e344286c32 Add missing step for Using systemd service file (#10175)
* Add missing step for  Using `systemd` service file

Copy Parity release from target folder to bin, write `cp -R ./target/release/parity /usr/bin/` to match `ExecStart=/usr/bin/parity --config /etc/parity/config.toml` from `https://github.com/paritytech/parity-ethereum/blob/master/scripts/parity.service`

* Copy release to bin folder using sudo install

`sudo install ./target/release/parity /usr/bin/parity`
2019-02-07 12:50:15 +01:00
Anton Gavrilov
45d7c60608 Call private contract methods from another private contract (read-only) (#10086)
* Patch available private contracts during private transaction

* Key acl ABI added

* Work with secret store keys moved to the separate struct

* Private tx test refactored

* Revert "Private tx test refactored"

This reverts commit 476c132d692c7a886bc7b7cd7fe47b3d7692bd63.

* Test for calling private contract from another one added

* Test fixed

* Redundant tab removed

* ACL contract processing fixed, test added

* Merge with head

* Expect replaced with closure
2019-02-07 12:39:04 +01:00
Andronik Ordian
a3e39c9858 update ring to 0.14 (#10262)
* cargo upgrade hyper-rustls --all

* cargo upgrade parity-crypto --all

* update Cargo.lock

* propagate NonZeroU32

* use NonZeroU32::new_unchecked for crypto::KEY_ITERATIONS

* update Cargo.lock

* replace unsafe code with lazy_static
2019-02-06 17:53:34 +01:00
Niklas Adolfsson
8ab6d89810 fix(secret-store): deprecation warning (#10301)
use of deprecated item 'core::str::<impl str>::trim_left_matches': superseded by `trim_start_matches`
2019-02-06 16:54:35 +03:00
Andrew Jones
1b3b9b2887 Update to jsonrpc-derive 10.0.2, fixes aliases bug (#10300) 2019-02-05 14:47:25 +00:00
Andrew Jones
89ae0f0ea0 Convert to jsonrpc-derive, use jsonrpc-* from crates.io (#10298)
* Use jsonrpc crates on local path

* Convert all RPC traits to use jsonrpc-derive

* Use local jsonrpc at top level

* Upgrade remaining jsonrpc dependencies

* Checkout Cargo.lock to master HEAD

* Use jsonrpc-* 10.0.1 from crates.io

* Attribute after docs
2019-02-05 14:31:19 +01:00
Pierre Krieger
06cae8a535 Fix Windows build (#10284) 2019-02-03 13:32:06 +01:00
Pierre Krieger
12ac992ffb Don't run the CPP example on CI (#10285)
* Don't run the CPP example on CI

* Add comment
2019-02-03 13:23:07 +01:00
Tomasz Drwięga
3b23c2e86d Additional tests for uint deserialization. (#10279) 2019-02-03 12:26:25 +01:00
Seun LanLege
0f9b2218da prevent silent errors in daemon mode (#10007)
* prevent silent errors in daemon mode

* change author in Cargo.toml, add preamble to pipe.rs

* set the uid and gid on daemon process, fix permission errors when writing to pid file

* call setup_logger before daemonize to prevent crashing when attempting to create logfile

* map_err for calls to splice and ioctl, fix spaces in Cargo.toml

* split out daemonize to own repo

* removed util/daemonize

* renamed dep to parity-daemonize

* fix(parity-clib): enable `logger`

* bump parity-daemonize

* remove obsolete comment

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

* fix(grumbles): docs and log in ParityParams

* Add FIXME comment regarding @tomaka grumbles
* Unify logger with the C-API in ParityParams (less type-safety with more from_raw() conversions)
* Add better documentation in the `parity.h`

* Apply suggestions from code review

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

* docs(parity lib): add link to logging issue

* fix(parity-clib): JNI enable `logger`

* fix(parity-clib): update `Java example`

* Update example to the API changes
* Remove needless printouts which can be controlled via logger instead
2019-02-01 19:31:02 +01:00
Tomasz Drwięga
12c42bce9b Fix join-set test to be deterministic. (#10263) 2019-01-30 12:57:38 +00:00
Gabriel Majoulet
eb3d33ed6f Update CHANGELOG-2.2.md (#10254) 2019-01-29 10:13:21 +01:00
cheme
a139c6d216 Macos heapsize force jemalloc (#10234)
* Switch to non prefixed malloc_size_of on macos

* Fix

* Testing darwin build

* Fix import

* conflict

* switch heapsize deps commit

* switch heapsize commit

* Rename branch

* Restore gitlab ci to origin

* test for mac

* mac tests?

* Switch of macos CI tests.
2019-01-29 09:26:22 +01:00
Andrew Plaza
50f5ccc4f2 Allow specifying local accounts via CLI (#9960)
* Allow specifying local accounts via CLI

 * Add `tx-queue-locals` CLI option
 * ethcore: modify miner to check options vec before importing transaction
 * modify tests (ethcore/parity)
Resolves #9634

* fix formatting

* fixes: Make prefer HashSet over Vec<>, add test, comment formatting

* Update ethcore/src/miner/miner.rs

Co-Authored-By: insipx <aplaza@liquidthink.net>

* Fix comments and add helper for set->vec conversion

* remove blank line from use statement

* fix helper test

* formatting

* fix test to pass on nightly

* revert test fix for nightly
2019-01-28 11:26:11 +01:00
Vladyslav Lupashevskyi
94db961975 Take in account zero gas price certification when doing transact_contract (#10232)
* Tx permission contract improvement

* Take in account zero gas price certification when doing transact_contract

* DRY in ServiceTransactionChecker

* Fix typos and regroup mod

* Fix imports

* Simplify code in struct instantiation

Co-Authored-By: VladLupashevskyi <vlad@lupashevskyi.com>
2019-01-28 10:58:34 +01:00
Yucong Sun
38f3747cde Update CHANGELOG.md (#10249)
change 2018 to 2019
2019-01-28 10:54:07 +01:00
folex
4fec2f2fc2 Fix typo: CHANGELOG-2.1 -> CHANGELOG-2.2 (#10233) 2019-01-23 11:09:40 +01:00
Sho Sawada
c96d8a742b Update copyright year to 2019. (#10181)
* Update copyright year to 2019.

Have a great year.

* add `(UK)`

* 2018-2019
2019-01-23 09:26:36 +00:00
Elder Ryan
c2de31e586 fixed: types::transaction::SignedTransaction; (#10229) 2019-01-22 22:03:31 +03:00
Niklas Adolfsson
4b11d79829 fix(ManageNetwork): replace Range with RangeInclusive (#10209)
* fix(ManageNetwork): replace Range -> RangeIncls

Fixes `TODO: Range should be changed to RangeInclusive once stable (https://github.com/rust-lang/rust/pull/50758)`

* fix(tests)

* fix(grumbles): off-by-one error in debug_asserts

* RangeInclusive::end() is inclusive which means that if start and end is equal the `debug_assert(range.end() >
range.start()` will fail which is shouldn't
2019-01-22 09:51:40 +01:00
Seun LanLege
c35abe4196 import rpc transactions sequentially (#10051)
* import rpc transactions sequentially

* use impl trait in argument position, renamed ProspectiveDispatcher to WithPostSign

* grouped imports

* integrates PostSign with ProspectiveSigner

* fix spaces, removed unnecessary type cast and duplicate polling

* clean up code style

* Apply suggestions from code review
2019-01-22 09:33:56 +01:00
Afri Schoedon
a9a278a6e1 Enable St-Peters-Fork ("Constantinople Fix") (#10223)
* ethcore: disable eip-1283 on kovan block 10255201

* ethcore: disable eip-1283 on ropsten block 4939394

* ethcore: enable st-peters-fork on mainnet block 7280000

* ethcore: fix kovan chain spec

* version: update fork blocks

* ethcore: disable eip-1283 on sokol block 7026400
2019-01-21 22:55:44 +01:00
Wei Tang
fb07ffa676 Add EIP-1283 disable transition (#10214) 2019-01-21 12:22:29 +01:00
Michael Müller
940a88fa4e Echo CORS request headers by default (#10221)
* Echo CORS request headers by default

More details in https://github.com/paritytech/parity-ethereum/issues/6616.

* fixup: Single line
2019-01-21 10:30:24 +00:00
Bryant Eisenbach
708e495c28 Happy New Year! (#10211)
* Happy New Year!

* Happy New Year!

* Update README.md
2019-01-18 14:00:13 +01:00
Denis S. Soldatov aka General-Beck
460681ead9 perform stripping during build (#10208)
* perform stripping during build

* var RUSTFLAGS
2019-01-18 12:03:18 +01:00
Hernando Castano
2a7ed457dc Remove CallContract and RegistryInfo re-exports from ethcore/client (#10205)
* Remove re-export of `CallContract` and `RegistryInfo` from `ethcore/client`

* Remove CallContract and RegistryInfo re-exports again

This was missed while fixing merge conflicts
2019-01-17 16:43:08 +01:00
Hernando Castano
35bbf11ba5 Extract CallContract and RegistryInfo traits into their own crate (#10178)
* Create call-contract crate

* Add license

* First attempt at using extracted CallContract trait

* Remove unneeded `extern crate` calls

* Move RegistryInfo trait into call-contract crate

* Move service-transaction-checker from ethcore to ethcore-miner

* Update Cargo.lock file

* Re-export call_contract

* Merge CallContract and RegistryInfo imports

* Remove commented code

* Add documentation to call_contract crate

* Add TODO for removal of re-exports

* Update call-contract crate description

Co-Authored-By: HCastano <HCastano@users.noreply.github.com>

* Rename call-contract crate to ethcore-call-contract
2019-01-16 19:52:21 +01:00
Afri Schoedon
4f1e1e8870 Update the changelogs for 2.1.11, 2.2.6, 2.2.7, and 2.3.0 (#10197)
* docs: move 2.2 changelog to docs/

* docs: mark parity 2.1 end of life

* docs: add changelog for 2.1.11

* docs: add changelog for 2.2.6

* docs: add changelog for 2.2.7

* docs: add changelog for 2.3.0

* docs: add release notes for 2.3.0
2019-01-16 18:32:53 +01:00
Victor Baranov
cf505139f1 Cancel Constantinople HF on POA Core (#10198) 2019-01-16 18:31:59 +01:00
Seun LanLege
cdba22a2cb Adds cli interface to allow reseting chain to a particular block (#9782)
* added BlockChainReset trait, client impl, and cli interface

* show block hashes to be deleted and new best block, update best block in db, better cli interface

* delete BlockNumber from COL_EXTRA

* add TODO comment

* add BlockReciepts to imports

* refactor block_headers_from_best_block, better cli documentation

* exit gracefully if reset arg isn't supplied

* fix cli usage macro

* removed stray int literals

* use Vec::with_capacity

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

* cast n to usize

* correct imports

* make db reset arg required
2019-01-16 16:37:26 +01:00
Nicolas Gotchac
1df6361753 Run all igd methods in its own thread (#10195) 2019-01-16 16:35:28 +01:00
Afri Schoedon
a6c6c7c070 pull constantinople on ethereum network (#10189)
* ethcore: pull constantinople on ethereum network

* version: mark update as critical

* ethcore: remove constantinople alltogether from chain spec

* version: revert fork block for ethereum
2019-01-15 21:50:41 +01:00
TriplEight
ed6f2877d7 Update for Android cross-compilation. (#10180)
* build-unix update

* .gitlab-ci update

* Update build-unix.sh

add android postprocessing

* path to android lib

libparity.so

* fix path to libparity

* add android lib to artifacts
2019-01-15 17:27:43 +01:00
Afri Schoedon
53c408f549 version: bump fork blocks for kovan and foundation (#10186) 2019-01-15 15:48:50 +01:00
Wei Tang
64704c456f Handle the case for contract creation on an empty but exist account with storage items (#10065)
* Add is_base_storage_root_unchanged

* Fix compile, use a shortcut for check, and remove ignored tests

* Add a warn!

* Update ethereum/tests to v6.0.0-beta.2

* grumble: use {:#x} instead of 0x{:x}

Co-Authored-By: sorpaas <accounts@that.world>
2019-01-15 10:21:44 +01:00
joshua-mir
0edf8e3f1b Align personal_unlockAccount behaviour when permanent unlock is disabled (#10060)
* align with docs

> If permanent unlocking is disabled (the default) then the duration argument will be ignored, and the account will be unlocked for a single signing.

Current behaviour throws an error that is no longer relevant.

* fix test

* Change back to throwing error

* Fix test again

* formatting

* oops

* whitespace fixes
2019-01-15 09:36:55 +01:00
Nicolas Gotchac
53a04e1686 Drop runtime after others (especially ws_server) (#10179) 2019-01-15 09:14:15 +01:00
Afri Schoedon
d356c6640d version: bump nightly to 2.4 (#10165)
* version: bump nightly to 2.4

* revert rand downgrade
2019-01-14 17:29:17 +01:00
Wei Tang
e8e087fc37 Skip locking in statedb for non-canon blocks (#10141) 2019-01-15 01:33:10 +11:00
shoffmeister
181738a736 Remove reference to ui-interface command-line option (#10170) 2019-01-12 13:12:03 +01:00
Tomasz Drwięga
1ac1224cd3 Fix #9822: trace_filter does not return failed contract creation (#10140)
currently trace_filter can't return failed contract creation transaction
but trace_block can query the failed contract creation transaction.it
because the logic of parity-ethereum/ethcore/src/trace/types/filter.rs
Line 109 in 9982eba
```
 _ => false
```

this patch correct the logic:
```
 _ => self.to_address.matches_all()
```

Signed-off-by: Deshi Xiao <xiaods@gmail.com>
2019-01-11 18:08:58 +01:00
Nicolas Gotchac
3687df8da2 Fix _cannot recursively call into Core_ issue (#10144)
* Change igd to github:maufl/rust-igd

* Run `igd::search_gateway_from_timeout` from own thread
2019-01-11 17:59:05 +01:00
Niklas Adolfsson
67eee6aeb7 fix(whisper): correct PoW calculation (#10166)
* Fix off-by-one error on `leading_zeros` which was used to index in the hash to get leading zeros when not aligned on byte boundary (i.e, all the bits in a byte was not zero such as 0001 1111)
* Fix overflow by shifting with bigger value than 63
2019-01-11 17:48:58 +01:00
Tomasz Drwięga
83ba9df85b Bump JSON-RPC (#10151)
* Bump JSON-RPC

* Fix test casing.
2019-01-11 16:55:03 +01:00
Kirill Pimenov
83f706186f Ping nodes from discovery (#10167) 2019-01-10 20:43:16 +01:00
Niklas Adolfsson
eea5f6f232 fix(android): remove dependency to libusb (#10161) 2019-01-10 13:13:15 +01:00
Niklas Adolfsson
38af7f35fc refactor(trim_right_matches -> trim_end_matches) (#10159) 2019-01-10 13:12:14 +01:00
Pierre Krieger
eea3de00c1 Merge Machine and WithRewards (#10071) 2019-01-10 13:11:39 +01:00
Afri Schoedon
4d66e8d06d snap: fix path in script (#10157)
* snap: fix path in script

* debug, revert me

* fix

* necromancer awk magic

* awk necromancy and path fixing

* working track selection
2019-01-10 10:58:30 +01:00
Wei Tang
010cfb7d67 Make sure parent block is not in importing queue when importing ancient blocks (#10138)
* Make sure parent block is not in importing queue when importing ancient blocks

* Clear queue when an ancient import fails

* Lock only once in clear

* Add comments why queued check is needed

* Should push the value back to the queue

* Directly check in chain.read()

* Remove extra empty line

* Revert unused verification change
2019-01-09 16:47:14 +03:00
Afri Schoedon
f9a8aac036 ci: re-enable snap publishing (#10142)
* ci: enable snap publishing~

* ci: add publish snap script

* ci: add snapcraft skeleton

* ci: group export statements

* ci: enable snaps on pr branch

* ci: enable snaps on pr branch

* ci: set default BUILD_ARCH

* ci: enable snaps on pr branch

* ci: enable snaps on pr branch

* ci: add libdb to snap

* ci: reinitiate gitlabci

* ci: reinitiate publish-snap script

* ci: fix yaml syntax

* cargo/gitlab env vars

* debug, revert me

* version?

* debug vars

* vars

* vars fix

* vars fix

* revert

* Update scripts/gitlab/publish-snap.sh

Co-Authored-By: 5chdn <5chdn@users.noreply.github.com>

* ci: read track from cargo toml
2019-01-09 14:39:21 +01:00
Vadim Arasev
3d28823be7 HF in POA Core (2019-01-18) - Constantinople (#10155)
https://github.com/poanetwork/poa-chain-spec/pull/100
2019-01-09 12:42:44 +01:00
ETHorHIL
492317abd7 Update EWF's tobalaba chainspec (#10152)
Added some bootnodes and removed some that we have lost access to.
2019-01-09 11:37:28 +01:00
Tomasz Drwięga
ab22d5e278 Replace ethcore-logger with env-logger. (#10102)
* Replace ethcore-logger with env-logger.

* Fix logger initialization in WASM tests.

* uncomment logger initialization in secret store

* Don't use ethcore-logger in whisper.

* Move ethcore-logger within parity dir.

* Uncomment rest from secret-store.

* Use `let _ =` in private_contract for consistency

* `ok()` to `let _ =` fix in service

* Use `let _ = ` for state_db
2019-01-08 15:07:20 +01:00
Andronik Ordian
ce5f704dd5 finality: dont require chain head to be in the chain (#10054) 2019-01-08 11:14:59 +01:00
Anton Gavrilov
696dc05dda Remove caching for node connections (#10143) 2019-01-08 11:31:26 +11:00
cheme
589083ad7a Blooms file iterator empty on out of range position. (#10145) 2019-01-07 17:54:06 +01:00
joshua-mir
1fda997370 Autogen docs for the "Configuring Parity Ethereum" wiki page. (#10067)
* publish docs changes for autogen config docs

* Update publish-docs.sh

adding an environment variable so js knows not to download git master and just grab the local repo

* Update publish-docs.sh

made some changes making this unnecessary

* fix env variable

env variable passes to node properly now

* use yarn

* test pipeline, revert me

* fix test pipeline, revert me

* change runner tag

* change runner tag 2

* change runner tag

* global git config

* supress upload_files output

* Update .gitlab-ci.yml

reverting testing changes

* Replace tag if exists

Very unlikely to be important/useful
2019-01-07 14:47:28 +01:00
Afri Schoedon
7c335e8764 misc: bump license header to 2019 (#10135)
* misc: bump license header to 2019

* misc: remove_duplicate_empty_lines.sh

* misc: run license header script

* commit cargo lock
2019-01-07 11:33:07 +01:00
Tomasz Drwięga
5b1d33d5fa Hide most of the logs from cpp example. (#10139) 2019-01-07 10:23:50 +01:00
Nicolas Gotchac
e435407080 Don't try to send oversized packets (#10042)
* Don't construct oversized packets

* Add test for payload limit

* [eth-sync] Fix wrongly computed data sizes

* Replace `MAX_RECEIPTS_TO_SEND` with overall softlimit
2019-01-04 19:58:21 +01:00
Anton Gavrilov
b180be7526 Private tx enabled flag added into STATUS packet (#9999)
* Add private tx enabled flag into status packet

* Error log added for the case with no peers available

* Add flag only for supported protocol versions

* Work with private handler refactored

* Log target changed

* Cargo.lock updated
2019-01-04 19:57:01 +01:00
Sergei Pepyakin
90fb473d87 Update pwasm-utils to 0.6.1 (#10134) 2019-01-04 16:56:56 +01:00
Tomasz Drwięga
3650f2d51c Extract blockchain from ethcore (#10114)
* Split blockchain & db from ethcore.

* Clean up blockchain deps.

* Missing docs.

* Fix blockchain tests.

* Make other crates compile.

* Remove some re-exports.

* Remove types re-export from ethcore.

* Remove EVM dependency from transaction.

* Merge ethcore-transaction with common-types.

* Clean-up ethcore deps a bit.

* remove ethcore from cargo.toml

* Update ethcore/blockchain/src/lib.rs

Co-Authored-By: tomusdrw <tomusdrw@users.noreply.github.com>

* Address review comments.

* Update DB comment.

* Add tracking issue to the TODO and fix typo.

* Common naming for common types.

* Update ethcore/db/src/keys.rs

Co-Authored-By: tomusdrw <tomusdrw@users.noreply.github.com>

* Update ethcore/blockchain/src/generator.rs

Co-Authored-By: tomusdrw <tomusdrw@users.noreply.github.com>

* Try to fix beta tests.
2019-01-04 14:05:46 +01:00
Afri Schoedon
3090324366 ethcore: update hardcoded headers (#10123)
* ethcore: update hardcoded headers for foundation

* ethcore: update hardcoded headers for ropsten

* ethcore: update hardcoded headers for kovan

* ethcore: use consistant formatting

* ethcore: restore spaces after colon in chain spec

* ethcore: fix bootnodes in chain specs

* ethcore: fix bootnodes in chain specs

* ethcore: enforce newline at the end of chainspecs
2019-01-04 13:26:18 +01:00
joshua-mir
130901e820 Identity fix (#10128)
* fix #10125

fix service transaction version detection if --identity is enabled, change test to match how --identity actually works

* fix wrong var

* get the index of  v, not /

* idx, not idx.len()

* Update ethcore/sync/src/chain/propagator.rs

Co-Authored-By: joshua-mir <43032097+joshua-mir@users.noreply.github.com>

* Update ethcore/sync/src/chain/propagator.rs

Co-Authored-By: joshua-mir <43032097+joshua-mir@users.noreply.github.com>

* change version prefix to a const

* space

Co-Authored-By: joshua-mir <43032097+joshua-mir@users.noreply.github.com>
2019-01-04 13:23:46 +01:00
Tomasz Drwięga
801b8191ef Use LenCachingMutex to optimize verification. (#10117) 2019-01-03 14:11:07 +01:00
Piotr Chromiec
469f9c26e7 Pyethereum keystore support (#9710)
* support for keystore format produced by pyethereum lib + some debug msgs

* made salt unbound also for Scrypt

* made address optional and skip if its none

* ignore values of any type, not just i32

* WIP: local deps

* cleanup

* enable optional address + more cleanup

* yet another cleanup

* enable keystore wo address import (using passwd)

* cleanup

* doc enchancement

* parity/account fix

* redesign after review

* fix indentation

* ignore just version in json under crypto

* remove unnecessary borrowing within match str

Co-Authored-By: tworec <tworec@golem.network>

* remove another unnecessary borrowing

Co-Authored-By: tworec <tworec@golem.network>

* default derived instead of implementing

* log dependency removed

* [ethstore] warn restored + env_logger initialized in CLI

* applied suggestion from @tomusdrw
2019-01-03 14:07:27 +01:00
Pierre Krieger
b5f510ead7 Bump rocksdb-sys to 0.5.5 (#10124)
* Bump rocksdb-sys to 0.5.5

* Revert rand
2019-01-03 13:13:02 +03:00
Niklas Adolfsson
b4f8bba843 parity-clib: async C bindings to RPC requests + subscribe/unsubscribe to websocket events (#9920)
* feat(parity-clib asynchronous rpc queries)

* feat(seperate bindings for ws and rpc)

* Subscribing to websockets for the full-client works

* feat(c binding unsubscribe_from_websocket)

* fix(tests): tweak CMake build config

* Enforce C+11

* refactor(parity-cpp-example) : `cpp:ify`

* fix(typedefs) : revert typedefs parity-clib

* docs(nits)

* fix(simplify websocket_unsubscribe)

* refactor(cpp example) : more subscriptions

* fix(callback type) : address grumbles on callback

* Use it the example to avoid using global variables

* docs(nits) - don't mention `arc`

* fix(jni bindings): fix compile errors

* feat(java example and updated java bindings)

* fix(java example) : run both full and light client

* fix(Java shutdown) : unsubscribe to sessions

Forgot to pass the JNIEnv environment since it is an instance method

* feat(return valid JString)

* Remove Java dependency by constructing a valid Java String in the callback

* fix(logger) : remove `rpc` trace log

* fix(format)

* fix(parity-clib): remove needless callback `type`

* fix(parity-clib-examples) : update examples

* `cpp` example pass in a struct instead to determines `callback kind`
* `java` add a instance variable the class `Callback` to determine `callback kind`

* fix(review comments): docs and format

* Update parity-clib/src/java.rs

Co-Authored-By: niklasad1 <niklasadolfsson1@gmail.com>

* fix(bad merge + spelling)

* fix(move examples to parity-clib/examples)
2019-01-02 16:49:01 +01:00
Niklas Adolfsson
2bb79614f6 refactor (hardware wallet) : reduce the number of threads (#9644)
* refactor(hardware-wallet) - use only one thread

This changes parity to use one thread instead of two to subscribe USB
events via the hardware-wallets.

* Fix logs and tests

* fix(grumbles) : formatting and spelling nits

* Update hw/src/lib.rs

Co-Authored-By: niklasad1 <niklasadolfsson1@gmail.com>

* Update hw/src/lib.rs

Co-Authored-By: niklasad1 <niklasadolfsson1@gmail.com>

* Update hw/src/ledger.rs

Co-Authored-By: niklasad1 <niklasadolfsson1@gmail.com>

* fix(grumbles): clarify docs and use constants

* Clarify bad explaination of `run-to-completion`
* Replace magic numbers with constants
2019-01-02 16:48:45 +01:00
Vadim Arasev
c077dc652d HF in POA Sokol (2019-01-04) (#10077)
* HF in POA Sokol (2019-01-04)

https://github.com/poanetwork/poa-chain-spec/pull/91

* Update POA Core bootnodes
2019-01-02 11:19:24 +01:00
Songtronix
1b6f2a3e92 Fix broken links (#10119)
Due to #10101 new directory structure, some links needed to be fixed.
2019-01-02 11:14:18 +01:00
Pierre Krieger
9136c81f05 Follow-up to #10105 (#10107) 2018-12-28 10:43:03 +01:00
Seun LanLege
912e5599d9 Move EIP-712 crate back to parity-ethereum (#10106)
* move eip-712 crate back to parity-ethereum

* changed license, updated documentation url
2018-12-28 17:36:55 +08:00
Tomasz Drwięga
ff0095ac5e Move a bunch of stuff around (#10101)
* Move devtools.

* Merge stop_guard & rename memzero

* Move price-info to miner.

* Group account management

* Clean up workspace members.

* Move local store closer to miner.

* Move clib examples.

* Move registrar and hash-fetch

* Move rpc_cli/rpc_client

* Move stratum closer to miner.

* Fix naming convention of crates.

* Update Cpp examples path.

* Fix paths for clib-example.

* Fix removing build.
2018-12-28 17:33:49 +08:00
Tomasz Drwięga
bf9fedc4ee Revert "Add --frozen when running cargo (#10081)" (#10105)
* Revert "Add --frozen when running cargo (#10081)"

This reverts commit c90e279ab5.

* Add Cargo.lock modification detection.
2018-12-27 13:42:19 +03:00
Wei Tang
78ba54da6b Fix left over small grumbles on whitespaces (#10084) 2018-12-20 14:28:32 +01:00
Pierre Krieger
c90e279ab5 Add --frozen when running cargo (#10081) 2018-12-19 15:23:26 +03:00
mattrutherford
215602de08 Fix pubsub new_blocks notifications to include all blocks (#9987)
Fix: new blocks notifications sometimes missing in pubsub RPC

Implement new struct to pass to `new_blocks()` with extra parameter - `has_more_blocks_to_import`, which was previously used to determine whether the notification should be sent. Now it's up to each implementation to decide what to do.

Updated all implementations to behave as before, except `eth_pubsub`, which will send notification even when the queue is not empty.

Update tests.
2018-12-19 09:24:14 +00:00
Pierre Krieger
13b832f959 Update some dependencies for compilation with pc-windows-gnu (#10082) 2018-12-18 23:26:01 +03:00
cheme
789bb9c852 Fill transaction hash on ethGetLog of light client. (#9938)
* Fill transaction hash on ethGetLog of light client. This is enifficient
but we keep align with spec.

* Using better variables names.

* Expose old fast light get log as `parity_getLogsLight`.

* Update rpc/src/v1/helpers/light_fetch.rs

Fix indent.

Co-Authored-By: cheme <emericchevalier.pro@gmail.com>

* Factor common code between light_logs and logs.

* Remove useless check

* Rename parity light logs to 'parity_getLogsNoTransactionHash'.
Fix indent and extra white lines.

* Use vec instead of tree map to avoid inner function.

* better loop
2018-12-17 22:40:25 +03:00
Thibaut Sardan
aada1f547b Update changelog update for 2.2.5-beta and 2.1.10-stable (#10064)
* Update CHANGELOG.md

* Update CHANGELOG-2.1.md

* Update docs/CHANGELOG-2.1.md

Co-Authored-By: Tbaut <33178835+Tbaut@users.noreply.github.com>

* Update docs/CHANGELOG-2.1.md

Co-Authored-By: Tbaut <33178835+Tbaut@users.noreply.github.com>

* Use - instead of *
2018-12-14 16:48:36 +01:00
mattrutherford
60718225ac Implement len caching for parking_lot RwLock (#10032)
- Refactor (and rename crate) and implement RwLock len cache.

- improve docs

- update ethcore verification queue to new version

- Implement Default, From,  also derive Debug

- update: parking_lot to 0.7
2018-12-13 18:07:56 +00:00
Pierre Krieger
1a2fc03083 Update parking_lot to 0.7 (#10050) 2018-12-11 17:22:55 +01:00
Tomasz Drwięga
61e8baee0c Bump crossbeam. (#10048) 2018-12-11 12:30:21 +00:00
Afri Schoedon
dbc5f55da9 ethcore: enable constantinople on ethereum (#10031)
* ethcore: change blockreward to 2e18 for foundation after constantinople

* ethcore: delay diff bomb by 2e6 blocks for foundation after constantinople

* ethcore: enable eip-{145,1014,1052,1283} for foundation after constantinople
2018-12-11 12:06:04 +08:00
Tomasz Drwięga
81b7698428 Strict empty steps validation (#10041)
* Add two failings tests for strict empty steps.

* Implement strict validation of empty steps.
2018-12-10 18:58:38 +00:00
Lazaridis
4ce4bad383 Center the Subtitle, use some CAPS (#10034) 2018-12-10 21:45:48 +08:00
cheme
23d25a079b Change test miner max memory to malloc reports. (#10024) 2018-12-07 09:11:16 +01:00
Anton Gavrilov
d19bdb642e Sort the storage for private state (#10018) 2018-12-06 13:02:15 +03:00
mattrutherford
2e0246a6c2 Fix: test corpus_inaccessible panic (#10019)
If system uptime is less than the duration in the test, thread
will panic due to: 'overflow when subtracting duration from instant'.

Changed duration to 20 seconds to make it unlikely the test will
fail due to this condition.

Since no operations that carry a similar risk of panic occur outside
of the tests, it doesn't seem warranted to depend on an external crate
to fix this.
2018-12-05 15:38:55 +00:00
Afri Schoedon
349098e7b2 ci: move future releases to ethereum subdir on s3 (#10017)
* ci: move future releases to ethereum subdir on s3

* ci: redesign s3 bucket logic

* ci: use the releases bucket
2018-12-05 15:02:37 +01:00
Andronik Ordian
dc3b1ecdd0 light(on_demand): decrease default time window to 10 secs (#10016)
* light(on_demand): decrease default time window to 10 secs

* light(on_demand): use secs units for cli options
2018-12-05 19:17:26 +08:00
Niklas Adolfsson
7fb33796b1 light client : failsafe crate (circuit breaker) (#9790)
* refactor(light) : N/W calls with `circuit breaker`

* fix(nits) : forgot to commit new files

* Add tests and change CLI args

* Address grumbles

* fix(failsafe-rs) : Santize input to prevent panics

* chore(failsafe) : bump failsafe, (parking_lot)

Bump failsafe to v0.3.0 to enable `parking_lot::Mutex` instead
`spin::Mutex`

* Remove `success_rate`

* feat(circuit_breaker logger)

* feat(CLI): separate CLI args request and response

* Fix tests

* Error response provide request kind

When a reponse `times-out` provide the actual request or requests that failed

* Update ethcore/light/src/on_demand/mod.rs

Co-Authored-By: niklasad1 <niklasadolfsson1@gmail.com>

* Update ethcore/light/src/on_demand/mod.rs

Co-Authored-By: niklasad1 <niklasadolfsson1@gmail.com>

* fix(grumbles): formatting nit

* fix(grumbles)

* Use second resolution on CLI args
* Use `consecutive failure policy` instead of `timeOverWindow`
* Add a couple of tests for `request_guard`

* fix(request_guard): off-by-one error, update tests
2018-12-05 10:36:53 +01:00
mattrutherford
ec886ddefb LenCachingMutex (#9988)
New util LenCachingMutex can be used in place of a Mutex, when working
with collections, or other types with a len() method. When
the Guard is dropped, the value returned from len() is stored
into an AtomicUsize and can be queried using load_len() without
needing to lock the Mutex. Implementations for ```Vec``` and
```VecDeque```.

Now used in [Verification](4ded4181a6/ethcore/src/verification/queue/mod.rs (L196)) so that calls to ```VerificationQueue.queue_info()```
no longer require locks.
2018-12-04 14:30:52 +00:00
Anton Gavrilov
4ded4181a6 Version and notification for private contract wrapper added (#9761)
* Version and notification for private contract wrapper added

* Error handling improved

* Style for comments in file fixed

* TODO issue added into comments
2018-12-03 19:44:36 +00:00
Wei Tang
60691d03e0 Handle failing case for update account cache in require (#9989) 2018-12-03 23:26:39 +08:00
Anton Gavrilov
869fa399b1 Add tokio runtime to ethcore io worker (#9979)
* Add tokio runtime to ethcore io worker

* Reworked with block_on_all
2018-12-03 22:35:46 +08:00
Andronik Ordian
7af953fd62 move daemonize before creating account provider (#10003)
* move daemonize before creating account provider

* daemonize: add a future-proofing comment
2018-11-30 17:22:41 +03:00
Afri Schoedon
5acbcb0d57 docs: update changelogs (#9990)
* docs: add changelog for 2.1.7 stable

* docs: add changelog for 2.2.2.2.2.2... :)
2018-11-30 13:30:40 +01:00
Andronik Ordian
7000c394b2 Fix daemonize (#10000)
* Revert "prevent silent errors in daemon mode, closes #9367 (#9946)"

This reverts commit 52d5278a62.

* deps(daemonize): switch back to crates.io
2018-11-30 12:39:30 +01:00
Nicolas Gotchac
7c0d894ccf Fix Bloom migration (#9992)
* Fix wrong block number in blooms migration

* Fix wrong `const` type (usize -> u64) 😬
2018-11-30 12:08:20 +08:00
Wei Tang
f092c10de5 Remove tendermint engine support (#9980)
* Remove tendermint engine support

* Remove tendermint test json spec

* Fix ethcore test compile

* Remove tendermint test in sync
2018-11-29 06:47:11 +08:00
Anton Gavrilov
7f5e6b3a0a Calculate gas for deployment transaction (#9840)
* Calculate gas for deployment transaction

* Space fixed

* ethcore: style fix in public_creation_transaction
2018-11-28 13:14:40 +01:00
Nicolas Gotchac
5e9dc185a5 Fix unstable peers and slowness in sync (#9967)
* Don't sync all peers after each response

* Update formating

* Fix tests: add `continue_sync` to `Sync_step`

* Update ethcore/sync/src/chain/mod.rs

Co-Authored-By: ngotchac <ngotchac@gmail.com>
2018-11-28 12:19:35 +01:00
Seun LanLege
0e94ac0111 adds parity_verifySignature RPC method (#9507)
* closes #7009

adds parity_verifySignature RPC method

* removed unneccesary into

* adds support for chain replay protected signatures

* corrected chain replay protection check

* corrected possible overflow

* added tests

* use checked_sub to prevent possible overflow

* use saturating_mul to prevent possible overflow

* changed method signature to accept r,s,v components

* added unit tests

* more tests

* refactored tests for better readability
moved verify_signature tests to live in the same file.

* removed unneccesary imports

* fixed PR grumbles

* fixed rsv notation

* fixed rsv notation

* renamed BasicAcount to RecoveredAccount, Support zero chain_id

* fixed compile errors

* fixed tests

* doc comment
2018-11-28 12:18:43 +01:00
Tomasz Drwięga
0b5bbf6048 Improve block and transaction propagation (#9954)
* Refactor sync to add priority tasks.

* Send priority tasks notifications.

* Propagate blocks, optimize transactions.

* Implement transaction propagation. Use sync_channel.

* Tone down info.

* Prevent deadlock by not waiting forever for sync lock.

* Fix lock order.

* Don't use sync_channel to prevent deadlocks.

* Fix tests.
2018-11-28 11:30:05 +01:00
Wei Tang
14c9cbd40e Deny unknown fields for chainspec (#9972)
* Add deny_unknown_fields to chainspec

* Add tests and fix existing one

* Remove serde_ignored dependency for chainspec

* Fix rpc test eth chain spec

* Fix starting_nonce_test spec
2018-11-28 06:21:31 +08:00
gabriel klawitter
c4466878cf fix docker build (#9971) 2018-11-27 12:51:42 +01:00
Afri Schoedon
c584221fa2 ci: rearrange pipeline by logic (#9970)
* ci: rearrange pipeline by logic

* ci: rename docs script
2018-11-27 12:51:27 +01:00
Afri Schoedon
70ba050c06 Add changelogs for 2.0.9, 2.1.4, 2.1.6, and 2.2.1 (#9963)
* docs: add changelog for parity 2.0.9 stable (eol)

* docs: add changelog for parity 2.1.4 beta and 2.1.6 stable

* docs: add changelogs for 2.2.1 beta

* docs: add releasenotes for 2.2
2018-11-26 20:18:56 +01:00
Seun LanLege
f2281dc38a Add Error message when sync is still in progress. (#9475)
* closes #9188

* check_for_unavailable_block in
eth_getTransactionByHash
eth_getTransactionByBlockHashAndIndex
eth_getTransactionByBlockNumberAndIndex
eth_getTransactionReceipt

* check for unavailable block in eth_getBlockByNumber

* corrected checks for unavailable_block

* check for block gaps in db

* corrected error messages

* corrected error information

* added allow-empty-block-result cli flag

* address grumbles

* --jsonrpc-allow-missing-blocks

* fix tests

* added checks to
    block_transaction_count_by_hash
    block_transaction_count_by_number
    block_uncles_count_by_hash
    block_uncles_count_by_number
    uncle_by_block_hash_and_index
    uncle_by_block_number_and_index
fix PR grumbles

* Update parity/cli/mod.rs

revert config name

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

* Update parity/cli/mod.rs

revert cli arg

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

* Apply suggestions from code review

revert config name

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

* fix PR grumbles

* fix more PR grumbles
2018-11-27 02:58:27 +08:00
Wei Tang
18a2e6265d Make CALLCODE to trace value to be the code address (#9881) 2018-11-26 12:21:55 +01:00
Nicolas Gotchac
0d593199d0 Fix light client informant while syncing (#9932)
* Add `is_idle` to LightSync to check importing status

* Use SyncStateWrapper to make sure is_idle gets updates

* Update is_major_import to use verified queue size as well

* Add comment for `is_idle`

* Add Debug to `SyncStateWrapper`

* `fn get` -> `fn into_inner`
2018-11-26 14:05:02 +03:00
cheme
832c4a7565 Add a optional json dump state to evm-bin (#9706)
* Add a dump of the state at the end of transaction for --json-test.
Also fixes json-test output on finish, and allow to put both on err or
out (--out-only and --err-only).

* Dump state resolution from trie, function behind evm-bin feature to avoid misuse.

* Rename 'slow' method to 'to_pod_full'.
Use cache first in 'to_pod_full', for in between commits case.
Change dump activation to use a function pointer instead.

* Fix tests.

* Query and add storage values to dump.

* Switch to use `require` method, even if less efficient it is better in
this case to reuse existing code.
Reuse of `storage_at` was not easy in this case (could not iterate and
use the method at the same time (refcell mutable borrow panics) so
keeping code as is.

* Switch to returning error.
Use 'base_storage_root' instead of 'storage_root'.
Added a test, it will only execute with json-test in ci, or when launch
with the feature.

* Renaming of command line parameters.
Comments fixes.
Minor code changes.

* Fix evmbin cmd parsing test.

* README update.

* Fix extra space and avoid clone call on copiable address.

* Revert test submodule.

* Revert wasm-test submodule.

* Use map_or instead of map + unwrap_or

* restore tests submodule
2018-11-25 20:12:59 +01:00
Wei Tang
34d22a35dd Disable EIP-98 transition by default (#9955)
* Change eip98Transition default to BlockNumber::max_value

* Remove accidential ethereum/tests submodule change
2018-11-25 19:59:27 +01:00
Nick Sanders
c880716f16 Remove secret_store runtimes. (#9888)
* Remove the independent runtimes from `KeyServerHttpListener` and
  `KeyServerCore` and instead require a `parity_runtime::Executor`
  to be passed upon creation of each.

* Remove the `threads` parameter from both `ClusterConfiguration` structs.

* Implement the `future::Executor` trait for `parity_runtime::Executor`.

* Update tests.
  - Update the `loop_until` function to instead use a oneshot to signal
    completion.
  - Modify the `make_key_servers` function to create and return a runtime.
2018-11-26 01:36:43 +08:00
Nicolas Gotchac
f20f4c74d2 Fix a deadlock (#9952)
* Update informant:
  - decimal in Mgas/s
  - print every 5s (not randomly between 5s and 10s)

* Fix dead-lock in `blockchain.rs`

* Update locks ordering
2018-11-25 15:53:41 +08:00
Niklas Adolfsson
1fdfa1e6c6 chore(eip712): remove unused failure-derive (#9958) 2018-11-23 16:42:44 +00:00
Sebastian Siemssen
4ee49f03df Do not use the home directory as the working dir in docker (#9834)
* Do not create a home directory.

* Re-add -m flag
2018-11-22 14:15:04 +00:00
Seun LanLege
52d5278a62 prevent silent errors in daemon mode, closes #9367 (#9946) 2018-11-22 05:41:23 +08:00
Tomasz Drwięga
35a2b87174 Fix empty steps (#9939)
* Don't send empty step twice or empty step then block.

* Perform basic validation of locally sealed blocks.

* Don't include empty step twice.
2018-11-21 21:30:03 +00:00
Nicolas Gotchac
664bb2becd Adjust requests costs for light client (#9925)
* PIP Table Cost relative to average peers instead of max peers

* Add tracing in PIP new_cost_table

* Update stat peer_count

* Use number of leeching peers for Light serve costs

* Fix test::light_params_load_share_depends_on_max_peers (wrong type)

* Remove (now) useless test

* Remove `load_share` from LightParams.Config
Prevent div. by 0

* Add LEECHER_COUNT_FACTOR

* PR Grumble: u64 to u32 for f64 casting

* Prevent u32 overflow for avg_peer_count

* Add tests for LightSync::Statistics
2018-11-21 20:11:01 +01:00
Simon Jentzsch
8865b95818 EIP-1186: add eth_getProof RPC-Method (#9001)
* added eth_getAccount

* changed to getProof

* implemented storage_proof

* better formatting of storage proof

* fixed imports;2C

* removed spaces

* fixed whitespace

* fixed docker

* added doc

* fixed Compile-error

* expose more ports

* added eth_getAccount

* changed to getProof

* implemented storage_proof

* better formatting of storage proof

* fixed docker

* removed slockit-changes

* fixed Dockerfile

* intend

* spaces

* removed spaces

* fixed whitespace

* fixed docker

* tabs

* fixed Compile-error

* added eth_getAccount

* changed to getProof

* implemented storage_proof

* fixed docker

* removed slockit-changes

* fixed Dockerfile

* intend

* spaces

* removed spaces

* fixed whitespace

* fixed docker

* tabs

* merged changes

* fixed warnings

* added eth_getAccount

* changed to getProof

* implemented storage_proof

* better formatting of storage proof

* Update Dockerfile

* fixed docker

* removed slockit-changes

* fixed Dockerfile

* intend

* spaces

* removed spaces

* fixed whitespace

* fixed docker

* tabs

* added eth_getAccount

* changed to getProof

* implemented storage_proof

* removed spaces

* fixed whitespace

* fixed docker

* added eth_getAccount

* changed to getProof

* implemented storage_proof

* better formatting of storage proof

* fixed docker

* removed slockit-changes

* fixed Dockerfile

* intend

* spaces

* removed spaces

* fixed whitespace

* fixed docker

* tabs

* merged changes

* fixed merge error

* fixed formatting

* fixed rename_all = "camelCase"

* fixed tabs

* fixed spaces

* removed port exposer

* formatting

* fixed comment

* use filter_map

* formatting

* use better variable names

* changed casting

* fixed tabs

* remote into() from address

* remove space

Co-Authored-By: simon-jentzsch <simon@slock.it>

* fixed storage_index

Co-Authored-By: simon-jentzsch <simon@slock.it>

* fixed clone

* fixed format

Co-Authored-By: simon-jentzsch <simon@slock.it>

* fixed empty lines

* removed Option from EthAccount

* fixed storage_index

* implemented test and fixed the struct-spaces

* fixed tests

* added experimental RPCs flag for getProof

* optmized code
2018-11-21 20:09:33 +01:00
mattrutherford
03600dce97 Missing blocks in filter_changes RPC (#9947)
* feat + fix: Missing blocks in filter_changes RPC

 * Implement validity check of reported hashes (in case of re-org) and re-set last_block to the last block reported that is still valid.

* Add const to set history size for validity check (32).

* test: in the case of a re-org we get same block number if hash is different
2018-11-21 15:50:41 +00:00
gabriel klawitter
8b607efc40 allow rust-nightly builds fail in nightly builds (#9944) 2018-11-20 11:17:03 +01:00
Reyk Floeter
9f1af6b3e8 Update eth-secp256k1 to include fix for BSDs (#9935) 2018-11-18 14:22:59 +08:00
Reyk Floeter
c0952ba44b Unbreak build on rust -stable (#9934) 2018-11-17 23:51:35 +00:00
Nicolas Gotchac
9475a2e474 Keep existing blocks when restoring a Snapshot (#8643)
* Rename db_restore => client

* First step: make it compile!

* Second step: working implementation!

* Refactoring

* Fix tests

* PR Grumbles

* PR Grumbles WIP

* Migrate ancient blocks interating backward

* Early return in block migration if snapshot is aborted

* Remove RwLock getter (PR Grumble I)

* Remove dependency on `Client`: only used Traits

* Add test for recovering aborted snapshot recovery

* Add test for migrating old blocks

* Fix build

* PR Grumble I

* PR Grumble II

* PR Grumble III

* PR Grumble IV

* PR Grumble V

* PR Grumble VI

* Fix one test

* Fix test

* PR Grumble

* PR Grumbles

* PR Grumbles II

* Fix tests

* Release RwLock earlier

* Revert Cargo.lock

* Update _update ancient block_ logic: set local in `commit`

* Update typo in ethcore/src/snapshot/service.rs

Co-Authored-By: ngotchac <ngotchac@gmail.com>
2018-11-18 00:06:34 +01:00
Tomasz Drwięga
5baed0c158 Add experimental RPCs flag (#9928)
* WiP

* Enable experimental RPCs.
2018-11-16 14:00:34 +01:00
Tomasz Drwięga
97c259858c Clarify poll lifetime (#9922)
* Clarify poll filter.

* Fix RPC test.
2018-11-16 11:39:29 +00:00
Niklas Adolfsson
0f90696528 docs(require rust 1.30) (#9923)
* docs(require rust 1.30)

* Update README.md

Co-Authored-By: niklasad1 <niklasadolfsson1@gmail.com>
2018-11-15 12:53:11 +01:00
Nicolas Gotchac
ac974a180d Use block header for building finality (#9914) 2018-11-14 13:05:49 +01:00
TriplEight
052380b8de simplify cargo audit (#9918) 2018-11-14 11:46:10 +01:00
Niklas Adolfsson
23a29439c0 light-fetch: Differentiate between out-of-gas/manual throw and use required gas from response on failure (#9824)
* fix start_gas, handle OOG exceptions & NotEnoughGas

* Change START_GAS: 50_000 -> 60_000
* When the `OutOfGas exception` is received then try to double the gas until it succeeds or block gas limit is reached
* When `NotEnoughBasGas error` is received then use the required gas provided in the response

* fix(light-fetch): ensure block_gas_limit is tried

Try the `block_gas_limit` before regard the execution as an error

* Update rpc/src/v1/helpers/light_fetch.rs

Co-Authored-By: niklasad1 <niklasadolfsson1@gmail.com>
2018-11-14 13:04:33 +03:00
Seun LanLege
a8617e2862 EIP 191 (#9701)
* added sign_191 rpc method

* fixed hash_structured_data return type

* added ConfirmationPayload::SignMessage for non-prefixed signatures, added tests for sign191

* renamed WithValidator -> PresignedTransaction

* rename applicationData to data in test

* adds docs for EIP191Version, renamed SignRequest to EIP191SignRequest
2018-11-14 09:02:40 +01:00
Niklas Adolfsson
6945a6b320 fix(logger): reqwest no longer a dependency (#9908) 2018-11-13 16:19:58 +00:00
Pierre Krieger
b375c9adbf Remove rust-toolchain file (#9906) 2018-11-13 18:23:17 +03:00
Thibaut Sardan
88a727739b foundation: #6692865, ropsten: #4417537, kovan: #9363457 (#9907) 2018-11-13 14:48:23 +01:00
André Silva
5f3ae4dee3 ethcore: use Machine::verify_transaction on parent block (#9900)
* ethcore: use Machine::verify_transaction on parent block

also fixes off-by-one activation of transaction permission contract

* ethcore: clarify call to verify_transaction
2018-11-13 14:58:53 +03:00
Niklas Adolfsson
5cbe834024 chore(rpc-tests): remove unused rand (#9896) 2018-11-12 13:41:05 +03:00
mattrutherford
eea5b86cc4 fix: Intermittent failing CI due to addr in use (#9885)
Allow OS to set port at runtime
2018-11-11 11:20:04 +01:00
Niklas Adolfsson
09c512abaa chore(bump docopt): 0.8 -> 1.0 (#9889) 2018-11-11 11:19:44 +01:00
zhangyaning
d42d816e7f Use expect (#9883) 2018-11-09 14:54:23 +03:00
Nicolas Gotchac
17effd15ab Use Weak reference in PubSubClient (#9886) 2018-11-09 11:51:49 +00:00
Afri Schoedon
9982eba188 ci: nuke the gitlab caches (#9855)
Will go without cache. Meanwhile have to investigate what was wrong and how to use it effectively.
2018-11-08 19:37:12 +01:00
zhangyaning
aafe527d4a Remove unused code (#9884) 2018-11-08 13:20:02 +01:00
Wei Tang
e4c53a460e Fix json tracer overflow (#9873)
* Fix json tracer overflow

* Replace trace_executed with a direct trace push

* Remove unused variable

* Add test for 5a51

* Remove duplicate json!
2018-11-08 03:04:36 +08:00
cheme
ca01596a65 Allow to seal work on latest block (#9876)
* Allow to seal work on latest block.

* Test from @todr to check sealing conditions.
2018-11-07 17:59:08 +00:00
Afri Schoedon
4f2415b483 Fix docker script (#9854)
* Dockerfile: change source path of the newly added check_sync.sh (#9869)
2018-11-07 15:53:22 +01:00
Tomasz Drwięga
f680eacdf2 Health endpoint (#9847)
* Health endpoint.

* Fix chain handling.

* Update to latest json-rpc.

* Change dev chain detection.

* Fix test.
2018-11-07 09:30:34 +01:00
gabriel klawitter
f6dcca3ebb gitlab-ci: make android release build succeed (#9743)
* use docker cargo config file for android builds

* make android build succeed
2018-11-06 20:26:05 +01:00
Wei Tang
1a642fc624 Clean up existing benchmarks (#9839)
* Add FIXME link for a state mod statement

* Remove unused benches feature in ethcore

* Fix evm benches compile

* Fix ethash benches compile

* Switch to criterion
2018-11-06 21:22:44 +08:00
Yohan Graterol
c4469514db Update Callisto block reward code to support HF1 (#9811)
* Add Callisto Mainnet support

* Remove merge failure

* EIP-649 removed

* Remove eip649Reward

* Modify difficultyBombDelays

* Callisto reward smart contract

* Remove ethash params

* Fix merge

* Update bootnodes

* Update block reward to support HF1
2018-11-06 14:07:59 +08:00
Tomasz Drwięga
59daf95859 Option to disable keep alive for JSON-RPC http transport (#9848)
* Keep alive jsonrpc CLI option.

* Update to latest json-rpc.

* Keep alive flag.
2018-11-05 22:39:51 +08:00
Yaz Khoury
3a6e04ba15 Classic.json Bootnode Update (#9828)
* fix: Update bootnodes list to only responsive nodes

* feat: Add more bootnodes to classic.json list

* feat: Add retested bootnodes
2018-11-01 11:30:34 +01:00
Jonathan Brown
b26f86d6ff Support MIX. (#9767)
* Support MIX.

* Re-arrange mix.json so tests pass.

* Add MIX hardfork.

* Fix MIX chain specification.

* Use original MIX datadir.

* Fix MIX Newark enode.
2018-11-01 11:06:53 +01:00
Afri Schoedon
570215acae ci: remove failing tests for android, windows, and macos (#9788)
* ci: remove failing tests for android, windows, and macos

* ci: restore android build jobs
2018-11-01 11:06:24 +01:00
cheme
a511264433 Implement NoProof for json tests and update tests reference (replaces #9744) (#9814)
* Update test reference.
Block test are really not working so I disabled a few by commenting
directly in source.

* Move ethtest commit cursor.

* Implements 'NoProof' engine from https://github.com/ethereum/tests/issues/464 .

Since tests has been regenerated those one were failing on block
difficulty check.

Update ethereum/tests, waiting for cost fix (block test are still
commented).

* Update tests submodule reference to latest (all test passing except an
identified case).
Fix block reward of constantinople json.

* Restore broken test by using old json tests files.

* Use CanonNoSeal instead of a custom engine, still have to include some
additional tests code.

* Gas upper limit check in json_chain test was bad, moving the test to
verification, the test is running in `verify_header_param`.
Note that test was previously only for ethash, and now for any engine.

* Restore old behavior (gas uper limit only for ethash engine), at the
cost of an additional trait method.

* Proper rpc test fix.

* Update tests submodule, add SStore bug tests.

* Fix json issue tabulation.
Update tests submodule to latest master (lot of new sstore tests
passing)

* Switch ethereum/tests to tag 6.0.0-beta.1 (no tests changes from latest
synch).

* Display hex with separator, use indirection instead of clone for copy
types.
2018-11-01 11:04:32 +01:00
Niklas Adolfsson
06f25d2b27 chore(bump regex) (#9842) 2018-11-01 13:16:02 +08:00
Anton Gavrilov
a3bd355b16 Ignore global cache for patched accounts (#9752)
* Ignore global cache for patched accounts

* Rollback patched account flag

* Store root in checkpoint storage
2018-10-31 15:55:11 +00:00
Wei Tang
1c1cd8b164 Move state root verification before gas used (#9841) 2018-10-31 22:44:46 +08:00
Niklas Adolfsson
a898109522 fix(docker-aarch64) : cross-compile config (#9798) 2018-10-31 12:39:18 +00:00
Afri Schoedon
3694b10e22 version: bump nightly to 2.3.0 (#9819)
* version: bump nightly to 2.3.0

* Revert Cargo.lock
2018-10-31 12:38:47 +00:00
cheme
39f25d20a8 Tests modification for windows CI (#9671)
* Fixing and disabling some tests for windows 10 compatibility.

* Few adjustment for windows in tests (eg bigger timeout for keyserver tests)

* Spaces and temporary single thread ci (to be able to spot the error).
2018-10-31 11:50:38 +01:00
Seun LanLege
61c1646b43 EIP-712 implementation (#9631)
* EIP-712 impl

* added more tests

* removed size parsing unwrap

* corrected TYPE_REGEX to disallow zero sized fixed length arrays, replaced LinkedHashSet with IndexSet, added API spec to docs, fixed Type::Byte encoding branch

* use Option<u64> instead of u64 for Type::Array::Length

* replace `.iter()` with  `.values()`

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

* tabify eip712.rs

* use proper comments for docs

* Cargo.lock: revert unrelated changes

* tabify encode.rs
2018-10-31 00:12:42 +03:00
Niklas Adolfsson
1b9396dcbb Fix typo (#9826) 2018-10-29 21:41:54 +01:00
Wei Tang
05be4b5b0e Clean up serde rename and use rename_all = camelCase when possible (#9823)
* Clean up serde rename and use rename_all = camelCase when possible

* snake_case for pricing

* Use camelcase for engine

* Use camel case for seal

* Use camel case for validator set

* Use camel case for confirmation payload

* Use camel case for consensus status

* Use camel case for nodekind

* Use kebab case for provenance

* Use camel case for pubsub

* Use lowercase and camelcase for trace

* Use camel case for whisper

* rename Ethash as irregular name
2018-10-29 23:49:04 +08:00
1168 changed files with 210431 additions and 236497 deletions

View File

@@ -1,3 +1,3 @@
[target.x86_64-pc-windows-msvc]
# Link the C runtime statically ; https://github.com/paritytech/parity-ethereum/issues/6643
# Link the C runtime statically ; https://github.com/openethereum/openethereum/issues/6643
rustflags = ["-Ctarget-feature=+crt-static"]

2
.git-blame-ignore-revs Normal file
View File

@@ -0,0 +1,2 @@
# Reformat the source code
610d9baba4af83b5767c659ca2ccfed337af1056

View File

@@ -2,11 +2,11 @@
## 1. Purpose
A primary goal of Parity is to be inclusive to the largest number of contributors, with the most varied and diverse backgrounds possible. As such, we are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, sexual orientation, ability, ethnicity, socioeconomic status, and religion (or lack thereof).
A primary goal of OpenEthereum is to be inclusive to the largest number of contributors, with the most varied and diverse backgrounds possible. As such, we are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, sexual orientation, ability, ethnicity, socioeconomic status, and religion (or lack thereof).
This code of conduct outlines our expectations for all those who participate in our community, as well as the consequences for unacceptable behavior.
We invite all those who participate in Parity to help us create safe and positive experiences for everyone.
We invite all those who participate in OpenEthereum to help us create safe and positive experiences for everyone.
## 2. Open Source Citizenship
@@ -63,7 +63,7 @@ Additionally, community organizers are available to help community members engag
## 7. Addressing Grievances
If you feel you have been falsely or unfairly accused of violating this Code of Conduct, you should notify Parity Technologies with a concise description of your grievance. Your grievance will be handled in accordance with our existing governing policies.
If you feel you have been falsely or unfairly accused of violating this Code of Conduct, you should notify OpenEthereum Technologies with a concise description of your grievance. Your grievance will be handled in accordance with our existing governing policies.
## 8. Scope
@@ -73,7 +73,7 @@ This code of conduct and its related procedures also applies to unacceptable beh
## 9. Contact info
You can contact Parity via Email: community@parity.io
You can contact OpenEthereum via Email: community@parity.io
## 10. License and attribution

View File

@@ -2,7 +2,7 @@
## Do you have a question?
Check out our [Basic Usage](https://wiki.parity.io/Basic-Usage), [Configuration](https://wiki.parity.io/Configuring-Parity-Ethereum), and [FAQ](https://wiki.parity.io/FAQ) articles on our [wiki](https://wiki.parity.io/)!
Check out our [Beginner Introduction](https://openethereum.github.io/Beginner-Introduction), [Configuration](https://openethereum.github.io//Configuring-OpenEthereum), and [FAQ](https://openethereum.github.io/FAQ) articles on our [wiki](https://openethereum.github.io/)!
See also frequently asked questions [tagged with `parity`](https://ethereum.stackexchange.com/questions/tagged/parity?sort=votes&pageSize=50) on Stack Exchange.
@@ -10,11 +10,11 @@ See also frequently asked questions [tagged with `parity`](https://ethereum.stac
Do **not** open an issue on Github if you think your discovered bug could be a **security-relevant vulnerability**. Please, read our [security policy](../SECURITY.md) instead.
Otherwise, just create a [new issue](https://github.com/paritytech/parity-ethereum/issues/new) in our repository and state:
Otherwise, just create a [new issue](https://github.com/openethereum/openethereum/issues/new) in our repository and state:
- What's your Parity Ethereum version?
- What's your OpenEthereum version?
- What's your operating system and version?
- How did you install Parity Ethereum?
- How did you install OpenEthereum?
- Is your node fully synchronized?
- Did you try turning it off and on again?
@@ -22,9 +22,44 @@ Also, try to include **steps to reproduce** the issue and expand on the **actual
## Contribute!
If you would like to contribute to Parity Ethereum, please **fork it**, fix bugs or implement features, and [propose a pull request](https://github.com/paritytech/parity-ethereum/compare).
If you would like to contribute to OpenEthereum, please **fork it**, fix bugs or implement features, and [propose a pull request](https://github.com/openethereum/openethereum/compare).
Please, refer to the [Coding Guide](https://wiki.parity.io/Coding-guide) in our wiki for more details about hacking on Parity.
### Labels & Milestones
We use [labels](https://github.com/openethereum/openethereum/labels) to manage PRs and issues and communicate the state of a PR. Please familiarize yourself with them. Furthermore we are organizing issues in [milestones](https://github.com/openethereum/openethereum/milestones). Best way to get started is to a pick a ticket from the current milestone tagged [`easy`](https://github.com/openethereum/openethereum/labels/Q2-easy%20%F0%9F%92%83) and get going, or [`mentor`](https://github.com/openethereum/openethereum/labels/Q1-mentor%20%F0%9F%95%BA) and get in contact with the mentor offering their support on that larger task.
### Rules
There are a few basic ground-rules for contributors (including the maintainer(s) of the project):
* **No pushing directly to the master branch**.
* **All modifications** must be made in a **pull-request** to solicit feedback from other contributors.
* Pull-requests cannot be merged before CI runs green and two reviewers have given their approval.
* All code changed should be formated by running `cargo fmt -- --config=merge_imports=true`
### Recommendations
* **Non-master branch names** *should* be prefixed with a short name moniker, followed by the associated Github Issue ID (if any), and a brief description of the task using the format `<GITHUB_USERNAME>-<ISSUE_ID>-<BRIEF_DESCRIPTION>` (e.g. `gavin-123-readme`). The name moniker helps people to inquiry about their unfinished work, and the GitHub Issue ID helps your future self and other developers (particularly those who are onboarding) find out about and understand the original scope of the task, and where it fits into Parity Ethereum [Projects](https://github.com/openethereum/openethereum/projects).
* **Remove stale branches periodically**
### Preparing Pull Requests
* If your PR does not alter any logic (e.g. comments, dependencies, docs), then it may be tagged [`insubstantial`](https://github.com/openethereum/openethereum/pulls?q=is%3Aopen+is%3Apr+label%3A%22A2-insubstantial+%F0%9F%91%B6%22).
* Once a PR is ready for review please add the [`pleasereview`](https://github.com/openethereum/openethereum/pulls?utf8=%E2%9C%93&q=is%3Aopen+is%3Apr+label%3A%22A0-pleasereview+%F0%9F%A4%93%22+) label.
### Reviewing Pull Requests*:
* At least two reviewers are required to review PRs (even for PRs tagged [`insubstantial`](https://github.com/openethereum/openethereum/pulls?q=is%3Aopen+is%3Apr+label%3A%22A2-insubstantial+%F0%9F%91%B6%22)).
When doing a review, make sure to look for any:
* Buggy behavior.
* Undue maintenance burden.
* Breaking with house coding style.
* Pessimization (i.e. reduction of speed as measured in the projects benchmarks).
* Breaking changes should be carefuly reviewed and tagged as such so they end up in the [changelog](../CHANGELOG.md).
* Uselessness (i.e. it does not strictly add a feature or fix a known issue).
## License.

View File

@@ -1,6 +1,8 @@
For questions please use https://discord.io/openethereum, issues are for bugs and feature requests.
_Before filing a new issue, please **provide the following information**._
- **Parity Ethereum version**: 0.0.0
- **OpenEthereum version (>=3.1.0)**: 0.0.0
- **Operating system**: Windows / MacOS / Linux
- **Installation**: homebrew / one-line installer / built from source
- **Fully synchronized**: no / yes

35
.github/workflows/build-test.yml vendored Normal file
View File

@@ -0,0 +1,35 @@
name: Build and Test Suite
on:
pull_request:
push:
branches:
- main
- dev
jobs:
build-tests:
name: Test and Build
strategy:
matrix:
platform:
- ubuntu-16.04
- macos-latest
toolchain:
- stable
runs-on: ${{ matrix.platform }}
steps:
- name: Checkout sources
uses: actions/checkout@main
with:
submodules: true
- name: Install toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.toolchain }}
profile: minimal
override: true
- name: Build tests
uses: actions-rs/cargo@v1
with:
command: test
args: --locked --all --release --features "json-tests" --verbose --no-run

285
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,285 @@
name: Build Release Suite
on:
push:
tags:
- v*
# Global vars
env:
AWS_REGION: "us-east-1"
AWS_S3_ARTIFACTS_BUCKET: "openethereum-releases"
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
jobs:
build:
name: Build Release
strategy:
matrix:
platform:
- ubuntu-16.04
- macos-latest
toolchain:
- stable
runs-on: ${{ matrix.platform }}
steps:
- name: Checkout sources
uses: actions/checkout@main
- name: Install toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.toolchain }}
profile: minimal
override: true
# ==============================
# Windows Build
# ==============================
# - name: Install LLVM for Windows
# if: matrix.platform == 'windows2019'
# run: choco install llvm
# - name: Build OpenEthereum for Windows
# if: matrix.platform == 'windows2019'
# run: sh scripts/actions/build-windows.sh ${{matrix.platform}}
# - name: Upload Windows build
# uses: actions/upload-artifact@v2
# if: matrix.platform == 'windows2019'
# with:
# name: windows-artifacts
# path: artifacts
# ==============================
# Linux/Macos Build
# ==============================
- name: Build OpenEthereum for ${{matrix.platform}}
if: matrix.platform != 'windows2019'
run: sh scripts/actions/build-linux.sh ${{matrix.platform}}
- name: Upload Linux build
uses: actions/upload-artifact@v2
if: matrix.platform == 'ubuntu-16.04'
with:
name: linux-artifacts
path: artifacts
- name: Upload MacOS build
uses: actions/upload-artifact@v2
if: matrix.platform == 'macos-latest'
with:
name: macos-artifacts
path: artifacts
zip-artifacts-creator:
name: Create zip artifacts
needs: build
runs-on: ubuntu-16.04
steps:
- name: Set env
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
# ==============================
# Create ZIP files
# ==============================
# - name: Download Windows artifacts
# uses: actions/download-artifact@v2
# with:
# name: windows-artifacts
# path: windows-artifacts
- name: Download Linux artifacts
uses: actions/download-artifact@v2
with:
name: linux-artifacts
path: linux-artifacts
- name: Download MacOS artifacts
uses: actions/download-artifact@v2
with:
name: macos-artifacts
path: macos-artifacts
- name: Display structure of downloaded files
run: ls
- name: Create zip Linux
id: create_zip_linux
run: |
cd linux-artifacts/
zip -rT openethereum-linux-${{ env.RELEASE_VERSION }}.zip *
ls openethereum-linux-${{ env.RELEASE_VERSION }}.zip
cd ..
mv linux-artifacts/openethereum-linux-${{ env.RELEASE_VERSION }}.zip .
echo "Setting outputs..."
echo ::set-output name=LINUX_ARTIFACT::openethereum-linux-${{ env.RELEASE_VERSION }}.zip
echo ::set-output name=LINUX_SHASUM::$(shasum -a 256 openethereum-linux-${{ env.RELEASE_VERSION }}.zip | awk '{print $1}')
- name: Create zip MacOS
id: create_zip_macos
run: |
cd macos-artifacts/
zip -rT openethereum-macos-${{ env.RELEASE_VERSION }}.zip *
ls openethereum-macos-${{ env.RELEASE_VERSION }}.zip
cd ..
mv macos-artifacts/openethereum-macos-${{ env.RELEASE_VERSION }}.zip .
echo "Setting outputs..."
echo ::set-output name=MACOS_ARTIFACT::openethereum-macos-${{ env.RELEASE_VERSION }}.zip
echo ::set-output name=MACOS_SHASUM::$(shasum -a 256 openethereum-macos-${{ env.RELEASE_VERSION }}.zip | awk '{print $1}')
# - name: Create zip Windows
# id: create_zip_windows
# run: |
# cd windows-artifacts/
# zip -rT openethereum-windows-${{ env.RELEASE_VERSION }}.zip *
# ls openethereum-windows-${{ env.RELEASE_VERSION }}.zip
# cd ..
# mv windows-artifacts/openethereum-windows-${{ env.RELEASE_VERSION }}.zip .
# echo "Setting outputs..."
# echo ::set-output name=WINDOWS_ARTIFACT::openethereum-windows-${{ env.RELEASE_VERSION }}.zip
# echo ::set-output name=WINDOWS_SHASUM::$(shasum -a 256 openethereum-windows-${{ env.RELEASE_VERSION }}.zip | awk '{print $1}')
# =======================================================================
# Upload artifacts
# This is required to share artifacts between different jobs
# =======================================================================
- name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: openethereum-linux-${{ env.RELEASE_VERSION }}.zip
path: openethereum-linux-${{ env.RELEASE_VERSION }}.zip
- name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: openethereum-macos-${{ env.RELEASE_VERSION }}.zip
path: openethereum-macos-${{ env.RELEASE_VERSION }}.zip
# - name: Upload artifacts
# uses: actions/upload-artifact@v2
# with:
# name: openethereum-windows-${{ env.RELEASE_VERSION }}.zip
# path: openethereum-windows-${{ env.RELEASE_VERSION }}.zip
# =======================================================================
# Upload artifacts to S3
# This is required by some software distribution systems which require
# artifacts to be downloadable, like Brew on MacOS.
# =======================================================================
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: Copy files to S3 with the AWS CLI
run: |
# Deploy zip artifacts to S3 bucket to a directory whose name is the tagged release version.
# Deploy macos binary artifact (if required, add more `aws s3 cp` commands to deploy specific OS versions)
aws s3 cp macos-artifacts/openethereum s3://${{ env.AWS_S3_ARTIFACTS_BUCKET }}/${{ env.RELEASE_VERSION }}/macos/ --region ${{ env.AWS_REGION }}
outputs:
linux-artifact: ${{ steps.create_zip_linux.outputs.LINUX_ARTIFACT }}
linux-shasum: ${{ steps.create_zip_linux.outputs.LINUX_SHASUM }}
macos-artifact: ${{ steps.create_zip_macos.outputs.MACOS_ARTIFACT }}
macos-shasum: ${{ steps.create_zip_macos.outputs.MACOS_SHASUM }}
# windows-artifact: ${{ steps.create_zip_windows.outputs.WINDOWS_ARTIFACT }}
# windows-shasum: ${{ steps.create_zip_windows.outputs.WINDOWS_SHASUM }}
draft-release:
name: Draft Release
needs: zip-artifacts-creator
runs-on: ubuntu-16.04
steps:
- name: Set env
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
# ==============================
# Download artifacts
# ==============================
- name: Download artifacts
uses: actions/download-artifact@v2
with:
name: openethereum-linux-${{ env.RELEASE_VERSION }}.zip
- name: Download artifacts
uses: actions/download-artifact@v2
with:
name: openethereum-macos-${{ env.RELEASE_VERSION }}.zip
# - name: Download artifacts
# uses: actions/download-artifact@v2
# with:
# name: openethereum-windows-${{ env.RELEASE_VERSION }}.zip
- name: Display structure of downloaded files
run: ls
# ==============================
# Create release draft
# ==============================
- name: Create Release Draft
id: create_release_draft
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
with:
tag_name: ${{ github.ref }}
release_name: OpenEthereum ${{ github.ref }}
body: |
This release contains <ADD_TEXT>
| System | Architecture | Binary | Sha256 Checksum |
|:---:|:---:|:---:|:---|
| <img src="https://gist.github.com/5chdn/1fce888fde1d773761f809b607757f76/raw/44c4f0fc63f1ea8e61a9513af5131ef65eaa6c75/apple.png" alt="Apple Icon by Pixel Perfect from https://www.flaticon.com/authors/pixel-perfect" style="width: 32px;"/> | x64 | [${{ needs.zip-artifacts-creator.outputs.macos-artifact }}](https://github.com/openethereum/openethereum/releases/download/${{ env.RELEASE_VERSION }}/${{ needs.zip-artifacts-creator.outputs.macos-artifact }}) | `${{ needs.zip-artifacts-creator.outputs.macos-shasum }}` |
| <img src="https://gist.github.com/5chdn/1fce888fde1d773761f809b607757f76/raw/44c4f0fc63f1ea8e61a9513af5131ef65eaa6c75/linux.png" alt="Linux Icon by Pixel Perfect from https://www.flaticon.com/authors/pixel-perfect" style="width: 32px;"/> | x64 | [${{ needs.zip-artifacts-creator.outputs.linux-artifact }}](https://github.com/openethereum/openethereum/releases/download/${{ env.RELEASE_VERSION }}/${{ needs.zip-artifacts-creator.outputs.linux-artifact }}) | `${{ needs.zip-artifacts-creator.outputs.linux-shasum }}` |
| <img src="https://gist.github.com/5chdn/1fce888fde1d773761f809b607757f76/raw/44c4f0fc63f1ea8e61a9513af5131ef65eaa6c75/windows.png" alt="Windows Icon by Pixel Perfect from https://www.flaticon.com/authors/pixel-perfect" style="width: 32px;"/> | x64 | [${{ needs.zip-artifacts-creator.outputs.windows-artifact }}](https://github.com/openethereum/openethereum/releases/download/${{ env.RELEASE_VERSION }}/${{ needs.zip-artifacts-creator.outputs.windows-artifact }}) | `${{ needs.zip-artifacts-creator.outputs.windows-shasum }}` |
| | | | |
| **System** | **Option** | - | **Resource** |
| <img src="https://gist.github.com/5chdn/1fce888fde1d773761f809b607757f76/raw/44c4f0fc63f1ea8e61a9513af5131ef65eaa6c75/settings.png" alt="Settings Icon by Pixel Perfect from https://www.flaticon.com/authors/pixel-perfect" style="width: 32px;"/> | Docker | - | [hub.docker.com/r/openethereum/openethereum](https://hub.docker.com/r/openethereum/openethereum) |
draft: true
prerelease: true
- name: Upload Release Asset - Linux
id: upload_release_asset_linux
uses: actions/upload-release-asset@v1.0.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release_draft.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: ./openethereum-linux-${{ env.RELEASE_VERSION }}.zip
asset_name: openethereum-linux-${{ env.RELEASE_VERSION }}.zip
asset_content_type: application/zip
- name: Upload Release Asset - MacOS
id: upload_release_asset_macos
uses: actions/upload-release-asset@v1.0.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release_draft.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: ./openethereum-macos-${{ env.RELEASE_VERSION }}.zip
asset_name: openethereum-macos-${{ env.RELEASE_VERSION }}.zip
asset_content_type: application/zip
# - name: Upload Release Asset - Windows
# id: upload_release_asset_windows
# uses: actions/upload-release-asset@v1
# env:
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# with:
# upload_url: ${{ steps.create_release_draft.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
# asset_path: ./openethereum-windows-${{ env.RELEASE_VERSION }}.zip
# asset_name: openethereum-windows-${{ env.RELEASE_VERSION }}.zip
# asset_content_type: application/zip

50
.github/workflows/check.yml vendored Normal file
View File

@@ -0,0 +1,50 @@
name: Check
on:
pull_request:
push:
branches:
- main
- dev
jobs:
check:
name: Check
runs-on: ubuntu-16.04
steps:
- name: Checkout sources
uses: actions/checkout@main
with:
submodules: true
- name: Install stable toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
- name: Run cargo check 1/3
uses: actions-rs/cargo@v1
with:
command: check
args: --locked --no-default-features --verbose
- name: Run cargo check 2/3
uses: actions-rs/cargo@v1
with:
command: check
args: --locked --manifest-path util/io/Cargo.toml --no-default-features --verbose
- name: Run cargo check 3/3
uses: actions-rs/cargo@v1
with:
command: check
args: --locked --manifest-path util/io/Cargo.toml --features "mio" --verbose
- name: Run cargo check evmbin
uses: actions-rs/cargo@v1
with:
command: check
args: --locked -p evmbin --verbose
- name: Run cargo check benches
uses: actions-rs/cargo@v1
with:
command: check
args: --locked --all --benches --verbose
- name: Run validate chainspecs
run: ./scripts/actions/validate-chainspecs.sh

View File

@@ -0,0 +1,29 @@
name: Docker Image Nightly Release
# Run "nightly" build on each commit to "dev" branch.
on:
push:
branches:
- dev
jobs:
deploy-docker:
name: Build Release
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@master
- name: Install toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
- name: Deploy to docker hub
uses: elgohr/Publish-Docker-Github-Action@master
with:
name: openethereum/openethereum
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
dockerfile: scripts/docker/alpine/Dockerfile
tags: "nightly"

30
.github/workflows/deploy-docker-tag.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: Docker Image Tag and Latest Release
on:
push:
tags:
- v*
jobs:
deploy-docker:
name: Build Release
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@master
- name: Set env
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- name: Install toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
- name: Deploy to docker hub
uses: elgohr/Publish-Docker-Github-Action@master
with:
name: openethereum/openethereum
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
dockerfile: scripts/docker/alpine/Dockerfile
tags: "latest,${{ env.RELEASE_VERSION }}"

30
.github/workflows/deploy-docker.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: Docker Image Release
on:
push:
branches:
- main
tags:
- v*
jobs:
deploy-docker:
name: Build Release
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@master
- name: Install toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
- name: Deploy to docker hub
uses: elgohr/Publish-Docker-Github-Action@master
with:
name: openethereum/openethereum
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
dockerfile: scripts/docker/alpine/Dockerfile
tag_names: true

20
.github/workflows/fmt.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
on: [push, pull_request]
name: rustfmt
jobs:
fmt:
name: Rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- run: rustup component add rustfmt
- uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check --config merge_imports=true

4
.gitignore vendored
View File

@@ -38,8 +38,10 @@ node_modules
# Build artifacts
out/
parity-clib-examples/cpp/build/
.vscode
rls/
/parity.*
# cargo remote artifacts
remote-target

View File

@@ -1,155 +0,0 @@
stages:
- test
- build
- publish
- optional
image: parity/rust:gitlab-ci
variables:
CI_SERVER_NAME: "GitLab CI"
CARGO_HOME: "${CI_PROJECT_DIR}/.cargo"
CARGO_TARGET: x86_64-unknown-linux-gnu
.releaseable_branches: # list of git refs for building GitLab artifacts (think "pre-release binaries")
only: &releaseable_branches
- stable
- beta
- tags
- schedules
.collect_artifacts: &collect_artifacts
artifacts:
name: "${CI_JOB_NAME}_${SCHEDULE_TAG:-${CI_COMMIT_REF_NAME}}"
when: on_success
expire_in: 1 mos
paths:
- artifacts/
.determine_version: &determine_version
- VERSION="$(sed -r -n '1,/^version/s/^version = "([^"]+)".*$/\1/p' Cargo.toml)"
- DATE_STR="$(date +%Y%m%d)"
- ID_SHORT="$(echo ${CI_COMMIT_SHA} | cut -c 1-7)"
- test "${SCHEDULE_TAG:-${CI_COMMIT_REF_NAME}}" = "nightly" && VERSION="${VERSION}-${ID_SHORT}-${DATE_STR}"
- export VERSION
- echo "Version = ${VERSION}"
test-linux:
stage: test
variables:
RUN_TESTS: all
script:
- scripts/gitlab/test-all.sh stable
tags:
- rust-stable
test-audit:
stage: test
script:
- scripts/gitlab/cargo-audit.sh
tags:
- rust-stable
build-linux:
stage: build
only: *releaseable_branches
variables:
CARGO_TARGET: x86_64-unknown-linux-gnu
script:
- scripts/gitlab/build-unix.sh
<<: *collect_artifacts
tags:
- rust-stable
build-darwin:
stage: build
only: *releaseable_branches
variables:
CARGO_TARGET: x86_64-apple-darwin
CC: gcc
CXX: g++
script:
- scripts/gitlab/build-unix.sh
tags:
- rust-osx
<<: *collect_artifacts
build-windows:
stage: build
only: *releaseable_branches
variables:
CARGO_TARGET: x86_64-pc-windows-msvc
script:
- sh scripts/gitlab/build-windows.sh
tags:
- rust-windows
<<: *collect_artifacts
publish-docker:
stage: publish
only: *releaseable_branches
cache: {}
dependencies:
- build-linux
tags:
- shell
script:
- scripts/gitlab/publish-docker.sh parity
publish-awss3:
stage: publish
only: *releaseable_branches
cache: {}
dependencies:
- build-linux
- build-darwin
- build-windows
before_script: *determine_version
script:
- scripts/gitlab/publish-awss3.sh
tags:
- shell
publish-docs:
stage: publish
only:
- tags
except:
- nightly
cache: {}
script:
- scripts/gitlab/publish-docs.sh
tags:
- shell
build-android:
stage: optional
image: parity/rust-android:gitlab-ci
variables:
CARGO_TARGET: armv7-linux-androideabi
script:
- scripts/gitlab/build-unix.sh
tags:
- rust-arm
allow_failure: true
test-beta:
stage: optional
variables:
RUN_TESTS: cargo
script:
- scripts/gitlab/test-all.sh beta
tags:
- rust-beta
allow_failure: true
test-nightly:
stage: optional
variables:
RUN_TESTS: all
script:
- scripts/gitlab/test-all.sh nightly
tags:
- rust-nightly
allow_failure: true

View File

@@ -1,873 +1,56 @@
## Parity-Ethereum [v2.1.3](https://github.com/paritytech/parity-ethereum/releases/tag/v2.1.3) (2018-10-16)
## OpenEthereum v3.1.1
Parity-Ethereum 2.1.3-stable is a release that fixes a consensus issue with the recent Constantinople release. Upgrading is mandatory whatever network you are connected to that plans enabling EIP-1283, e.g., Ropsten, Kovan, Ethereum.
Bug fixes:
* Ancient target set. InvalidStateRoot bug (#69) (#149)
* Update linked-hash-map to 0.5.3
The full list of included changes:
Enhancements:
* Added additional Sg-1,Ca-2,Ca-3 OE bootnodes
* Add --ws-max-paxload (#155)
* Add flag to disable storage output in openethereum-evm tool #97 (#115)
* ethstore - remove unnecessary dir & tiny-keccak dependencies from the lib (#107)
* Sync block verification (#74)
* Add `wasmDisableTransition` spec option (#60)
* EIP2929 with journaling + Yolov3 (#79)
* EIP2565 impl (#82)
* TypedTransaction (EIP-2718) and Optional access list (EIP-2930) (#135)
- Beta release 2.1.3 backports ([#9749](https://github.com/paritytech/parity-ethereum/pull/9749))
- Parity-version: mark 2.1.3 beta as critical
- Use signed 256-bit integer for sstore gas refund substate ([#9746](https://github.com/paritytech/parity-ethereum/pull/9746))
- Add --force to cargo audit install script ([#9735](https://github.com/paritytech/parity-ethereum/pull/9735))
- Heads ref not present for branches beta and stable ([#9741](https://github.com/paritytech/parity-ethereum/pull/9741))
- Aura: fix panic on extra_info with unsealed block ([#9755](https://github.com/paritytech/parity-ethereum/pull/9755))
DevOps:
* Add custom windows runner (#162)
* Remove sscache (#138)
* Fix deprecated set-env declaration (#106)
## Parity-Ethereum [v2.1.2](https://github.com/paritytech/parity-ethereum/releases/tag/v2.1.2) (2018-10-12)
Parity-Ethereum 2.1.2-beta is a release that introduces **Constantinople** to the Ethereum client. Upgrading is strongly recommended.
## OpenEthereum v3.1.0
![europe-1803495_1280](https://user-images.githubusercontent.com/15729797/46785767-15f1e280-cd33-11e8-862a-458edfd73ecf.png)
OpenEthereum 3.1.0 is a release based on v2.5.13 which is the last stable version known of the client that does not include any of the issues introduced in v2.7. It removes non core features like Ethereum Classic, Private Transactions, Light Client, Updater, IPFS and Swarm support, currently deprecated flags such as expanse, kotti, mordor testnets.
The following hardforks are supported by this release:
Database migration utility currently in beta: https://github.com/openethereum/3.1-db-upgrade-tool
- Ropsten testnet block `4_230_000` on October 14, 2018 (Constantinople)
- POA core mainnet block `5_329_160` on October 22, 2018 (CORE HF 2)
- Kovan testnet block `9_200_000` on October 25, 2018 (Constantinople, KIP-{4,6})
The full list of included changes from v2.5.13 to v3.1.0:
Running one of these networks, an upgrade to 2.0.7 or 2.1.2 is mandatory. More details can be found in Changelog below.
Please note, the following deprecations in our distribution of binaries:
- `arm*` targets are no longer served by parity, please consider (cross-)compiling from source yourself.
- `i*86` targets are no longer served by parity, please consider upgrading your operating system.
- Snapcraft is no longer maintained. please use binaries directly or your distro's repositories.
The full list of included changes:
- More backports for 2.1.2 ([#9733](https://github.com/paritytech/parity-ethereum/pull/9733))
- Produce portable binaries ([#9725](https://github.com/paritytech/parity-ethereum/pull/9725))
- HF in POA Core (2018-10-22) ([#9724](https://github.com/paritytech/parity-ethereum/pull/9724))
- Use static call and apparent value transfer for block reward contract code ([#9603](https://github.com/paritytech/parity-ethereum/pull/9603))
- Verify block syncing responses against requests ([#9670](https://github.com/paritytech/parity-ethereum/pull/9670))
- Fix ancient blocks sync ([#9531](https://github.com/paritytech/parity-ethereum/pull/9531))
- Add hardcoded headers ([#9730](https://github.com/paritytech/parity-ethereum/pull/9730))
- Gitlab ci: releasable_branches: change variables condition to schedule ([#9729](https://github.com/paritytech/parity-ethereum/pull/9729))
- Backports for beta 2.1.2 ([#9649](https://github.com/paritytech/parity-ethereum/pull/9649))
- Parity-version: bump beta to 2.1.2
- Ethcore: fix detection of major import ([#9552](https://github.com/paritytech/parity-ethereum/pull/9552))
- Hardfork the testnets ([#9562](https://github.com/paritytech/parity-ethereum/pull/9562))
- Docs(rpc): push the branch along with tags ([#9578](https://github.com/paritytech/parity-ethereum/pull/9578))
- Remove snapcraft clean ([#9585](https://github.com/paritytech/parity-ethereum/pull/9585))
- Fix (light/provider) : Make `read_only executions` only read-only ([#9591](https://github.com/paritytech/parity-ethereum/pull/9591))
- Ci: fix regex 🙄 ([#9597](https://github.com/paritytech/parity-ethereum/pull/9597))
- Docs(rpc): annotate tag with the provided message ([#9601](https://github.com/paritytech/parity-ethereum/pull/9601))
- Update ropsten bootnodes ([#9602](https://github.com/paritytech/parity-ethereum/pull/9602))
- HF in POA Sokol (2018-09-19) ([#9607](https://github.com/paritytech/parity-ethereum/pull/9607))
- Fix(network): don't disconnect reserved peers ([#9608](https://github.com/paritytech/parity-ethereum/pull/9608))
- Fix failing node-table tests on mac os ([#9633](https://github.com/paritytech/parity-ethereum/pull/9633))
- Fix bad-block reporting no reason ([#9638](https://github.com/paritytech/parity-ethereum/pull/9638))
- Ethcore-io retries failed work steal ([#9651](https://github.com/paritytech/parity-ethereum/pull/9651))
- Remove master from releasable branches ([#9655](https://github.com/paritytech/parity-ethereum/pull/9655))
- Test fix for windows cache name... ([#9658](https://github.com/paritytech/parity-ethereum/pull/9658))
- Fix(light_fetch): avoid race with BlockNumber::Latest ([#9665](https://github.com/paritytech/parity-ethereum/pull/9665))
- Calculate sha3 instead of sha256 for push-release. ([#9673](https://github.com/paritytech/parity-ethereum/pull/9673))
- Ci: fix push script ([#9679](https://github.com/paritytech/parity-ethereum/pull/9679))
- CI: Remove unnecessary pipes ([#9681](https://github.com/paritytech/parity-ethereum/pull/9681))
- Don't hash the init_code of CREATE. ([#9688](https://github.com/paritytech/parity-ethereum/pull/9688))
- Docker: run parity as normal user ([#9689](https://github.com/paritytech/parity-ethereum/pull/9689))
- CI: Skip docs job for master and nightly ([#9693](https://github.com/paritytech/parity-ethereum/pull/9693))
- Implement CREATE2 gas changes and fix some potential overflowing ([#9694](https://github.com/paritytech/parity-ethereum/pull/9694))
- Make instantSeal engine backwards compatible ([#9700](https://github.com/paritytech/parity-ethereum/pull/9700))
- Ethcore: delay ropsten hardfork ([#9704](https://github.com/paritytech/parity-ethereum/pull/9704))
## Parity-Ethereum [v2.1.1](https://github.com/paritytech/parity-ethereum/releases/tag/v2.1.1) (2018-09-20)
Parity-Ethereum 2.1.1-beta is a release that does not improve performance and stability; no changes were made.
The full list of included changes:
- Backports for 2.1.1 beta ([#9599](https://github.com/paritytech/parity-ethereum/pull/9599))
- Parity: bump version to 2.1.1 beta
- Ci: fix regex roll_eyes
- Docs(rpc): annotate tag with the provided message
## Parity-Ethereum [v2.1.0](https://github.com/paritytech/parity-ethereum/releases/tag/v2.1.0) (2018-09-19)
Parity-Ethereum 2.1.0-beta is released! Look at this!
Important notices:
- This release moves the 2.1 track of Parity-Ethereum to beta.
- This release contains a low-severity issue with the web-sockets ports. [#9545](https://github.com/paritytech/parity-ethereum/pull/9545)
- This release resolves a potential network fragmentation issue. [#9526](https://github.com/paritytech/parity-ethereum/pull/9526)
- With this release, all versions of Parity Ethereum 1.x prior to 2.0 reached end of life.
- Users are urged to upgrade to 2.0.5-stable or 2.1.0-beta.
Further changes worth highlighting:
- Generalized `blockReward` and `difficultyBombDelays` config ([#9480](https://github.com/paritytech/parity-ethereum/pull/9480)): This removes `eip649*` parameters from chain specs and allows `blockReward` to accept `multi`. Please review your chain-specs!
- Implement EIP234 `block_hash` for `eth_getLogs` ([#9256](https://github.com/paritytech/parity-ethereum/pull/9256)): If `block_hash` and `from_block`/`to_block` present, return error. This also changes `eth_getLogs` to return error if any of `block_hash`/`from_block`/`to_block` cannot be found.
- The default `gas_floor_target` was increased to `8_000_000`, the default `gas_cap` to `10_000_000`.
- Light clients provide the actual account for `eth_coinbase` RPC ([#9383](https://github.com/paritytech/parity-ethereum/pull/9383)). Note, this behavior is different from the full client where we return the `0x0` address if no accounts are found!
- Light servers give free credits for reserved peers ([#9448](https://github.com/paritytech/parity-ethereum/pull/9448)): When connecting to a reserved peers in light client, assign free credits to them. This fixes the scenario where a home server is running a full node, and another light client connects to the full node as a reserved peer.
- Multi-threaded snapshot creation ([#9239](https://github.com/paritytech/parity-ethereum/pull/9239)): to speed up the generation of snapshots on disk, this can be parallelized now. By default N/2 CPU cores are being used. Use `--snapshot-threads` flag to customize the number of threads.
- Remove all dapp permissions related settings ([#9120](https://github.com/paritytech/parity-ethereum/pull/9120)). This completely removes dapp permission settings from `AccountProvider` and JSON-RPC: In JSON-RPC, all available accounts are returned, regardless of the origin; previously we return accounts based on dapps policy. It's not possible to set a "default account" (as for dapps) any more; this is now always the first account in the available account list.
- Remove unused `--tx_queue_gas` parameter ([#9153](https://github.com/paritytech/parity-ethereum/pull/9153)). Please use `parity --help` to learn about available transaction queue strategies.
The full list of included changes:
- Add snapcraft package image ([#9583](https://github.com/paritytech/parity-ethereum/pull/9583))
- Add snapcraft package image
- Update .gitlab-ci.yml
- Remove snapcraft clean
- Backports for 2.1.0 beta ([#9518](https://github.com/paritytech/parity-ethereum/pull/9518))
- Parity-version: mark 2.1.0 track beta
- Ci: update branch version references
- Docker: release master to latest
- Fix checkpointing when creating contract failed ([#9514](https://github.com/paritytech/parity-ethereum/pull/9514))
- Ci: fix json docs generation ([#9515](https://github.com/paritytech/parity-ethereum/pull/9515))
- Fix typo in version string ([#9516](https://github.com/paritytech/parity-ethereum/pull/9516))
- Update patricia trie to 0.2.2 crates. Default dependencies on minor version only.
- Putting back ethereum tests to the right commit
- Enable all Constantinople hard fork changes in constantinople_test.json ([#9505](https://github.com/paritytech/parity-ethereum/pull/9505))
- Enable all Constantinople hard fork changes in constantinople_test.json
- Address grumbles
- Remove EIP-210 activation
- 8m -> 5m
- Temporarily add back eip210 transition so we can get test passed
- Add eip210_test and remove eip210 transition from const_test
- In create memory calculation is the same for create2 because the additional parameter was popped before. ([#9522](https://github.com/paritytech/parity-ethereum/pull/9522))
- Deps: bump fs-swap and kvdb-rocksdb
- Multithreaded snapshot creation ([#9239](https://github.com/paritytech/parity-ethereum/pull/9239))
- Add Progress to Snapshot Secondary chunks creation
- Use half of CPUs to multithread snapshot creation
- Use env var to define number of threads
- Info to debug logs
- Add Snapshot threads as CLI option
- Randomize chunks per thread
- Remove randomness, add debugging
- Add warning
- Add tracing
- Use parity-common fix seek branch
- Fix log
- Fix tests
- Fix tests
- Pr Grumbles
- Pr Grumble II
- Update Cargo.lock
- Pr Grumbles
- Default snapshot threads to half number of CPUs
- Fix default snapshot threads // min 1
- Correct before_script for nightly build versions ([#9543](https://github.com/paritytech/parity-ethereum/pull/9543))
- Fix gitlab array of strings syntax error
- Get proper commit id
- Avoid colon in stings
- Remove initial token for WS. ([#9545](https://github.com/paritytech/parity-ethereum/pull/9545))
- Version: mark release critical
- Ci: fix rpc docs generation 2 ([#9550](https://github.com/paritytech/parity-ethereum/pull/9550))
- Improve P2P discovery ([#9526](https://github.com/paritytech/parity-ethereum/pull/9526))
- Add `target` to Rust traces
- Network-devp2p: Don't remove discovery peer in main sync
- Network-p2p: Refresh discovery more often
- Update Peer discovery protocol
- Run discovery more often when not enough nodes connected
- Start the first discovery early
- Update fast discovery rate
- Fix tests
- Fix `ping` tests
- Fixing remote Node address ; adding PingPong round
- Fix tests: update new +1 PingPong round
- Increase slow Discovery rate
- Check in flight FindNode before pings
- Add `deprecated` to deprecated_echo_hash
- Refactor `discovery_round` branching
- Net_version caches network_id to avoid redundant acquire of sync read lock ([#9544](https://github.com/paritytech/parity-ethereum/pull/9544))
- Net_version caches network_id to avoid redundant acquire of sync read lock, [#8746](https://github.com/paritytech/parity-ethereum/issues/8746)
- Use lower_hex display formatting for net_peerCount rpc method
- Increase Gas-floor-target and Gas Cap ([#9564](https://github.com/paritytech/parity-ethereum/pull/9564))
- Gas-floor-target increased to 8M by default
- Gas-cap increased to 10M by default
- Revert to old parity-tokio-ipc.
- Downgrade named pipes.
- Fix checkpointing when creating contract failed ([#9514](https://github.com/paritytech/parity-ethereum/pull/9514))
- Ci: fix json docs generation ([#9515](https://github.com/paritytech/parity-ethereum/pull/9515))
- Update state tests execution model ([#9440](https://github.com/paritytech/parity-ethereum/pull/9440))
- Update & fix JSON state tests.
- Update tests to be able to run ethtest at 021fe3d410773024cd5f0387e62db6e6ec800f32.
- Touch user in state
- Adjust transaction tests to new json format
- Switch to same commit for submodule ethereum/test as geth (next includes constantinople changes).
- Added test `json_tests::trie::generic::TrieTests_trieanyorder` and a few difficulty tests.
- Remove trietestnextprev as it would require to parse differently and implement it.
- Support new (shitty) format of transaction tests.
- Ignore junk in ethereum/tests repo.
- Ignore incorrect test.
- Update to a later commit
- Move block number to a constant.
- Fix ZK2 test - touched account should also be cleared.
- Fix conflict resolution
- Upload will fail if a file with the same hash is already up ([#9479](https://github.com/paritytech/parity-ethereum/pull/9479))
- Upload will fail if a file with the same hash is already up
- Compose version string for nightly releases
- Fix Snapshot restoration failure on Windows ([#9491](https://github.com/paritytech/parity-ethereum/pull/9491))
- Close Blooms DB files before DB restoration
- Don't error when Snapshot is aborted ([#9492](https://github.com/paritytech/parity-ethereum/pull/9492))
- Light: give free credits for reserved peers ([#9448](https://github.com/paritytech/parity-ethereum/pull/9448))
- Light: give free credits for reserved peers
- Fix ethcore-light tests
- Test free_flow_params
- Parity: print correct keys path on startup ([#9501](https://github.com/paritytech/parity-ethereum/pull/9501))
- Generalized blockReward and difficultyBombDelays config ([#9480](https://github.com/paritytech/parity-ethereum/pull/9480))
- Implement multi blockReward
- Implement difficultyBombDelays
- Fix json crate compile
- Json keys can only be string
- Rpc(debug_getBadBlocks): fix test ([#9502](https://github.com/paritytech/parity-ethereum/pull/9502))
- Bad blocks RPC + reporting ([#9433](https://github.com/paritytech/parity-ethereum/pull/9433))
- Bad blocks RPC.
- Return bad blocks via RPC.
- Fix test.
- More verbose bad block message.
- Expose via CLI.
- Remove stray whitespace.
- Remove stray newline.
- Fix tests.
- Eip 1283: Net gas metering for SSTORE without dirty maps ([#9319](https://github.com/paritytech/parity-ethereum/pull/9319))
- Implement last_checkpoint_storage_at
- Add reverted_storage_at for externalities
- Sstore_clears_count -> sstore_clears_refund
- Implement eip1283 for evm
- Add eip1283Transition params
- Evm: fix tests
- Jsontests: fix test
- Return checkpoint index when creating
- Comply with spec Version II
- Fix docs
- Fix jsontests feature compile
- Address grumbles
- Fix no-checkpoint-entry case
- Remove unnecessary expect
- Add test for State::checkpoint_storage_at
- Add executive level test for eip1283
- Hard-code transaction_checkpoint_index to 0
- Fix jsontests
- Add tests for checkpoint discard/revert
- Require checkpoint to be empty for kill_account and commit
- Get code coverage
- Use saturating_add/saturating_sub
- Fix issues in insert_cache
- Clear the state again
- Fix original_storage_at
- Early return for empty RLP trie storage
- Update comments
- Fix borrow_mut issue
- Simplify checkpoint_storage_at if branches
- Better commenting for gas handling code
- Address naming grumbles
- More tests
- Fix an issue in overwrite_with
- Add another test
- Fix comment
- Remove unnecessary bracket
- Move orig to inner if
- Remove test coverage for this PR
- Add tests for executive original value
- Add warn! for an unreachable cause
- Light `clippy(fy)` ([#9473](https://github.com/paritytech/parity-ethereum/pull/9473))
- Wasm tests
- `clippyfy` light-client
- Revert inefficient change `collect_ready()`
- Aura: don't report skipped primaries when empty steps are enabled ([#9435](https://github.com/paritytech/parity-ethereum/pull/9435))
- Support millisecond timestamp for instant seal engine ([#9469](https://github.com/paritytech/parity-ethereum/pull/9469))
- Support millisecond timestamp for instant seal engine
- Forgot to checkin instant_seal mod
- Fix instant seal config
- Fix json crate compile
- Fix private_spec.json
- Option<bool> -> bool
- Ethcore: don't validate difficulty when ignoring seal check ([#9470](https://github.com/paritytech/parity-ethereum/pull/9470))
- Ethcore: don't validate difficulty when ignoring seal check
- Ethcore: fix block verification test
- Ethcore: document skipped verifications when check_seal is disabled
- [light/jsonrpc] Provide the actual account for `eth_coinbase` RPC and unify error handling for light and full client ([#9383](https://github.com/paritytech/parity-ethereum/pull/9383))
- Provide the actual `account` for eth_coinbase
- The previous implementation always provided the `zero address` on `eth_coinbase` RPC. Now, instead the actual address is returned on success or an error when no account(s) is found!
- Full client `eth_coinbase` return err
- In the full-client return an error when no account is found instead of returning the `zero address`
- Remove needless blocks on single import
- Remove needless `static` lifetime on const
- Fix `rpc_eth_author` test
- Add a Java interface ([#9346](https://github.com/paritytech/parity-ethereum/pull/9346))
- Add a Java interface
- Use system ABI
- Forgot exception
- Fix param for parity_rpc
- Address concerns
- Fetch `parity-common` crates from crates.io ([#9410](https://github.com/paritytech/parity-ethereum/pull/9410))
- Fetch `parity-common` crates from crates.io
- Add doc tests from `patricia-trie` to `patricia-trie-ethereum`
- Fix/update a few deps
- [ethkey] upgrade ethereum-types
- [whisper] update deps
- [network] deps
- [network-devp2p] deps
- [journaldb] deps
- [fastmap] deps
- [miner] deps and test fixes
- [machine] deps
- [json] deps
- [hw] deps
- [ethash] deps
- [registrar] deps
- Update a few more dependencies with new ethabi-*
- [updater] Update deps
- Deps
- [ethcore] Update deps
- Use new parity-snappy and parity-rocksdb crates
- Updated submodules
- Use parity-snappy 0.1
- Use kvdb-rocksdb 0.1.2
- Don't use latest ethereum/tests
- Fix merge conflicts errors
- Remove superseeded comment
- Address grumbles: add newlines, add/remove spaces
- Fixed typo ([#9467](https://github.com/paritytech/parity-ethereum/pull/9467))
- Fix light client deadlock ([#9385](https://github.com/paritytech/parity-ethereum/pull/9385))
- This PR is fixing deadlock for [#8918](https://github.com/paritytech/parity-ethereum/issues/8918)
- It avoids some recursive calls on light_sync by making state check optional for Informant.
- The current behavior is to display the information when informant checks if block is major version.
- This change a bit the informant behavior, but not on most cases.
- To remember where and how this kind of deadlock are likely to happen (not seen with Parkinglot deadlock detection because it uses std condvar), I am adding a description of the deadlock.
- Also, for the reviewers there may be better solution than modifying the informant.
- Fix docs of address_hash ([#9463](https://github.com/paritytech/parity-ethereum/pull/9463))
- Fix typo in bash script ([#9462](https://github.com/paritytech/parity-ethereum/pull/9462))
- Fix a bug in evmbin initial_gas display ([#9457](https://github.com/paritytech/parity-ethereum/pull/9457))
- Evmbin: escape newlines in json errors ([#9458](https://github.com/paritytech/parity-ethereum/pull/9458))
- Use kvdb-* and parity-snappy crates from crates.io ([#9441](https://github.com/paritytech/parity-ethereum/pull/9441))
- Use kvdb-* and parity-snappy crates from crates.io
- Update rocksdb-sys and snappy-sys
- Add EIP-1014 transition config flag ([#9268](https://github.com/paritytech/parity-ethereum/pull/9268))
- Add EIP-1014 transition config flag
- Remove EIP-86 configs
- Change CREATE2 opcode index to 0xf5
- Move salt to the last item in the stack
- Change sendersaltandaddress scheme to comply with current EIP-1014
- Fix json configs
- Fix create2 test
- Fix deprecated comments
- Add tags for runner selection of build-linux jobs ([#9451](https://github.com/paritytech/parity-ethereum/pull/9451))
- Remove unused BlockStatus::Pending ([#9447](https://github.com/paritytech/parity-ethereum/pull/9447))
- Pending case never instantiated, and only ever matched together with Unknown
- Ci: only include local paths in coverage script (except target) ([#9437](https://github.com/paritytech/parity-ethereum/pull/9437))
- Add POA Networks: Core and Sokol ([#9413](https://github.com/paritytech/parity-ethereum/pull/9413))
- Ethcore: add poa network and sokol chainspecs
- Rpc: simplify chain spec docs
- Cli: rearrange networks by main/test and size/range
- Parity: don't blacklist 0x00a328 on sokol testnet
- Parity: add sokol and poanet to params and clean up a bit, add tests
- Ethcore: add the poa networks and clean up a bit
- Ethcore: fix path to poacore chain spec
- Parity: rename poa networks to poacore and poasokol
- Parity: fix configuration tests
- Parity: fix parameter tests
- Ethcore: rename POA Core and POA Sokol
- Docker: install missing dependencies in arm target dockerfiles ([#9436](https://github.com/paritytech/parity-ethereum/pull/9436))
- Random small cleanups ([#9423](https://github.com/paritytech/parity-ethereum/pull/9423))
- Clean up toml files
- Update the parity ethereum toolchain docs
- Update contribution guide and issue templates
- Update desktop and service files
- Build clib examples with 8 threads
- Update header templates
- Replace parity technologies with parity ethereum logo
- Evmbin: Fix gas_used issue in state root mismatch and handle output better ([#9418](https://github.com/paritytech/parity-ethereum/pull/9418))
- Fix gas used in staterootmismatch, and print full state root hash
- Write trace info for stdjson to stderr
- Fix tests
- Remove struct trait bound
- Update hardcoded sync ([#9421](https://github.com/paritytech/parity-ethereum/pull/9421))
- Update foundation hardcoded header to block 6219777
- Update ropsten hardcoded header to block 3917825
- Update kovan hardcoded header to block 8511489
- Add block reward contract config to ethash and allow off-chain contracts ([#9312](https://github.com/paritytech/parity-ethereum/pull/9312))
- This adds block reward contract config to ethash. A new config `blockRewardContractCode` is also added to both Aura and ethash. When specified, it will execute the code directly and overrides any `blockRewardContractAddress` config. Having this `blockRewardContractCode` config allows chains to deploy hard fork by simply replacing the current config value, without the need from us to support any `multi` block reward scheme.
- Private packets verification and queue refactoring ([#8715](https://github.com/paritytech/parity-ethereum/pull/8715))
- Verify private transaction before propagating
- Private transactions queue reworked with tx pool queue direct usage
- Styling fixed
- Prevent resending private packets to the sender
- Process signed private transaction packets via io queue
- Test fixed
- Build and test fixed after merge
- Comments after review fixed
- Signed transaction taken from verified
- Fix after merge
- Pool scoring generalized in order to use externally
- Lib refactored according to the review comments
- Ready state refactored
- Redundant bound and copying removed
- Fixed build after the merge
- Forgotten case reworked
- Review comments fixed
- Logging reworked, target added
- Fix after merge
- Update tobalaba.json ([#9419](https://github.com/paritytech/parity-ethereum/pull/9419))
- Docs: add parity ethereum logo to readme ([#9415](https://github.com/paritytech/parity-ethereum/pull/9415))
- Docs: add parity ethereum logo
- Docs: add logo to readme
- Docs: align logo center
- Docs: remove separators from readme
- Docs: restructure readme
- Docs: check spelling and grammar in readme
- Docs: clarify readme
- Docs: improve readme significantly
- Build: update rocksdb crate ([#9414](https://github.com/paritytech/parity-ethereum/pull/9414))
- Updating the CI system ([#8765](https://github.com/paritytech/parity-ethereum/pull/8765))
- Updating the CI system with the publication of releases and binary files on github
- Add missed scripts
- Chmod +x scripts
- Fix download link for github
- Rebuilding CI scripts
- Small fixes
- Update submodule wasm tests
- Ci: fix merge leftovers
- Ci: remove gitlab-next from ci triggers
- Ci: fix git add in docs script
- Ci: use nightly instead of master for publish triggers
- Ci: remove sleep from gitlab config
- Ci: replace ':' with '-' in gitlab targets
- Ci: fix recursive copy in docs script
- Better support for eth_getLogs in light mode ([#9186](https://github.com/paritytech/parity-ethereum/pull/9186))
- Light client on-demand request for headers range.
- Cache headers in HeaderWithAncestors response.
- Also fulfills request locally if all headers are in cache.
- Lightfetch::logs fetches missing headers on demand.
- Lightfetch::logs limit the number of headers requested at a time.
- Lightfetch::logs refactor header fetching logic.
- Enforce limit on header range length in light client logs request.
- Fix light request tests after struct change.
- Respond to review comments.
- Add update docs script to CI ([#9219](https://github.com/paritytech/parity-ethereum/pull/9219))
- Add update docs script to CI
- Added a script to CI that will use the jsonrpc tool to update rpc documentation then commit and push those to the wiki repo.
- Fix gitlab ci lint
- Only apply jsonrpc docs update on tags
- Update gitlab-rpc-docs.sh
- Copy correct parity repo to jsonrpc folder
- Copy correct parity repo to jsonrpc folder before attempting to build docs since the CI runner clones the repo as parity and not parity-ethereum.
- Fix JSONRPC docs CI job
- Update remote config in wiki repo before pushing changes using a github token for authentication. Add message to wiki tag when pushing changes. Use project directory to correctly copy parity code base into the jsonrpc repo for doc generation.
- Fix set_remote_wiki function call in CI
- `gasleft` extern implemented for WASM runtime (kip-6) ([#9357](https://github.com/paritytech/parity-ethereum/pull/9357))
- Wasm gasleft extern added
- Wasm_gasleft_activation_transition -> kip4_transition
- Use kip-6 switch
- Gasleft_panic -> gasleft_fail rename
- Call_msg_gasleft test added and gas_left agustments because this paritytech/wasm-tests#52
- Change .. to _
- Fix comment for the have_gasleft param
- Update tests (paritytech/wasm-tests-0edbf86)
- Block view! removal in progress ([#9397](https://github.com/paritytech/parity-ethereum/pull/9397))
- Prevent sync restart if import queue full ([#9381](https://github.com/paritytech/parity-ethereum/pull/9381))
- Nonroot CentOS Docker image ([#9280](https://github.com/paritytech/parity-ethereum/pull/9280))
- Updates CentOS Docker image build process
- Rename build.Dockerfile
- Ethcore: kovan: delay activation of strict score validation ([#9406](https://github.com/paritytech/parity-ethereum/pull/9406))
- Revert "Use std::sync::Condvar ([#1732](https://github.com/paritytech/parity-ethereum/pull/1732))" ([#9392](https://github.com/paritytech/parity-ethereum/pull/9392))
- Revert "Use std::sync::Condvar ([#1732](https://github.com/paritytech/parity-ethereum/pull/1732))"
- This reverts commit c65ee93.
- Verification_queue: remove redundant mutexes
- Replace `std::env::home_dir()` with `home` crate impl. ([#9293](https://github.com/paritytech/parity-ethereum/pull/9293))
- Import the `home` crate in `util/dir`.
- Replace uses of `env::home_dir()` with `home::home_dir()`.
- `home` uses a 'correct' impl. on windows and the stdlib impl. of `::home_dir` otherwise.
- Reexport `home::home_dir` from `util/dir`.
- Bump `util/dir` to 0.1.2.
- Docs: restore readme ([#9391](https://github.com/paritytech/parity-ethereum/pull/9391))
- Replace `Duration::new()` w/ `Duration::from_nanos` ([#9387](https://github.com/paritytech/parity-ethereum/pull/9387))
- Delete Dockerfile ([#9386](https://github.com/paritytech/parity-ethereum/pull/9386))
- Network-devp2p `Fix some clippy errors/warnings` ([#9378](https://github.com/paritytech/parity-ethereum/pull/9378))
- Fix some clippy warnings
- Remove `shallow-copy` of Node's
- Make `NonReservedPeerMode` Copy and pass-by-value
- Allow calling contracts in genesis state. ([#9375](https://github.com/paritytech/parity-ethereum/pull/9375))
- Make `Capabilities struct` Copy ([#9372](https://github.com/paritytech/parity-ethereum/pull/9372))
- Light client "Enable more logs for light client `on_demand`" ([#9374](https://github.com/paritytech/parity-ethereum/pull/9374))
- Enable more logs for light client `on_demand`
- Remove extra whitespace
- Fix indentation
- Better logging when mining own transactions. ([#9363](https://github.com/paritytech/parity-ethereum/pull/9363))
- Fix typos in `network-devp2p` ([#9371](https://github.com/paritytech/parity-ethereum/pull/9371))
- Light client `Provide default nonce in transactions when it´s missing` ([#9370](https://github.com/paritytech/parity-ethereum/pull/9370))
- Provide `default_nonce` in tx`s when it´s missing
- When `nonce` is missing in a `EthTransaction` will cause it to fall in these cases provide `default_nonce` value instead!
- Changed http:// to https:// on Yasm link ([#9369](https://github.com/paritytech/parity-ethereum/pull/9369))
- Changed http:// to https:// on Yasm link in README.md
- Provide `default_nonce` in tx`s when it´s missing
- When `nonce` is missing in a `EthTransaction` will cause it to fall in these cases provide `default_nonce` value instead!
- Address grumbles
- Changed http:// to https:// on Yasm link ([#9369](https://github.com/paritytech/parity-ethereum/pull/9369))
- Changed http:// to https:// on Yasm link in README.md
- Fix no line breaks in logs ([#9355](https://github.com/paritytech/parity-ethereum/pull/9355))
- Lower the max size of transaction packet to prevent going oversize. ([#9308](https://github.com/paritytech/parity-ethereum/pull/9308))
- Lower the max size of transaction packet to prevent going oversize.
- Log RLP size.
- Remove prepare_trace_output and make sure prepare_trace_call and trace*call are balanced ([#9353](https://github.com/paritytech/parity-ethereum/pull/9353))
- This refactors `prepare_trace_output` to instead directly take the reference of return values, so that it's simpler and we save a stack item. This should also fixes [the issue]([#9236](https://github.com/paritytech/parity-ethereum/pull/9236) (comment)) udoprog is facing. Replaces [#9236](https://github.com/paritytech/parity-ethereum/issues/9236)
- More details in logs returned by light client ([#9324](https://github.com/paritytech/parity-ethereum/pull/9324))
- Log details for light logs.
- Create Log directly.
- Expose UnorderedIterator. ([#9347](https://github.com/paritytech/parity-ethereum/pull/9347))
- Light client logs should include 'from_block' when querying logs ([#9331](https://github.com/paritytech/parity-ethereum/pull/9331))
- Fix PubSub for logs when using light client:
- Prior to this fix the pubsub process did send a query for each new block header (and for each subs: there is something to optimize here) by setting from and to of the filter at this block number; but there was a bug in the code that fetch logs : it was non inclusive for its start bound, meaning that with start bound = end bound we never query any block (and attached logs).
- Option iter instead of once.
- Use of bloom existing function to check if a bloom contains another.
- Makes from block header checking explicit
- Remove pass-by-reference return data value from executive ([#9211](https://github.com/paritytech/parity-ethereum/pull/9211))
- Remove pass-by-reference return data value from executive
- Fix tests
- Fix a missing test output
- Typo: wasm_activation_test
- Tracing change in output
- Json_tests: fix compile
- Typo: 0..32 -> ..32 to keep it consistent with other occurance
- Fix tests
- Allow single opcode stepping for EVM ([#9051](https://github.com/paritytech/parity-ethereum/pull/9051))
- Feed in ActionParams on VM creation
- Fix ethcore after Vm interface change
- Move informant inside Interpreter struct
- Move do_trace to Interpreter struct
- Move all remaining exec variables to Interpreter struct
- Refactor VM to allow single opcode step
- Fix all EVM tests
- Fix all wasm tests
- Fix wasm runner tests
- Fix a check case where code length is zero
- Fix jsontests compile
- Fix cargo lock
- Use match instead of expect
- Use cheaper check reader.len() == 0 for the initial special case
- Get rid of try_and_done! macro by using Result<(), ReturnType>
- Use Never instead of ()
- Fix parity-bytes path
- Bypass gasometer lifetime problem by borrow only for a instance
- Typo: missing {
- Fix ethcore test compile
- Fix evm tests
- Fix load share ([#9321](https://github.com/paritytech/parity-ethereum/pull/9321))
- Fix(light_sync): calculate `load_share` properly
- Refactor(api.rs): extract `light_params` fn, add test
- Style(api.rs): add trailing commas
- Implement EIP234 block_hash for eth_getLogs ([#9256](https://github.com/paritytech/parity-ethereum/pull/9256))
- Implement EIP234
- Make filter conversion returns error if both blockHash and from/toBlock is found
- This also changes PollFilter to store the EthFilter type, instead of the jsonrpc one, saving repeated conversion.
- Return error if block filtering target is not found in eth_getLogs
- Use the old behavior (unwrap_or_default) for anywhere else.
- Fix test: secret_store
- Fix weird indentation
- Make client log filter return error in case a block cannot be found
- Return blockId error in rpc
- Test_client: allow return error on logs
- Add a mocked test for eth_getLogs error
- Fix: should return error if from_block/to_block greater than best block number
- Add notes on pending
- Add comment for UNSUPPORTED_REQUEST
- Address grumbles
- Return err if from > to
- Ethcore: fix pow difficulty validation ([#9328](https://github.com/paritytech/parity-ethereum/pull/9328))
- Ethcore: fix pow difficulty validation
- Ethcore: validate difficulty is not zero
- Ethcore: add issue link to regression test
- Ethcore: fix tests
- Ethcore: move difficulty_to_boundary to ethash crate
- Ethcore: reuse difficulty_to_boundary and boundary_to_difficulty
- Ethcore: fix grumbles in difficulty_to_boundary_aux
- Ethcore/sync `Make view macro only visible to test` ([#9316](https://github.com/paritytech/parity-ethereum/pull/9316))
- Remove needless macro import
- Enable ethcore/macros in tests
- Allow setting the panic hook with parity-clib ([#9292](https://github.com/paritytech/parity-ethereum/pull/9292))
- Allow setting the panic hook with parity-clib
- Make all FFI functions unsafe
- Fix comment
- Fix concern
- Prevent blockchain & miner racing when accessing pending block. ([#9310](https://github.com/paritytech/parity-ethereum/pull/9310))
- Prevent blockchain & miner racing when accessing pending block.
- Fix unavailability of pending block during reseal.
- Docker alpine: use multi-stage concept ([#9269](https://github.com/paritytech/parity-ethereum/pull/9269))
- Docker alpine: use multi-stage concept
- Docker alpine: create config directory
- Update `log` -> 0.4, `env_logger` -> 0.5. ([#9294](https://github.com/paritytech/parity-ethereum/pull/9294))
- Rename a few types & methods.
- Change `(Log)Builder::format` (closure) arg.
- Update tobalaba.json ([#9313](https://github.com/paritytech/parity-ethereum/pull/9313))
- Allow tx pool to be Send ([#9315](https://github.com/paritytech/parity-ethereum/pull/9315))
- Fix codecov.io badge in README ([#9327](https://github.com/paritytech/parity-ethereum/pull/9327))
- Move ethereum-specific H256FastMap type to own crate ([#9307](https://github.com/paritytech/parity-ethereum/pull/9307))
- Add a `fastmap` crate that provides the H256FastMap specialized HashMap
- Use `fastmap` instead of `plain_hasher`
- Update submodules for Reasons™
- Submodule update
- Ethcore sync decodes rlp less often ([#9264](https://github.com/paritytech/parity-ethereum/pull/9264))
- Deserialize block only once during verification
- Ethcore-sync uses Unverified
- Ethcore-sync uses Unverified
- Fixed build error
- Removed Block::is_good
- Applied review suggestions
- Ethcore-sync deserializes headers and blocks only once
- Ethcore: add transition flag for transaction permission contract ([#9275](https://github.com/paritytech/parity-ethereum/pull/9275))
- Ethcore: add transition flag for transaction permission contract
- Ethcore: fix transaction permission contract tests
- Remove all dapp permissions related settings ([#9120](https://github.com/paritytech/parity-ethereum/pull/9120))
- Completely remove all dapps struct from rpc
- Remove unused pub use
- Remove dapp policy/permission func in ethcore
- Remove all dapps settings from rpc
- Fix rpc tests
- Use both origin and user_agent
- Address grumbles
- Address grumbles
- Fix tests
- Improve return data truncate logic ([#9254](https://github.com/paritytech/parity-ethereum/pull/9254))
- Improve return data truncate logic
- Fix: size -> offset + size
- Update wasm-tests hash ([#9295](https://github.com/paritytech/parity-ethereum/pull/9295))
- Implement KIP4: create2 for wasm ([#9277](https://github.com/paritytech/parity-ethereum/pull/9277))
- Basic implementation for kip4
- Add KIP-4 config flags
- Typo: docs fix
- Fix args offset
- Add tests for create2
- Tests: evm
- Update wasm-tests and fix all gas costs
- Update wasm-tests
- Update wasm-tests and fix gas costs
- Fix loop start value ([#9285](https://github.com/paritytech/parity-ethereum/pull/9285))
- Avoid using $HOME if not necessary ([#9273](https://github.com/paritytech/parity-ethereum/pull/9273))
- Avoid using $HOME if not necessary
- Fix concerns and issues
- Fix path to parity.h ([#9274](https://github.com/paritytech/parity-ethereum/pull/9274))
- Fix path to parity.h
- Fix other paths as well
- Propagate transactions for next 4 blocks. ([#9265](https://github.com/paritytech/parity-ethereum/pull/9265))
- Closes [#9255](https://github.com/paritytech/parity-ethereum/issues/9255)
- This PR also removes the limit of max 64 transactions per packet, currently we only attempt to prevent the packet size to go over 8MB. This will only be the case for super-large transactions or high-block-gas-limit chains. Patching this is important only for chains that have blocks that can fit more than 4k transactions (over 86M block gas limit) For mainnet, we should actually see a tiny bit faster propagation since instead of computing 4k pending set, we only need `4 * 8M / 21k = 1523` transactions. Running some tests on `dekompile` node right now, to check how it performs in the wild.
- Decode block rlp less often ([#9252](https://github.com/paritytech/parity-ethereum/pull/9252))
- Removed 4 redundant rlp deserializations
- Avoid 1 redundant block data copy
- Fix eternalities tests can_create (missing parameter) ([#9270](https://github.com/paritytech/parity-ethereum/pull/9270))
- Update ref to `parity-common` and update `seek` behaviour ([#9257](https://github.com/paritytech/parity-ethereum/pull/9257))
- Update ref to `parity-common` and update `seek` behaviour
- Remove reference to `ng-fix-triedb-seek` branch
- Comply EIP-86 with the new definition ([#9140](https://github.com/paritytech/parity-ethereum/pull/9140))
- Comply EIP-86 with the new CREATE2 opcode
- Fix rpc compile
- Fix interpreter CREATE/CREATE2 stack pop difference
- Add unreachable! to fix compile
- Fix instruction_info
- Fix gas check due to new stack item
- Add new tests in executive
- Fix have_create2 comment
- Remove all unused references of eip86_transition and block_number
- Check if synced when using eth_getWork ([#9193](https://github.com/paritytech/parity-ethereum/pull/9193)) ([#9210](https://github.com/paritytech/parity-ethereum/pull/9210))
- Check if synced when using eth_getWork ([#9193](https://github.com/paritytech/parity-ethereum/pull/9193))
- Don't use fn syncing
- Fix identation
- Fix typo
- Don't check for warping
- Rpc: avoid calling queue_info twice on eth_getWork
- Removed client error ([#9253](https://github.com/paritytech/parity-ethereum/pull/9253))
- Implement EIP-1052 (EXTCODEHASH) and fix several issues in state account cache ([#9234](https://github.com/paritytech/parity-ethereum/pull/9234))
- Implement EIP-1052 and fix several issues related to account cache
- Fix jsontests
- Merge two matches together
- Avoid making unnecessary Arc<Vec>
- Address grumbles
- Improve Tracer documentation ([#9237](https://github.com/paritytech/parity-ethereum/pull/9237))
- Update Dockerfile ([#9242](https://github.com/paritytech/parity-ethereum/pull/9242))
- Update Dockerfile
- Fix Docker build
- Fix dockerfile paths: parity -> parity-ethereum ([#9248](https://github.com/paritytech/parity-ethereum/pull/9248))
- Block cleanup ([#9117](https://github.com/paritytech/parity-ethereum/pull/9117))
- Blockchain insert expects owned block instead of block reference
- Reduce a number of times a block is deserialized
- Removed cached uncle_bytes from block
- Removed is_finalized from OpenBlock
- Removed unused parity_machine::WithMetadata trait
- Removed commented out code
- Remove unused metadata from block
- Remove unused metadata from block
- Blockdetails extras may have at most 5 elements
- Increase the number of sessions. ([#9203](https://github.com/paritytech/parity-ethereum/pull/9203))
- Add changelog for 1.11.8 stable and 2.0.1 beta ([#9230](https://github.com/paritytech/parity-ethereum/pull/9230))
- Docs: add changelog for 1.11.8 stable
- Docs: add changelog for 2.0.1 beta
- Fix typo ([#9232](https://github.com/paritytech/parity-ethereum/pull/9232))
- Fix potential as_usize overflow when casting from U256 in miner ([#9221](https://github.com/paritytech/parity-ethereum/pull/9221))
- Allow old blocks from peers with lower difficulty ([#9226](https://github.com/paritytech/parity-ethereum/pull/9226))
- Previously we only allow downloading of old blocks if the peer difficulty was greater than our syncing difficulty. This change allows downloading of blocks from peers where the difficulty is greater then the last downloaded old block.
- Removes duplicate libudev-dev from Dockerfile ([#9220](https://github.com/paritytech/parity-ethereum/pull/9220))
- Snap: remove ssl dependencies from snapcraft definition ([#9222](https://github.com/paritytech/parity-ethereum/pull/9222))
- Remove ssl from dockerfiles, closes [#8880](https://github.com/paritytech/parity-ethereum/issues/8880) ([#9195](https://github.com/paritytech/parity-ethereum/pull/9195))
- Insert PROOF messages for some cases in blockchain ([#9141](https://github.com/paritytech/parity-ethereum/pull/9141))
- Insert PROOF messages for some cases in blockchain
- Break expect to its own line to avoid things being too long
- Be more specific for all low-level database error cases
- Fix BranchBecomingCanonChain expect
- Ethcore: fix typo in expect proof message
- [chain] Add more bootnodes ([#9174](https://github.com/paritytech/parity-ethereum/pull/9174))
- For ETC, ELLA, EXP, Morden, MUSIC
- Ethcore: update bn version ([#9217](https://github.com/paritytech/parity-ethereum/pull/9217))
- Deserialize block only once during verification ([#9161](https://github.com/paritytech/parity-ethereum/pull/9161))
- Simple build instruction fix ([#9215](https://github.com/paritytech/parity-ethereum/pull/9215))
- Changed `parity` dir name into `parity-ethereum`
- Added --tx-queue-no-early-reject flag to disable early tx queue rejects ([#9143](https://github.com/paritytech/parity-ethereum/pull/9143))
- Added --tx-queue-no-early-reject flag to disable early tx queue rejects because of low gas price
- Fixed failing tests, clarified comments and simplified no_early_reject field name.
- Added test case for the --tx-queue-no-early-reject flag
- Avoid schedule copying in nested call/create ([#9190](https://github.com/paritytech/parity-ethereum/pull/9190))
- Avoid schedule copying in nested call/create
- Fix tests
- Fix test: wrong Schedule used
- Fix private-tx test
- Fix jsontests compilation
- Ethcore: add builtin benchmarks based on geth ([#9179](https://github.com/paritytech/parity-ethereum/pull/9179))
- Ethcore: add geth benchmarks for all builtins
- Ethcore: remove old builtin benchmarks
- Rpc: fix is_major_importing sync state condition ([#9112](https://github.com/paritytech/parity-ethereum/pull/9112))
- Rpc: fix is_major_importing sync state condition
- Rpc: fix informant printout when waiting for peers
- Docs: update repository links ([#9159](https://github.com/paritytech/parity-ethereum/pull/9159))
- Docs: update repository links
- Docs: update repository links in contribution guide
- Parity: fix UserDefaults json parser ([#9189](https://github.com/paritytech/parity-ethereum/pull/9189))
- Parity: fix UserDefaults json parser
- Parity: use serde_derive for UserDefaults
- Parity: support deserialization of old UserDefault json format
- Parity: make UserDefaults serde backwards compatible
- Parity: tabify indentation in UserDefaults
- Update "This is a bug. Please report it at:" link ([#9191](https://github.com/paritytech/parity-ethereum/pull/9191))
- Docker: update hub dockerfile ([#9173](https://github.com/paritytech/parity-ethereum/pull/9173))
- Update Dockerfile for hub
- Update to Ubuntu Xenial 16.04
- Fix cmake version
- Docker: fix tab indentation in hub dockerfile
- Ci: update version strings for snaps ([#9160](https://github.com/paritytech/parity-ethereum/pull/9160))
- Ethcore: add missing builtins benchmarks ([#9170](https://github.com/paritytech/parity-ethereum/pull/9170))
- Ethcore: add modexp benchmarks
- Ethcore: add_bn_128_add benchmark
- Fix bugfix hard fork logic ([#9138](https://github.com/paritytech/parity-ethereum/pull/9138))
- Fix bugfix hard fork logic
- Remove dustProtectionTransition from bugfix category
- Eip-168 is not enabled by default
- Remove unnecessary 'static
- Be more graceful on Aura difficulty validation ([#9164](https://github.com/paritytech/parity-ethereum/pull/9164))
- Be more graceful on Aura difficulty validation
- Test: rejects_step_backwards
- Test: proposer_switching
- Test: rejects_future_block
- Test: reports_skipped
- Test: verify_empty_seal_steps
- Handle SyncHandler errors properly ([#9151](https://github.com/paritytech/parity-ethereum/pull/9151))
- Handle SyncHandler errors properly, closes [#9150](https://github.com/paritytech/parity-ethereum/issues/9150)
- Applied review suggestions
- Remove node-health ([#9119](https://github.com/paritytech/parity-ethereum/pull/9119))
- Remove node-health
- Remove ntp_servers
- Add --ntp-servers as legacy instead of removing it
- Add --ntp-servers to deprecated args
- Remove unused stuff
- Remove _legacy_ntp_servers
- Remove unused tx_queue_gas parameter. ([#9153](https://github.com/paritytech/parity-ethereum/pull/9153))
- Changelogs for 1.11.7-stable and 2.0.0-beta ([#9105](https://github.com/paritytech/parity-ethereum/pull/9105))
- Docs: mark 1.10 as end-of-life
- Docs: move changelog for 1.11
- Docs: Add changelog for 1.11.7-stable
- Docs: add changelog for 2.0.0-beta
- Docs: add release notes for 2.0.0 beta
- Docs: fix links in changelog
- Docs: Update changelog for 1.11.7-stable
- Docs: Update changelog for 2.0.0-beta
- Docs: address Tbaut's comments for the 2.0.0-beta changelog
- Docs: add note regarding txqueue changes as recommended by tomusdrw
- Disable per-sender limit for local transactions. ([#9148](https://github.com/paritytech/parity-ethereum/pull/9148))
- Disable per-sender limit for local transactions.
- Add a missing new line.
- Parity: fix logging cli parameter example ([#9154](https://github.com/paritytech/parity-ethereum/pull/9154))
- Be more specific for `-l` CLI arguments ([#9149](https://github.com/paritytech/parity-ethereum/pull/9149))
- Update mod.rs
- Receipt constructor `Allocate less stack for blooms` ([#9146](https://github.com/paritytech/parity-ethereum/pull/9146))
- Allocate less stack in `Receipt ctor`
- Ethcore: use accrue_bloom when computing transaction receipt
- `evm bench` fix broken dependencies ([#9134](https://github.com/paritytech/parity-ethereum/pull/9134))
- `evm bench` use valid dependencies
- Benchmarks of the `evm` used stale versions of a couple a crates that this commit fixes!
- Fix warnings
- Update snapcraft.yaml ([#9132](https://github.com/paritytech/parity-ethereum/pull/9132))
- Fix verification in ethcore-sync collect_blocks ([#9135](https://github.com/paritytech/parity-ethereum/pull/9135))
- Unify engine error to reject blocks ([#9085](https://github.com/paritytech/parity-ethereum/pull/9085))
- Reject if Engine::on_close_block returns error
- Unify open block behaviors
- Fix tests in ethcore
- Fix Aura tests
- Fix RPC test
- Print a warning if open block failed
- Print the actual error when closing the block
- Update comments for prepare_pending_block
- Add BlockPreparationStatus to distingish three different state after prepare_pending_block
- Fix `todo` in `ethcore/types::Receipt` constructor ([#9086](https://github.com/paritytech/parity-ethereum/pull/9086))
- Remove needless mutable variable and assignment
- Completely remove all dapps struct from rpc ([#9107](https://github.com/paritytech/parity-ethereum/pull/9107))
- Completely remove all dapps struct from rpc
- Remove unused pub use
- Removed redundant struct bounds and unnecessary data copying ([#9096](https://github.com/paritytech/parity-ethereum/pull/9096))
- Removed redundant struct bounds and unnecessary data copying
- Updated docs, removed redundant bindings
- Insert ETC (classic) hardcoded headers until block 6170625 ([#9121](https://github.com/paritytech/parity-ethereum/pull/9121))
- Make sure to produce full blocks. ([#9115](https://github.com/paritytech/parity-ethereum/pull/9115))
- Update light client hardcoded headers ([#9098](https://github.com/paritytech/parity-ethereum/pull/9098))
- Insert Kovan hardcoded headers until 7690241
- Insert Kovan hardcoded headers until block 7690241
- Insert Ropsten hardcoded headers until 3612673
- Insert Mainnet hardcoded headers until block 5941249
- Parity-version: bump nightly version to 2.1 ([#9095](https://github.com/paritytech/parity-ethereum/pull/9095))
- Fix work-notify. ([#9104](https://github.com/paritytech/parity-ethereum/pull/9104))
- Update snappy ([#9082](https://github.com/paritytech/parity-ethereum/pull/9082))
- Offload cull to IoWorker. ([#9099](https://github.com/paritytech/parity-ethereum/pull/9099))
- Docker: add cmake dependency ([#9111](https://github.com/paritytech/parity-ethereum/pull/9111))
- Update hidapi, fixes [#7542](https://github.com/paritytech/parity-ethereum/issues/7542) ([#9108](https://github.com/paritytech/parity-ethereum/pull/9108))
- Update README.md ([#9084](https://github.com/paritytech/parity-ethereum/pull/9084))
- Update README.md
- Rename parity client
- Docs: remove UI stuff from readme.
- Docs: add changelog link to readme
- Revert "Replace `std::env::home_dir` with `dirs::home_dir` ([#9077](https://github.com/paritytech/parity-ethereum/pull/9077))" ([#9097](https://github.com/paritytech/parity-ethereum/pull/9097))
- Revert "Replace `std::env::home_dir` with `dirs::home_dir` ([#9077](https://github.com/paritytech/parity-ethereum/pull/9077))"
- This reverts commit 7e77932.
- Restore some of the changes
- Update parity-common
- Multiple improvements to discovery ping handling ([#8771](https://github.com/paritytech/parity-ethereum/pull/8771))
- Discovery: Only add nodes to routing table after receiving pong.
- Previously the discovery algorithm would add nodes to the routing table before confirming that the endpoint is participating in the protocol. This now tracks in-flight pings and adds to the routing table only after receiving a response.
- Discovery: Refactor packet creation into its own function.
- This function is useful inside unit tests.
- Discovery: Additional testing for new add_node behavior.
- Discovery: Track expiration of pings to non-yet-in-bucket nodes.
- Now that we may ping nodes before adding to a k-bucket, the timeout tracking must be separate from BucketEntry.
- Discovery: Verify echo hash on pong packets.
- Stores packet hash with in-flight requests and matches with pong response.
- Discovery: Track timeouts on FIND_NODE requests.
- Discovery: Retry failed pings with exponential backoff.
- Udp packets may get dropped, so instead of immediately booting nodes that fail to respond to a ping, retry 4 times with exponential backoff.
- !fixup Use slice instead of Vec for request_backoff.
- Add separate database directory for light client ([#8927](https://github.com/paritytech/parity-ethereum/pull/8927)) ([#9064](https://github.com/paritytech/parity-ethereum/pull/9064))
- Add seperate default DB path for light client ([#8927](https://github.com/paritytech/parity-ethereum/pull/8927))
- Improve readability
## Previous releases
- [CHANGELOG-2.0](docs/CHANGELOG-2.0.md) (_stable_)
- [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)
* Use ubuntu-16.04 for glibc compatibility (#11888) (#73)
* Remove classic, kotti, mordor, expanse (#52)
* Added bad block header hash for ropsten (#49)
* Remove accounts bloom (#33)
* Bump jsonrpc-- to v15
* Implement eth/64, remove eth/62 (#46)
* No snapshotting by default (#11814)
* Update Ellaism chainspec
* Prometheus, heavy memory calls removed (#27)
* Update ethereum/tests
* Implement JSON test suite (#11801)
* Fix issues during block sync (#11265)
* Fix race same block (#11400)
* EIP-2537: Precompile for BLS12-381 curve operations (#11707)
* Remove private transactions
* Remove GetNodeData
* Remove IPFS integration (#11532)
* Remove updater
* Remove light client
* Remove C and Java bindings (#11346)
* Remove whisper (#10855)
* EIP-2315: Simple Subroutines for the EVM (#11629)
* Remove deprecated flags (removal of --geth flag)
* Remove support for hardware wallets (#10678)
* Update bootnodes

5721
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +1,19 @@
[package]
description = "Parity Ethereum client"
name = "parity-ethereum"
description = "OpenEthereum"
name = "openethereum"
# NOTE Make sure to update util/version/Cargo.toml as well
version = "2.2.3"
version = "3.1.1"
license = "GPL-3.0"
authors = ["Parity Technologies <admin@parity.io>"]
authors = [
"OpenEthereum developers",
"Parity Technologies <admin@parity.io>"
]
[dependencies]
blooms-db = { path = "util/blooms-db" }
log = "0.4"
env_logger = "0.5"
rustc-hex = "1.0"
docopt = "0.8"
docopt = "1.0"
clap = "2"
term_size = "0.3"
textwrap = "0.9"
@@ -20,55 +22,57 @@ number_prefix = "0.2"
rpassword = "1.0"
semver = "0.9"
ansi_term = "0.10"
parking_lot = "0.6"
regex = "0.2"
parking_lot = "0.7"
regex = "1.0"
atty = "0.2.8"
toml = "0.4"
serde = "1.0"
serde_json = "1.0"
serde_derive = "1.0"
futures = "0.1"
hyper = { version = "0.12" }
fdlimit = "0.1"
ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" }
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-2.2" }
ethcore = { path = "ethcore", features = ["parity"] }
jsonrpc-core = "15.0.0"
parity-bytes = "0.1"
common-types = { path = "ethcore/types" }
ethcore = { path = "ethcore", features = ["parity"] }
ethcore-accounts = { path = "accounts", optional = true }
ethcore-blockchain = { path = "ethcore/blockchain" }
ethcore-call-contract = { path = "ethcore/call-contract"}
ethcore-db = { path = "ethcore/db" }
ethcore-io = { path = "util/io" }
ethcore-light = { path = "ethcore/light" }
ethcore-logger = { path = "logger" }
ethcore-logger = { path = "parity/logger" }
ethcore-miner = { path = "miner" }
ethcore-network = { path = "util/network" }
ethcore-private-tx = { path = "ethcore/private-tx" }
ethcore-service = { path = "ethcore/service" }
ethcore-sync = { path = "ethcore/sync" }
ethcore-transaction = { path = "ethcore/transaction" }
ethereum-types = "0.4"
node-filter = { path = "ethcore/node_filter" }
ethkey = { path = "ethkey" }
ethkey = { path = "accounts/ethkey" }
ethstore = { path = "accounts/ethstore" }
fetch = { path = "util/fetch" }
node-filter = { path = "ethcore/node-filter" }
rlp = { version = "0.3.0", features = ["ethereum"] }
rpc-cli = { path = "rpc_cli" }
parity-hash-fetch = { path = "hash-fetch" }
parity-ipfs-api = { path = "ipfs" }
parity-local-store = { path = "local-store" }
cli-signer= { path = "cli-signer" }
parity-daemonize = "0.3"
parity-local-store = { path = "miner/local-store" }
parity-runtime = { path = "util/runtime" }
parity-rpc = { path = "rpc" }
parity-rpc-client = { path = "rpc_client" }
parity-updater = { path = "updater" }
parity-version = { path = "util/version" }
parity-whisper = { path = "whisper" }
parity-path = "0.1"
dir = { path = "util/dir" }
panic_hook = { path = "util/panic_hook" }
panic_hook = { path = "util/panic-hook" }
keccak-hash = "0.1"
migration-rocksdb = { path = "util/migration-rocksdb" }
kvdb = "0.1"
kvdb-rocksdb = "0.1.3"
journaldb = { path = "util/journaldb" }
mem = { path = "util/mem" }
stats = { path = "util/stats" }
prometheus = "0.9.0"
ethcore-secretstore = { path = "secret_store", optional = true }
ethcore-secretstore = { path = "secret-store", optional = true }
registrar = { path = "registrar" }
registrar = { path = "util/registrar" }
[build-dependencies]
rustc_version = "0.2"
@@ -78,22 +82,22 @@ 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"] }
[target.'cfg(not(windows))'.dependencies]
daemonize = "0.3"
[features]
default = ["accounts"]
accounts = ["ethcore-accounts", "parity-rpc/accounts"]
miner-debug = ["ethcore/miner-debug"]
json-tests = ["ethcore/json-tests"]
ci-skip-issue = ["ethcore/ci-skip-issue"]
ci-skip-tests = ["ethcore/ci-skip-tests"]
test-heavy = ["ethcore/test-heavy"]
evm-debug = ["ethcore/evm-debug"]
evm-debug-tests = ["ethcore/evm-debug-tests"]
slow-blocks = ["ethcore/slow-blocks"]
secretstore = ["ethcore-secretstore"]
secretstore = ["ethcore-secretstore", "ethcore-secretstore/accounts"]
final = ["parity-version/final"]
deadlock_detection = ["parking_lot/deadlock_detection"]
# to create a memory profile (requires nightly rust), use e.g.
@@ -103,37 +107,38 @@ deadlock_detection = ["parking_lot/deadlock_detection"]
# `valgrind --tool=massif /path/to/parity <parity params>`
# and `massif-visualizer` for visualization
memory_profiling = []
# hardcode version number 1.3.7 of parity to force an update
# in order to manually test that parity fall-over to the local version
# in case of invalid or deprecated command line arguments are entered
test-updater = ["parity-updater/test-updater"]
[lib]
path = "parity/lib.rs"
[[bin]]
path = "parity/main.rs"
name = "parity"
name = "openethereum"
[profile.dev]
[profile.test]
lto = false
opt-level = 3 # makes tests slower to compile, but faster to run
[profile.release]
debug = false
lto = true
[workspace]
# This should only list projects that are not
# in the dependency tree in any other way
# (i.e. pretty much only standalone CLI tools)
members = [
"accounts/ethkey/cli",
"accounts/ethstore/cli",
"chainspec",
"ethcore/wasm/run",
"ethcore/types",
"ethkey/cli",
"ethstore/cli",
"evmbin",
"miner",
"parity-clib",
"whisper",
"whisper/cli",
"util/triehash-ethereum",
"util/keccak-hasher",
"util/patricia-trie-ethereum",
"util/fastmap",
"util/time-utils"
]
[patch.crates-io]
heapsize = { git = "https://github.com/cheme/heapsize.git", branch = "ec-macfix" }

299
README.md
View File

@@ -1,13 +1,38 @@
![Parity Ethereum](docs/logo-parity-ethereum.svg)
# OpenEthereum
## The fastest and most advanced Ethereum client.
Fast and feature-rich multi-network Ethereum client.
<p align="center"><strong><a href="https://github.com/paritytech/parity-ethereum/releases/latest">» Download the latest release «</a></strong></p>
[» Download the latest release «](https://github.com/openethereum/openethereum/releases/latest)
<p align="center"><a href="https://gitlab.parity.io/parity/parity-ethereum/commits/master" target="_blank"><img src="https://gitlab.parity.io/parity/parity-ethereum/badges/master/build.svg" /></a>
<a href="https://www.gnu.org/licenses/gpl-3.0.en.html" target="_blank"><img src="https://img.shields.io/badge/license-GPL%20v3-green.svg" /></a></p>
[![GPL licensed][license-badge]][license-url]
[![Build Status][ci-badge]][ci-url]
[![Discord chat][chat-badge]][chat-url]
**Built for mission-critical use**: Miners, service providers, and exchanges need fast synchronisation and maximum uptime. Parity Ethereum provides the core infrastructure essential for speedy and reliable services.
[license-badge]: https://img.shields.io/badge/license-GPL_v3-green.svg
[license-url]: LICENSE
[ci-badge]: https://github.com/openethereum/openethereum/workflows/Build%20and%20Test%20Suite/badge.svg
[ci-url]: https://github.com/openethereum/openethereum/actions
[chat-badge]: https://img.shields.io/discord/669192218728202270.svg?logo=discord
[chat-url]: https://discord.io/openethereum
## Table of Contents
1. [Description](#chapter-001)
2. [Technical Overview](#chapter-002)
3. [Building](#chapter-003)<br>
3.1 [Building Dependencies](#chapter-0031)<br>
3.2 [Building from Source Code](#chapter-0032)<br>
3.3 [Starting OpenEthereum](#chapter-0034)
4. [Testing](#chapter-004)
5. [Documentation](#chapter-005)
6. [Toolchain](#chapter-006)
7. [Contributing](#chapter-008)
8. [License](#chapter-009)
## 1. Description <a id="chapter-001"></a>
**Built for mission-critical use**: Miners, service providers, and exchanges need fast synchronisation and maximum uptime. OpenEthereum provides the core infrastructure essential for speedy and reliable services.
- Clean, modular codebase for easy customisation
- Advanced CLI-based client
@@ -15,19 +40,21 @@
- Synchronise in hours, not days with Warp Sync
- Modular for light integration into your service or product
## Technical Overview
## 2. Technical Overview <a id="chapter-002"></a>
Parity Ethereum's goal is to be the fastest, lightest, and most secure Ethereum client. We are developing Parity Ethereum using the sophisticated and cutting-edge **Rust programming language**. Parity Ethereum is licensed under the GPLv3 and can be used for all your Ethereum needs.
OpenEthereum's goal is to be the fastest, lightest, and most secure Ethereum client. We are developing OpenEthereum using the **Rust programming language**. OpenEthereum is licensed under the GPLv3 and can be used for all your Ethereum needs.
By default, Parity Ethereum runs a JSON-RPC HTTP server on port `:8545` and a Web-Sockets server on port `:8546`. This is fully configurable and supports a number of APIs.
By default, OpenEthereum runs a JSON-RPC HTTP server on port `:8545` and a Web-Sockets server on port `:8546`. This is fully configurable and supports a number of APIs.
If you run into problems while using Parity Ethereum, check out the [wiki for documentation](https://wiki.parity.io/), feel free to [file an issue in this repository](https://github.com/paritytech/parity-ethereum/issues/new), or hop on our [Gitter](https://gitter.im/paritytech/parity) or [Riot](https://riot.im/app/#/group/+parity:matrix.parity.io) chat room to ask a question. We are glad to help! **For security-critical issues**, please refer to the security policy outlined in [SECURITY.md](SECURITY.md).
If you run into problems while using OpenEthereum, check out the [old wiki for documentation](https://openethereum.github.io/), feel free to [file an issue in this repository](https://github.com/openethereum/openethereum/issues/new), or hop on our [Discord](https://discord.io/openethereum) chat room to ask a question. We are glad to help!
Parity Ethereum's current beta-release is 2.1. You can download it at [the releases page](https://github.com/paritytech/parity-ethereum/releases) or follow the instructions below to build from source. Please, mind the [CHANGELOG.md](CHANGELOG.md) for a list of all changes between different versions.
You can download OpenEthereum's latest release at [the releases page](https://github.com/openethereum/openethereum/releases) or follow the instructions below to build from source. Read the [CHANGELOG.md](CHANGELOG.md) for a list of all changes between different versions.
## Build Dependencies
## 3. Building <a id="chapter-003"></a>
Parity Ethereum requires **Rust version 1.29.x** to build.
### 3.1 Build Dependencies <a id="chapter-0031"></a>
OpenEthereum requires **latest stable Rust version** to build.
We recommend installing Rust through [rustup](https://www.rustup.rs/). If you don't already have `rustup`, you can install it like this:
@@ -36,7 +63,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++`, `libudev-dev`, `pkg-config`, `file`, `make`, and `cmake` packages to be installed.
OpenEthereum also requires `clang` (>= 9.0), `clang++`, `pkg-config`, `file`, `make`, and `cmake` packages to be installed.
- OSX:
```bash
@@ -45,7 +72,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
@@ -56,14 +83,14 @@ Once you have `rustup` installed, then you need to install:
* [Perl](https://www.perl.org)
* [Yasm](https://yasm.tortall.net)
Make sure that these binaries are in your `PATH`. After that, you should be able to build Parity Ethereum from source.
Make sure that these binaries are in your `PATH`. After that, you should be able to build OpenEthereum from source.
## Build from Source Code
### 3.2 Build from Source Code <a id="chapter-0032"></a>
```bash
# download Parity Ethereum code
$ git clone https://github.com/paritytech/parity-ethereum
$ cd parity-ethereum
# download OpenEthereum code
$ git clone https://github.com/openethereum/openethereum
$ cd openethereum
# build in release mode
$ cargo build --release --features final
@@ -83,73 +110,209 @@ Note, when compiling a crate and you receive errors, it's in most cases your out
$ cargo clean
```
This always compiles the latest nightly builds. If you want to build stable or beta, do a
This always compiles the latest nightly builds. If you want to build stable, do a
```bash
$ git checkout stable
```
or
### 3.3 Starting OpenEthereum <a id="chapter-0034"></a>
#### Manually
To start OpenEthereum manually, just run
```bash
$ git checkout beta
$ ./target/release/openethereum
```
## Simple One-Line Installer for Mac and Linux
so OpenEthereum begins syncing the Ethereum blockchain.
```bash
bash <(curl https://get.parity.io -L)
```
#### Using `systemd` service file
The one-line installer always defaults to the latest beta release. To install a stable release, run:
To start OpenEthereum as a regular user using `systemd` init:
```bash
bash <(curl https://get.parity.io -L) -r stable
```
## Start Parity Ethereum
### Manually
To start Parity Ethereum manually, just run
```bash
$ ./target/release/parity
```
so Parity Ethereum begins syncing the Ethereum blockchain.
### Using `systemd` service file
To start Parity Ethereum as a regular user using `systemd` init:
1. Copy `./scripts/parity.service` to your
1. Copy `./scripts/openethereum.service` to your
`systemd` user directory (usually `~/.config/systemd/user`).
2. To configure Parity Ethereum, write a `/etc/parity/config.toml` config file, see [Configuring Parity Ethereum](https://paritytech.github.io/wiki/Configuring-Parity) for details.
2. Copy release to bin folder, write `sudo install ./target/release/openethereum /usr/bin/openethereum`
3. To configure OpenEthereum, see [our wiki](https://openethereum.github.io/Configuring-OpenEthereum) for details.
## Parity Ethereum toolchain
## 4. Testing <a id="chapter-004"></a>
In addition to the Parity Ethereum client, there are additional tools in this repository available:
Download the required test files: `git submodule update --init --recursive`. You can run tests with the following commands:
- [evmbin](https://github.com/paritytech/parity-ethereum/blob/master/evmbin/) - EVM implementation for Parity Ethereum.
- [ethabi](https://github.com/paritytech/ethabi) - Parity Ethereum function calls encoding.
- [ethstore](https://github.com/paritytech/parity-ethereum/blob/master/ethstore/) - Parity Ethereum key management.
- [ethkey](https://github.com/paritytech/parity-ethereum/blob/master/ethkey/) - Parity Ethereum keys generator.
- [whisper](https://github.com/paritytech/parity-ethereum/blob/master/whisper/) - Implementation of Whisper-v2 PoC.
* **All** packages
```
cargo test --all
```
## Join the chat!
* Specific package
```
cargo test --package <spec>
```
Questions? Get in touch with us on Gitter:
[![Gitter: Parity](https://img.shields.io/badge/gitter-parity-4AB495.svg)](https://gitter.im/paritytech/parity)
[![Gitter: Parity.js](https://img.shields.io/badge/gitter-parity.js-4AB495.svg)](https://gitter.im/paritytech/parity.js)
[![Gitter: Parity/Miners](https://img.shields.io/badge/gitter-parity/miners-4AB495.svg)](https://gitter.im/paritytech/parity/miners)
[![Gitter: Parity-PoA](https://img.shields.io/badge/gitter-parity--poa-4AB495.svg)](https://gitter.im/paritytech/parity-poa)
Replace `<spec>` with one of the packages from the [package list](#package-list) (e.g. `cargo test --package evmbin`).
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)
You can show your logs in the test output by passing `--nocapture` (i.e. `cargo test --package evmbin -- --nocapture`)
## Documentation
## 5. Documentation <a id="chapter-005"></a>
Official website: https://parity.io
Be sure to [check out our wiki](https://openethereum.github.io/) for more information.
Be sure to [check out our wiki](https://wiki.parity.io) for more information.
### Viewing documentation for OpenEthereum packages
You can generate documentation for OpenEthereum Rust packages that automatically opens in your web browser using [rustdoc with Cargo](https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html#using-rustdoc-with-cargo) (of the The Rustdoc Book), by running the the following commands:
* **All** packages
```
cargo doc --document-private-items --open
```
* Specific package
```
cargo doc --package <spec> -- --document-private-items --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 openethereum --open`):
<a id="package-list"></a>
**Package List**
<details><p>
* OpenEthereum Client Application
```bash
openethereum
```
* OpenEthereum Account Management, Key Management Tool, and Keys Generator
```bash
ethcore-accounts, ethkey-cli, ethstore, ethstore-cli
```
* OpenEthereum Chain Specification
```bash
chainspec
```
* OpenEthereum CLI Signer Tool & RPC Client
```bash
cli-signer parity-rpc-client
```
* OpenEthereum Ethash & ProgPoW Implementations
```bash
ethash
```
* EthCore Library
```bash
ethcore
```
* OpenEthereum Blockchain Database, Test Generator, Configuration,
Caching, Importing Blocks, and Block Information
```bash
ethcore-blockchain
```
* OpenEthereum Contract Calls and Blockchain Service & Registry Information
```bash
ethcore-call-contract
```
* OpenEthereum Database Access & Utilities, Database Cache Manager
```bash
ethcore-db
```
* OpenEthereum Virtual Machine (EVM) Rust Implementation
```bash
evm
```
* OpenEthereum Light Client Implementation
```bash
ethcore-light
```
* Smart Contract based Node Filter, Manage Permissions of Network Connections
```bash
node-filter
```
* OpenEthereum Client & Network Service Creation & Registration with the I/O Subsystem
```bash
ethcore-service
```
* OpenEthereum Blockchain Synchronization
```bash
ethcore-sync
```
* OpenEthereum Common Types
```bash
common-types
```
* OpenEthereum Virtual Machines (VM) Support Library
```bash
vm
```
* OpenEthereum WASM Interpreter
```bash
wasm
```
* OpenEthereum WASM Test Runner
```bash
pwasm-run-test
```
* OpenEthereum EVM Implementation
```bash
evmbin
```
* OpenEthereum JSON Deserialization
```bash
ethjson
```
* OpenEthereum State Machine Generalization for Consensus Engines
```bash
parity-machine
```
* OpenEthereum Miner Interface
```bash
ethcore-miner parity-local-store price-info ethcore-stratum using_queue
```
* OpenEthereum Logger Implementation
```bash
ethcore-logger
```
* OpenEthereum JSON-RPC Servers
```bash
parity-rpc
```
* OpenEthereum Updater Service
```bash
parity-updater parity-hash-fetch
```
* OpenEthereum Core Libraries (`util`)
```bash
accounts-bloom blooms-db dir eip-712 fake-fetch fastmap fetch ethcore-io
journaldb keccak-hasher len-caching-lock memory-cache memzero
migration-rocksdb ethcore-network ethcore-network-devp2p panic_hook
patricia-trie-ethereum registrar rlp_compress stats
time-utils triehash-ethereum unexpected parity-version
```
</p></details>
## 6. Toolchain <a id="chapter-006"></a>
In addition to the OpenEthereum client, there are additional tools in this repository available:
- [evmbin](./evmbin) - OpenEthereum EVM Implementation.
- [ethstore](./accounts/ethstore) - OpenEthereum Key Management.
- [ethkey](./accounts/ethkey) - OpenEthereum Keys Generator.
The following tools are available in a separate repository:
- [ethabi](https://github.com/openethereum/ethabi) - OpenEthereum Encoding of Function Calls. [Docs here](https://crates.io/crates/ethabi)
- [whisper](https://github.com/openethereum/whisper) - OpenEthereum Whisper-v2 PoC Implementation.
## 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).
### Contributor Code of Conduct
[CODE_OF_CONDUCT](./.github/CODE_OF_CONDUCT.md)
## 8. License <a id="chapter-008"></a>
[LICENSE](./LICENSE)

View File

@@ -1,80 +0,0 @@
# Security Policy
Parity Technologies is committed to resolving security vulnerabilities in our software quickly and carefully. We take the necessary steps to minimize risk, provide timely information, and deliver vulnerability fixes and mitigations required to address security issues.
## Reporting a Vulnerability
Security vulnerabilities in Parity software should be reported by email to security@parity.io. If you think your report might be eligible for the Parity Bug Bounty Program, your email should be send to bugbounty@parity.io.
Your report should include the following:
- your name
- description of the vulnerability
- attack scenario (if any)
- components
- reproduction
- other details
Try to include as much information in your report as you can, including a description of the vulnerability, its potential impact, and steps for reproducing it. Be sure to use a descriptive subject line.
You'll receive a response to your email within two business days indicating the next steps in handling your report. We encourage finders to use encrypted communication channels to protect the confidentiality of vulnerability reports. You can encrypt your report using our public key. This key is [on MIT's key server](https://pgp.mit.edu/pks/lookup?op=get&search=0x5D0F03018D07DE73) server and reproduced below.
After the initial reply to your report, our team will endeavor to keep you informed of the progress being made towards a fix. These updates will be sent at least every five business days.
Thank you for taking the time to responsibly disclose any vulnerabilities you find.
## Responsible Investigation and Reporting
Responsible investigation and reporting includes, but isn't limited to, the following:
- Don't violate the privacy of other users, destroy data, etc.
- Dont defraud or harm Parity Technologies Ltd or its users during your research; you should make a good faith effort to not interrupt or degrade our services.
- Don't target our physical security measures, or attempt to use social engineering, spam, distributed denial of service (DDOS) attacks, etc.
- Initially report the bug only to us and not to anyone else.
- Give us a reasonable amount of time to fix the bug before disclosing it to anyone else, and give us adequate written warning before disclosing it to anyone else.
- In general, please investigate and report bugs in a way that makes a reasonable, good faith effort not to be disruptive or harmful to us or our users. Otherwise your actions might be interpreted as an attack rather than an effort to be helpful.
## Bug Bounty Program
Our Bug Bounty Program allows us to recognise and reward members of the Parity community for helping us find and address significant bugs, in accordance with the terms of the Parity Bug Bounty Program. A detailed description on eligibility, rewards, legal information and terms & conditions for contributors can be found on [our website](https://paritytech.io/bug-bounty.html).
## Plaintext PGP Key
```
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQENBFlyIAwBCACe0keNPjgYzZ1Oy/8t3zj/Qw9bHHqrzx7FWy8NbXnYBM19NqOZ
DIP7Oe0DvCaf/uruBskCS0iVstHlEFQ2AYe0Ei0REt9lQdy61GylU/DEB3879IG+
6FO0SnFeYeerv1/hFI2K6uv8v7PyyVDiiJSW0I1KIs2OBwJicTKmWxLAeQsRgx9G
yRGalrVk4KP+6pWTA7k3DxmDZKZyfYV/Ej10NtuzmsemwDbv98HKeomp/kgFOfSy
3AZjeCpctlsNqpjUuXa0/HudmH2WLxZ0fz8XeoRh8XM9UudNIecjrDqmAFrt/btQ
/3guvlzhFCdhYPVGsUusKMECk/JG+Xx1/1ZjABEBAAG0LFBhcml0eSBTZWN1cml0
eSBDb250YWN0IDxzZWN1cml0eUBwYXJpdHkuaW8+iQFUBBMBCAA+FiEE2uUVYCjP
N6B8aTiDXQ8DAY0H3nMFAllyIAwCGwMFCQPCZwAFCwkIBwIGFQgJCgsCBBYCAwEC
HgECF4AACgkQXQ8DAY0H3nM60wgAkS3A36Zc+upiaxU7tumcGv+an17j7gin0sif
+0ELSjVfrXInM6ovai+NhUdcLkJ7tCrKS90fvlaELK5Sg9CXBWCTFccKN4A/B7ey
rOg2NPXUecnyBB/XqQgKYH7ujYlOlqBDXMfz6z8Hj6WToxg9PPMGGomyMGh8AWxM
3yRPFs5RKt0VKgN++5N00oly5Y8ri5pgCidDvCLYMGTVDHFKwkuc9w6BlWlu1R1e
/hXFWUFAP1ffTAul3QwyKhjPn2iotCdxXjvt48KaU8DN4iL7aMBN/ZBKqGS7yRdF
D/JbJyaaJ0ZRvFSTSXy/sWY3z1B5mtCPBxco8hqqNfRkCwuZ6LkBDQRZciAMAQgA
8BP8xrwe12TOUTqL/Vrbxv/FLdhKh53J6TrPKvC2TEEKOrTNo5ahRq+XOS5E7G2N
x3b+fq8gR9BzFcldAx0XWUtGs/Wv++ulaSNqTBxj13J3G3WGsUfMKxRgj//piCUD
bCFLQfGZdKk0M1o9QkPVARwwmvCNiNB/l++xGqPtfc44H5jWj3GoGvL2MkShPzrN
yN/bJ+m+R5gtFGdInqa5KXBuxxuW25eDKJ+LzjbgUgeC76wNcfOiQHTdMkcupjdO
bbGFwo10hcbRAOcZEv6//Zrlmk/6nPxEd2hN20St2bSN0+FqfZ267mWEu3ejsgF8
ArdCpv5h4fBvJyNwiTZwIQARAQABiQE8BBgBCAAmFiEE2uUVYCjPN6B8aTiDXQ8D
AY0H3nMFAllyIAwCGwwFCQPCZwAACgkQXQ8DAY0H3nNisggAl4fqhRlA34wIb190
sqXHVxiCuzPaqS6krE9xAa1+gncX485OtcJNqnjugHm2rFE48lv7oasviuPXuInE
/OgVFnXYv9d/Xx2JUeDs+bFTLouCDRY2Unh7KJZasfqnMcCHWcxHx5FvRNZRssaB
WTZVo6sizPurGUtbpYe4/OLFhadBqAE0EUmVRFEUMc1YTnu4eLaRBzoWN4d2UWwi
LN25RSrVSke7LTSFbgn9ntQrQ2smXSR+cdNkkfRCjFcpUaecvFl9HwIqoyVbT4Ym
0hbpbbX/cJdc91tKa+psa29uMeGL/cgL9fAu19yNFRyOTMxjZnvql1X/WE1pLmoP
ETBD1Q==
=K9Qw
-----END PGP PUBLIC KEY BLOCK-----
```

22
accounts/Cargo.toml Normal file
View File

@@ -0,0 +1,22 @@
[package]
description = "OpenEthereum Account Management"
homepage = "https://github.com/openethereum/openethereum"
license = "GPL-3.0"
name = "ethcore-accounts"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
[dependencies]
common-types = { path = "../ethcore/types" }
ethkey = { path = "ethkey" }
ethstore = { path = "ethstore" }
log = "0.4"
parking_lot = "0.7"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
[dev-dependencies]
ethereum-types = "0.4"
tempdir = "0.3"

View File

@@ -1,18 +1,18 @@
[package]
description = "Parity Ethereum Keys Generator"
name = "ethkey"
version = "0.3.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
byteorder = "1.0"
edit-distance = "2.0"
parity-crypto = "0.2"
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" }
parity-crypto = "0.3.0"
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1", rev = "ccc06e7480148b723eb44ac56cf4d20eec380b6f" }
ethereum-types = "0.4"
lazy_static = "1.0"
log = "0.4"
mem = { path = "../util/mem" }
parity-wordlist = "1.2"
memzero = { path = "../../util/memzero" }
parity-wordlist = "1.3"
quick-error = "1.2.2"
rand = "0.4"
rustc-hex = "1.0"

View File

@@ -5,8 +5,8 @@ Parity Ethereum keys generator.
### Usage
```
Parity Ethereum keys generator.
Copyright 2015-2018 Parity Technologies (UK) Ltd.
Parity Ethereum Keys Generator.
Copyright 2015-2019 Parity Technologies (UK) Ltd.
Usage:
ethkey info <secret-or-phrase> [options]
@@ -216,6 +216,5 @@ _This project is a part of the Parity Ethereum toolchain._
- [evmbin](https://github.com/paritytech/parity-ethereum/blob/master/evmbin/) - EVM implementation for Parity Ethereum.
- [ethabi](https://github.com/paritytech/ethabi) - Parity Ethereum function calls encoding.
- [ethstore](https://github.com/paritytech/parity-ethereum/blob/master/ethstore/) - Parity Ethereum key management.
- [ethkey](https://github.com/paritytech/parity-ethereum/blob/master/ethkey/) - Parity Ethereum keys generator.
- [whisper](https://github.com/paritytech/parity-ethereum/blob/master/whisper/) - Implementation of Whisper-v2 PoC.
- [ethstore](https://github.com/paritytech/parity-ethereum/blob/master/accounts/ethstore) - Parity Ethereum key management.
- [ethkey](https://github.com/paritytech/parity-ethereum/blob/master/accounts/ethkey) - Parity Ethereum keys generator.

View File

@@ -1,14 +1,15 @@
[package]
description = "Parity Ethereum Keys Generator CLI"
name = "ethkey-cli"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
docopt = "0.8"
docopt = "1.0"
env_logger = "0.5"
ethkey = { path = "../" }
panic_hook = { path = "../../util/panic_hook" }
parity-wordlist="1.2"
panic_hook = { path = "../../../util/panic-hook" }
parity-wordlist="1.3"
rustc-hex = "1.0"
serde = "1.0"
serde_derive = "1.0"

View File

@@ -0,0 +1,494 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
extern crate docopt;
extern crate env_logger;
extern crate ethkey;
extern crate panic_hook;
extern crate parity_wordlist;
extern crate rustc_hex;
extern crate serde;
extern crate threadpool;
#[macro_use]
extern crate serde_derive;
use std::{env, fmt, io, num::ParseIntError, process, sync};
use docopt::Docopt;
use ethkey::{
brain_recover, sign, verify_address, verify_public, Brain, BrainPrefix, Error as EthkeyError,
Generator, KeyPair, Prefix, Random,
};
use rustc_hex::{FromHex, FromHexError};
const USAGE: &'static str = r#"
Parity Ethereum keys generator.
Copyright 2015-2019 Parity Technologies (UK) Ltd.
Usage:
ethkey info <secret-or-phrase> [options]
ethkey generate random [options]
ethkey generate prefix <prefix> [options]
ethkey sign <secret> <message>
ethkey verify public <public> <signature> <message>
ethkey verify address <address> <signature> <message>
ethkey recover <address> <known-phrase>
ethkey [-h | --help]
Options:
-h, --help Display this message and exit.
-s, --secret Display only the secret key.
-p, --public Display only the public key.
-a, --address Display only the address.
-b, --brain Use parity brain wallet algorithm. Not recommended.
Commands:
info Display public key and address of the secret.
generate random Generates new random Ethereum key.
generate prefix Random generation, but address must start with a prefix ("vanity address").
sign Sign message using a secret key.
verify Verify signer of the signature by public key or address.
recover Try to find brain phrase matching given address from partial phrase.
"#;
#[derive(Debug, Deserialize)]
struct Args {
cmd_info: bool,
cmd_generate: bool,
cmd_random: bool,
cmd_prefix: bool,
cmd_sign: bool,
cmd_verify: bool,
cmd_public: bool,
cmd_address: bool,
cmd_recover: bool,
arg_prefix: String,
arg_secret: String,
arg_secret_or_phrase: String,
arg_known_phrase: String,
arg_message: String,
arg_public: String,
arg_address: String,
arg_signature: String,
flag_secret: bool,
flag_public: bool,
flag_address: bool,
flag_brain: bool,
}
#[derive(Debug)]
enum Error {
Ethkey(EthkeyError),
FromHex(FromHexError),
ParseInt(ParseIntError),
Docopt(docopt::Error),
Io(io::Error),
}
impl From<EthkeyError> for Error {
fn from(err: EthkeyError) -> Self {
Error::Ethkey(err)
}
}
impl From<FromHexError> for Error {
fn from(err: FromHexError) -> Self {
Error::FromHex(err)
}
}
impl From<ParseIntError> for Error {
fn from(err: ParseIntError) -> Self {
Error::ParseInt(err)
}
}
impl From<docopt::Error> for Error {
fn from(err: docopt::Error) -> Self {
Error::Docopt(err)
}
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
Error::Io(err)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
Error::Ethkey(ref e) => write!(f, "{}", e),
Error::FromHex(ref e) => write!(f, "{}", e),
Error::ParseInt(ref e) => write!(f, "{}", e),
Error::Docopt(ref e) => write!(f, "{}", e),
Error::Io(ref e) => write!(f, "{}", e),
}
}
}
enum DisplayMode {
KeyPair,
Secret,
Public,
Address,
}
impl DisplayMode {
fn new(args: &Args) -> Self {
if args.flag_secret {
DisplayMode::Secret
} else if args.flag_public {
DisplayMode::Public
} else if args.flag_address {
DisplayMode::Address
} else {
DisplayMode::KeyPair
}
}
}
fn main() {
panic_hook::set_abort();
env_logger::try_init().expect("Logger initialized only once.");
match execute(env::args()) {
Ok(ok) => println!("{}", ok),
Err(Error::Docopt(ref e)) => e.exit(),
Err(err) => {
eprintln!("{}", err);
process::exit(1);
}
}
}
fn display(result: (KeyPair, Option<String>), mode: DisplayMode) -> String {
let keypair = result.0;
match mode {
DisplayMode::KeyPair => match result.1 {
Some(extra_data) => format!("{}\n{}", extra_data, keypair),
None => format!("{}", keypair),
},
DisplayMode::Secret => format!("{:x}", keypair.secret()),
DisplayMode::Public => format!("{:x}", keypair.public()),
DisplayMode::Address => format!("{:x}", keypair.address()),
}
}
fn execute<S, I>(command: I) -> Result<String, Error>
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
let args: Args = Docopt::new(USAGE).and_then(|d| d.argv(command).deserialize())?;
return if args.cmd_info {
let display_mode = DisplayMode::new(&args);
let result = if args.flag_brain {
let phrase = args.arg_secret_or_phrase;
let phrase_info = validate_phrase(&phrase);
let keypair = Brain::new(phrase)
.generate()
.expect("Brain wallet generator is infallible; qed");
(keypair, Some(phrase_info))
} else {
let secret = args
.arg_secret_or_phrase
.parse()
.map_err(|_| EthkeyError::InvalidSecret)?;
(KeyPair::from_secret(secret)?, None)
};
Ok(display(result, display_mode))
} else if args.cmd_generate {
let display_mode = DisplayMode::new(&args);
let result = if args.cmd_random {
if args.flag_brain {
let mut brain = BrainPrefix::new(vec![0], usize::max_value(), BRAIN_WORDS);
let keypair = brain.generate()?;
let phrase = format!("recovery phrase: {}", brain.phrase());
(keypair, Some(phrase))
} else {
(Random.generate()?, None)
}
} else if args.cmd_prefix {
let prefix = args.arg_prefix.from_hex()?;
let brain = args.flag_brain;
in_threads(move || {
let iterations = 1024;
let prefix = prefix.clone();
move || {
let prefix = prefix.clone();
let res = if brain {
let mut brain = BrainPrefix::new(prefix, iterations, BRAIN_WORDS);
let result = brain.generate();
let phrase = format!("recovery phrase: {}", brain.phrase());
result.map(|keypair| (keypair, Some(phrase)))
} else {
let result = Prefix::new(prefix, iterations).generate();
result.map(|res| (res, None))
};
Ok(res.map(Some).unwrap_or(None))
}
})?
} else {
return Ok(format!("{}", USAGE));
};
Ok(display(result, display_mode))
} else if args.cmd_sign {
let secret = args
.arg_secret
.parse()
.map_err(|_| EthkeyError::InvalidSecret)?;
let message = args
.arg_message
.parse()
.map_err(|_| EthkeyError::InvalidMessage)?;
let signature = sign(&secret, &message)?;
Ok(format!("{}", signature))
} else if args.cmd_verify {
let signature = args
.arg_signature
.parse()
.map_err(|_| EthkeyError::InvalidSignature)?;
let message = args
.arg_message
.parse()
.map_err(|_| EthkeyError::InvalidMessage)?;
let ok = if args.cmd_public {
let public = args
.arg_public
.parse()
.map_err(|_| EthkeyError::InvalidPublic)?;
verify_public(&public, &signature, &message)?
} else if args.cmd_address {
let address = args
.arg_address
.parse()
.map_err(|_| EthkeyError::InvalidAddress)?;
verify_address(&address, &signature, &message)?
} else {
return Ok(format!("{}", USAGE));
};
Ok(format!("{}", ok))
} else if args.cmd_recover {
let display_mode = DisplayMode::new(&args);
let known_phrase = args.arg_known_phrase;
let address = args
.arg_address
.parse()
.map_err(|_| EthkeyError::InvalidAddress)?;
let (phrase, keypair) = in_threads(move || {
let mut it =
brain_recover::PhrasesIterator::from_known_phrase(&known_phrase, BRAIN_WORDS);
move || {
let mut i = 0;
while let Some(phrase) = it.next() {
i += 1;
let keypair = Brain::new(phrase.clone()).generate().unwrap();
if keypair.address() == address {
return Ok(Some((phrase, keypair)));
}
if i >= 1024 {
return Ok(None);
}
}
Err(EthkeyError::Custom("Couldn't find any results.".into()))
}
})?;
Ok(display((keypair, Some(phrase)), display_mode))
} else {
Ok(format!("{}", USAGE))
};
}
const BRAIN_WORDS: usize = 12;
fn validate_phrase(phrase: &str) -> String {
match Brain::validate_phrase(phrase, BRAIN_WORDS) {
Ok(()) => format!("The recovery phrase looks correct.\n"),
Err(err) => format!("The recover phrase was not generated by Parity: {}", err),
}
}
fn in_threads<F, X, O>(prepare: F) -> Result<O, EthkeyError>
where
O: Send + 'static,
X: Send + 'static,
F: Fn() -> X,
X: FnMut() -> Result<Option<O>, EthkeyError>,
{
let pool = threadpool::Builder::new().build();
let (tx, rx) = sync::mpsc::sync_channel(1);
let is_done = sync::Arc::new(sync::atomic::AtomicBool::default());
for _ in 0..pool.max_count() {
let is_done = is_done.clone();
let tx = tx.clone();
let mut task = prepare();
pool.execute(move || {
loop {
if is_done.load(sync::atomic::Ordering::SeqCst) {
return;
}
let res = match task() {
Ok(None) => continue,
Ok(Some(v)) => Ok(v),
Err(err) => Err(err),
};
// We are interested only in the first response.
let _ = tx.send(res);
}
});
}
if let Ok(solution) = rx.recv() {
is_done.store(true, sync::atomic::Ordering::SeqCst);
return solution;
}
Err(EthkeyError::Custom("No results found.".into()))
}
#[cfg(test)]
mod tests {
use super::execute;
#[test]
fn info() {
let command = vec![
"ethkey",
"info",
"17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55",
]
.into_iter()
.map(Into::into)
.collect::<Vec<String>>();
let expected =
"secret: 17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55
public: 689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124
address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned();
assert_eq!(execute(command).unwrap(), expected);
}
#[test]
fn brain() {
let command = vec!["ethkey", "info", "--brain", "this is sparta"]
.into_iter()
.map(Into::into)
.collect::<Vec<String>>();
let expected =
"The recover phrase was not generated by Parity: The word 'this' does not come from the dictionary.
secret: aa22b54c0cb43ee30a014afe5ef3664b1cde299feabca46cd3167a85a57c39f2
public: c4c5398da6843632c123f543d714d2d2277716c11ff612b2a2f23c6bda4d6f0327c31cd58c55a9572c3cc141dade0c32747a13b7ef34c241b26c84adbb28fcf4
address: 006e27b6a72e1f34c626762f3c4761547aff1421".to_owned();
assert_eq!(execute(command).unwrap(), expected);
}
#[test]
fn secret() {
let command = vec!["ethkey", "info", "--brain", "this is sparta", "--secret"]
.into_iter()
.map(Into::into)
.collect::<Vec<String>>();
let expected =
"aa22b54c0cb43ee30a014afe5ef3664b1cde299feabca46cd3167a85a57c39f2".to_owned();
assert_eq!(execute(command).unwrap(), expected);
}
#[test]
fn public() {
let command = vec!["ethkey", "info", "--brain", "this is sparta", "--public"]
.into_iter()
.map(Into::into)
.collect::<Vec<String>>();
let expected = "c4c5398da6843632c123f543d714d2d2277716c11ff612b2a2f23c6bda4d6f0327c31cd58c55a9572c3cc141dade0c32747a13b7ef34c241b26c84adbb28fcf4".to_owned();
assert_eq!(execute(command).unwrap(), expected);
}
#[test]
fn address() {
let command = vec!["ethkey", "info", "-b", "this is sparta", "--address"]
.into_iter()
.map(Into::into)
.collect::<Vec<String>>();
let expected = "006e27b6a72e1f34c626762f3c4761547aff1421".to_owned();
assert_eq!(execute(command).unwrap(), expected);
}
#[test]
fn sign() {
let command = vec![
"ethkey",
"sign",
"17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55",
"bd50b7370c3f96733b31744c6c45079e7ae6c8d299613246d28ebcef507ec987",
]
.into_iter()
.map(Into::into)
.collect::<Vec<String>>();
let expected = "c1878cf60417151c766a712653d26ef350c8c75393458b7a9be715f053215af63dfd3b02c2ae65a8677917a8efa3172acb71cb90196e42106953ea0363c5aaf200".to_owned();
assert_eq!(execute(command).unwrap(), expected);
}
#[test]
fn verify_valid_public() {
let command = vec!["ethkey", "verify", "public", "689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124", "c1878cf60417151c766a712653d26ef350c8c75393458b7a9be715f053215af63dfd3b02c2ae65a8677917a8efa3172acb71cb90196e42106953ea0363c5aaf200", "bd50b7370c3f96733b31744c6c45079e7ae6c8d299613246d28ebcef507ec987"]
.into_iter()
.map(Into::into)
.collect::<Vec<String>>();
let expected = "true".to_owned();
assert_eq!(execute(command).unwrap(), expected);
}
#[test]
fn verify_valid_address() {
let command = vec!["ethkey", "verify", "address", "26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5", "c1878cf60417151c766a712653d26ef350c8c75393458b7a9be715f053215af63dfd3b02c2ae65a8677917a8efa3172acb71cb90196e42106953ea0363c5aaf200", "bd50b7370c3f96733b31744c6c45079e7ae6c8d299613246d28ebcef507ec987"]
.into_iter()
.map(Into::into)
.collect::<Vec<String>>();
let expected = "true".to_owned();
assert_eq!(execute(command).unwrap(), expected);
}
#[test]
fn verify_invalid() {
let command = vec!["ethkey", "verify", "public", "689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124", "c1878cf60417151c766a712653d26ef350c8c75393458b7a9be715f053215af63dfd3b02c2ae65a8677917a8efa3172acb71cb90196e42106953ea0363c5aaf200", "bd50b7370c3f96733b31744c6c45079e7ae6c8d299613246d28ebcef507ec986"]
.into_iter()
.map(Into::into)
.collect::<Vec<String>>();
let expected = "false".to_owned();
assert_eq!(execute(command).unwrap(), expected);
}
}

View File

@@ -0,0 +1,74 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::{Generator, KeyPair, Secret};
use keccak::Keccak256;
use parity_wordlist;
/// Simple brainwallet.
pub struct Brain(String);
impl Brain {
pub fn new(s: String) -> Self {
Brain(s)
}
pub fn validate_phrase(phrase: &str, expected_words: usize) -> Result<(), ::WordlistError> {
parity_wordlist::validate_phrase(phrase, expected_words)
}
}
impl Generator for Brain {
type Error = ::Void;
fn generate(&mut self) -> Result<KeyPair, Self::Error> {
let seed = self.0.clone();
let mut secret = seed.into_bytes().keccak256();
let mut i = 0;
loop {
secret = secret.keccak256();
match i > 16384 {
false => i += 1,
true => {
if let Ok(pair) =
Secret::from_unsafe_slice(&secret).and_then(KeyPair::from_secret)
{
if pair.address()[0] == 0 {
trace!("Testing: {}, got: {:?}", self.0, pair.address());
return Ok(pair);
}
}
}
}
}
}
}
#[cfg(test)]
mod tests {
use Brain;
use Generator;
#[test]
fn test_brain() {
let words = "this is sparta!".to_owned();
let first_keypair = Brain::new(words.clone()).generate().unwrap();
let second_keypair = Brain::new(words.clone()).generate().unwrap();
assert_eq!(first_keypair.secret(), second_keypair.secret());
}
}

View File

@@ -0,0 +1,73 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::{Brain, Error, Generator, KeyPair};
use parity_wordlist as wordlist;
/// Tries to find brain-seed keypair with address starting with given prefix.
pub struct BrainPrefix {
prefix: Vec<u8>,
iterations: usize,
no_of_words: usize,
last_phrase: String,
}
impl BrainPrefix {
pub fn new(prefix: Vec<u8>, iterations: usize, no_of_words: usize) -> Self {
BrainPrefix {
prefix,
iterations,
no_of_words,
last_phrase: String::new(),
}
}
pub fn phrase(&self) -> &str {
&self.last_phrase
}
}
impl Generator for BrainPrefix {
type Error = Error;
fn generate(&mut self) -> Result<KeyPair, Error> {
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().starts_with(&self.prefix) {
self.last_phrase = phrase;
return Ok(keypair);
}
}
Err(Error::Custom("Could not find keypair".into()))
}
}
#[cfg(test)]
mod tests {
use BrainPrefix;
use Generator;
#[test]
fn prefix_generator() {
let prefix = vec![0x00u8];
let keypair = BrainPrefix::new(prefix.clone(), usize::max_value(), 12)
.generate()
.unwrap();
assert!(keypair.address().starts_with(&prefix));
}
}

View File

@@ -0,0 +1,178 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use std::collections::HashSet;
use edit_distance::edit_distance;
use parity_wordlist;
use super::{Address, Brain, Generator};
/// Tries to find a phrase for address, given the number
/// of expected words and a partial phrase.
///
/// Returns `None` if phrase couldn't be found.
pub fn brain_recover(
address: &Address,
known_phrase: &str,
expected_words: usize,
) -> Option<String> {
let it = PhrasesIterator::from_known_phrase(known_phrase, expected_words);
for phrase in it {
let keypair = Brain::new(phrase.clone())
.generate()
.expect("Brain wallets are infallible; qed");
trace!("Testing: {}, got: {:?}", phrase, keypair.address());
if &keypair.address() == address {
return Some(phrase);
}
}
None
}
fn generate_substitutions(word: &str) -> Vec<&'static str> {
let mut words = parity_wordlist::WORDS
.iter()
.cloned()
.map(|w| (edit_distance(w, word), w))
.collect::<Vec<_>>();
words.sort_by(|a, b| a.0.cmp(&b.0));
words.into_iter().map(|pair| pair.1).collect()
}
/// Iterator over possible
pub struct PhrasesIterator {
words: Vec<Vec<&'static str>>,
combinations: u64,
indexes: Vec<usize>,
has_next: bool,
}
impl PhrasesIterator {
pub fn from_known_phrase(known_phrase: &str, expected_words: usize) -> Self {
let known_words = parity_wordlist::WORDS
.iter()
.cloned()
.collect::<HashSet<_>>();
let mut words = known_phrase
.split(' ')
.map(|word| match known_words.get(word) {
None => {
info!(
"Invalid word '{}', looking for potential substitutions.",
word
);
let substitutions = generate_substitutions(word);
info!("Closest words: {:?}", &substitutions[..10]);
substitutions
}
Some(word) => vec![*word],
})
.collect::<Vec<_>>();
// add missing words
if words.len() < expected_words {
let to_add = expected_words - words.len();
info!("Number of words is insuficcient adding {} more.", to_add);
for _ in 0..to_add {
words.push(parity_wordlist::WORDS.iter().cloned().collect());
}
}
// start searching
PhrasesIterator::new(words)
}
pub fn new(words: Vec<Vec<&'static str>>) -> Self {
let combinations = words.iter().fold(1u64, |acc, x| acc * x.len() as u64);
let indexes = words.iter().map(|_| 0).collect();
info!("Starting to test {} possible combinations.", combinations);
PhrasesIterator {
words,
combinations,
indexes,
has_next: combinations > 0,
}
}
pub fn combinations(&self) -> u64 {
self.combinations
}
fn current(&self) -> String {
let mut s = self.words[0][self.indexes[0]].to_owned();
for i in 1..self.indexes.len() {
s.push(' ');
s.push_str(self.words[i][self.indexes[i]]);
}
s
}
fn next_index(&mut self) -> bool {
let mut pos = self.indexes.len();
while pos > 0 {
pos -= 1;
self.indexes[pos] += 1;
if self.indexes[pos] >= self.words[pos].len() {
self.indexes[pos] = 0;
} else {
return true;
}
}
false
}
}
impl Iterator for PhrasesIterator {
type Item = String;
fn next(&mut self) -> Option<String> {
if !self.has_next {
return None;
}
let phrase = self.current();
self.has_next = self.next_index();
Some(phrase)
}
}
#[cfg(test)]
mod tests {
use super::PhrasesIterator;
#[test]
fn should_generate_possible_combinations() {
let mut it =
PhrasesIterator::new(vec![vec!["1", "2", "3"], vec!["test"], vec!["a", "b", "c"]]);
assert_eq!(it.combinations(), 9);
assert_eq!(it.next(), Some("1 test a".to_owned()));
assert_eq!(it.next(), Some("1 test b".to_owned()));
assert_eq!(it.next(), Some("1 test c".to_owned()));
assert_eq!(it.next(), Some("2 test a".to_owned()));
assert_eq!(it.next(), Some("2 test b".to_owned()));
assert_eq!(it.next(), Some("2 test c".to_owned()));
assert_eq!(it.next(), Some("3 test a".to_owned()));
assert_eq!(it.next(), Some("3 test b".to_owned()));
assert_eq!(it.next(), Some("3 test c".to_owned()));
assert_eq!(it.next(), None);
}
}

View File

@@ -0,0 +1,202 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
#![allow(deprecated)]
use parity_crypto::error::SymmError;
use secp256k1;
use std::io;
quick_error! {
#[derive(Debug)]
pub enum Error {
Secp(e: secp256k1::Error) {
display("secp256k1 error: {}", e)
cause(e)
from()
}
Io(e: io::Error) {
display("i/o error: {}", e)
cause(e)
from()
}
InvalidMessage {
display("invalid message")
}
Symm(e: SymmError) {
cause(e)
from()
}
}
}
/// ECDH functions
pub mod ecdh {
use super::Error;
use secp256k1::{self, ecdh, key};
use Public;
use Secret;
use SECP256K1;
/// Agree on a shared secret
pub fn agree(secret: &Secret, public: &Public) -> Result<Secret, Error> {
let context = &SECP256K1;
let pdata = {
let mut temp = [4u8; 65];
(&mut temp[1..65]).copy_from_slice(&public[0..64]);
temp
};
let publ = key::PublicKey::from_slice(context, &pdata)?;
let sec = key::SecretKey::from_slice(context, &secret)?;
let shared = ecdh::SharedSecret::new_raw(context, &publ, &sec);
Secret::from_unsafe_slice(&shared[0..32])
.map_err(|_| Error::Secp(secp256k1::Error::InvalidSecretKey))
}
}
/// ECIES function
pub mod ecies {
use super::{ecdh, Error};
use ethereum_types::H128;
use parity_crypto::{aes, digest, hmac, is_equal};
use Generator;
use Public;
use Random;
use Secret;
/// Encrypt a message with a public key, writing an HMAC covering both
/// the plaintext and authenticated data.
///
/// Authenticated data may be empty.
pub fn encrypt(public: &Public, auth_data: &[u8], plain: &[u8]) -> Result<Vec<u8>, Error> {
let r = Random.generate()?;
let z = ecdh::agree(r.secret(), public)?;
let mut key = [0u8; 32];
kdf(&z, &[0u8; 0], &mut key);
let ekey = &key[0..16];
let mkey = hmac::SigKey::sha256(&digest::sha256(&key[16..32]));
let mut msg = vec![0u8; 1 + 64 + 16 + plain.len() + 32];
msg[0] = 0x04u8;
{
let msgd = &mut msg[1..];
msgd[0..64].copy_from_slice(r.public());
let iv = H128::random();
msgd[64..80].copy_from_slice(&iv);
{
let cipher = &mut msgd[(64 + 16)..(64 + 16 + plain.len())];
aes::encrypt_128_ctr(ekey, &iv, plain, cipher)?;
}
let mut hmac = hmac::Signer::with(&mkey);
{
let cipher_iv = &msgd[64..(64 + 16 + plain.len())];
hmac.update(cipher_iv);
}
hmac.update(auth_data);
let sig = hmac.sign();
msgd[(64 + 16 + plain.len())..].copy_from_slice(&sig);
}
Ok(msg)
}
/// Decrypt a message with a secret key, checking HMAC for ciphertext
/// and authenticated data validity.
pub fn decrypt(secret: &Secret, auth_data: &[u8], encrypted: &[u8]) -> Result<Vec<u8>, Error> {
let meta_len = 1 + 64 + 16 + 32;
if encrypted.len() < meta_len || encrypted[0] < 2 || encrypted[0] > 4 {
return Err(Error::InvalidMessage); //invalid message: publickey
}
let e = &encrypted[1..];
let p = Public::from_slice(&e[0..64]);
let z = ecdh::agree(secret, &p)?;
let mut key = [0u8; 32];
kdf(&z, &[0u8; 0], &mut key);
let ekey = &key[0..16];
let mkey = hmac::SigKey::sha256(&digest::sha256(&key[16..32]));
let clen = encrypted.len() - meta_len;
let cipher_with_iv = &e[64..(64 + 16 + clen)];
let cipher_iv = &cipher_with_iv[0..16];
let cipher_no_iv = &cipher_with_iv[16..];
let msg_mac = &e[(64 + 16 + clen)..];
// Verify tag
let mut hmac = hmac::Signer::with(&mkey);
hmac.update(cipher_with_iv);
hmac.update(auth_data);
let mac = hmac.sign();
if !is_equal(&mac.as_ref()[..], msg_mac) {
return Err(Error::InvalidMessage);
}
let mut msg = vec![0u8; clen];
aes::decrypt_128_ctr(ekey, cipher_iv, cipher_no_iv, &mut msg[..])?;
Ok(msg)
}
fn kdf(secret: &Secret, s1: &[u8], dest: &mut [u8]) {
// SEC/ISO/Shoup specify counter size SHOULD be equivalent
// to size of hash output, however, it also notes that
// the 4 bytes is okay. NIST specifies 4 bytes.
let mut ctr = 1u32;
let mut written = 0usize;
while written < dest.len() {
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);
hasher.update(s1);
let d = hasher.finish();
&mut dest[written..(written + 32)].copy_from_slice(&d);
written += 32;
ctr += 1;
}
}
}
#[cfg(test)]
mod tests {
use super::ecies;
use Generator;
use Random;
#[test]
fn ecies_shared() {
let kp = Random.generate().unwrap();
let message = b"So many books, so little time";
let shared = b"shared";
let wrong_shared = b"incorrect";
let encrypted = ecies::encrypt(kp.public(), shared, message).unwrap();
assert!(encrypted[..] != message[..]);
assert_eq!(encrypted[0], 0x04);
assert!(ecies::decrypt(kp.secret(), wrong_shared, &encrypted).is_err());
let decrypted = ecies::decrypt(kp.secret(), shared, &encrypted).unwrap();
assert_eq!(decrypted[..message.len()], message[..]);
}
}

View File

@@ -0,0 +1,81 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use std::{error, fmt};
#[derive(Debug)]
/// Crypto error
pub enum Error {
/// Invalid secret key
InvalidSecret,
/// Invalid public key
InvalidPublic,
/// Invalid address
InvalidAddress,
/// Invalid EC signature
InvalidSignature,
/// Invalid AES message
InvalidMessage,
/// IO Error
Io(::std::io::Error),
/// Custom
Custom(String),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let msg = match *self {
Error::InvalidSecret => "Invalid secret".into(),
Error::InvalidPublic => "Invalid public".into(),
Error::InvalidAddress => "Invalid address".into(),
Error::InvalidSignature => "Invalid EC signature".into(),
Error::InvalidMessage => "Invalid AES message".into(),
Error::Io(ref err) => format!("I/O error: {}", err),
Error::Custom(ref s) => s.clone(),
};
f.write_fmt(format_args!("Crypto error ({})", msg))
}
}
impl error::Error for Error {
fn description(&self) -> &str {
"Crypto error"
}
}
impl Into<String> for Error {
fn into(self) -> String {
format!("{}", self)
}
}
impl From<::secp256k1::Error> for Error {
fn from(e: ::secp256k1::Error) -> Error {
match e {
::secp256k1::Error::InvalidMessage => Error::InvalidMessage,
::secp256k1::Error::InvalidPublicKey => Error::InvalidPublic,
::secp256k1::Error::InvalidSecretKey => Error::InvalidSecret,
_ => Error::InvalidSignature,
}
}
}
impl From<::std::io::Error> for Error {
fn from(err: ::std::io::Error) -> Error {
Error::Io(err)
}
}

View File

@@ -0,0 +1,589 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
//! Extended keys
pub use self::derivation::Error as DerivationError;
use ethereum_types::H256;
use secret::Secret;
use Public;
/// Represents label that can be stored as a part of key derivation
pub trait Label {
/// Length of the data that label occupies
fn len() -> usize;
/// Store label data to the key derivation sequence
/// Must not use more than `len()` bytes from slice
fn store(&self, target: &mut [u8]);
}
impl Label for u32 {
fn len() -> usize {
4
}
fn store(&self, target: &mut [u8]) {
let bytes = self.to_be_bytes();
target[0..4].copy_from_slice(&bytes);
}
}
/// Key derivation over generic label `T`
pub enum Derivation<T: Label> {
/// Soft key derivation (allow proof of parent)
Soft(T),
/// Hard key derivation (does not allow proof of parent)
Hard(T),
}
impl From<u32> for Derivation<u32> {
fn from(index: u32) -> Self {
if index < (2 << 30) {
Derivation::Soft(index)
} else {
Derivation::Hard(index)
}
}
}
impl Label for H256 {
fn len() -> usize {
32
}
fn store(&self, target: &mut [u8]) {
self.copy_to(&mut target[0..32]);
}
}
/// Extended secret key, allows deterministic derivation of subsequent keys.
pub struct ExtendedSecret {
secret: Secret,
chain_code: H256,
}
impl ExtendedSecret {
/// New extended key from given secret and chain code.
pub fn with_code(secret: Secret, chain_code: H256) -> ExtendedSecret {
ExtendedSecret {
secret: secret,
chain_code: chain_code,
}
}
/// New extended key from given secret with the random chain code.
pub fn new_random(secret: Secret) -> ExtendedSecret {
ExtendedSecret::with_code(secret, H256::random())
}
/// New extended key from given secret.
/// Chain code will be derived from the secret itself (in a deterministic way).
pub fn new(secret: Secret) -> ExtendedSecret {
let chain_code = derivation::chain_code(*secret);
ExtendedSecret::with_code(secret, chain_code)
}
/// Derive new private key
pub fn derive<T>(&self, index: Derivation<T>) -> ExtendedSecret
where
T: Label,
{
let (derived_key, next_chain_code) =
derivation::private(*self.secret, self.chain_code, index);
let derived_secret = Secret::from(derived_key.0);
ExtendedSecret::with_code(derived_secret, next_chain_code)
}
/// Private key component of the extended key.
pub fn as_raw(&self) -> &Secret {
&self.secret
}
}
/// Extended public key, allows deterministic derivation of subsequent keys.
pub struct ExtendedPublic {
public: Public,
chain_code: H256,
}
impl ExtendedPublic {
/// New extended public key from known parent and chain code
pub fn new(public: Public, chain_code: H256) -> Self {
ExtendedPublic {
public: public,
chain_code: chain_code,
}
}
/// Create new extended public key from known secret
pub fn from_secret(secret: &ExtendedSecret) -> Result<Self, DerivationError> {
Ok(ExtendedPublic::new(
derivation::point(**secret.as_raw())?,
secret.chain_code.clone(),
))
}
/// Derive new public key
/// Operation is defined only for index belongs [0..2^31)
pub fn derive<T>(&self, index: Derivation<T>) -> Result<Self, DerivationError>
where
T: Label,
{
let (derived_key, next_chain_code) =
derivation::public(self.public, self.chain_code, index)?;
Ok(ExtendedPublic::new(derived_key, next_chain_code))
}
pub fn public(&self) -> &Public {
&self.public
}
}
pub struct ExtendedKeyPair {
secret: ExtendedSecret,
public: ExtendedPublic,
}
impl ExtendedKeyPair {
pub fn new(secret: Secret) -> Self {
let extended_secret = ExtendedSecret::new(secret);
let extended_public = ExtendedPublic::from_secret(&extended_secret)
.expect("Valid `Secret` always produces valid public; qed");
ExtendedKeyPair {
secret: extended_secret,
public: extended_public,
}
}
pub fn with_code(secret: Secret, public: Public, chain_code: H256) -> Self {
ExtendedKeyPair {
secret: ExtendedSecret::with_code(secret, chain_code.clone()),
public: ExtendedPublic::new(public, chain_code),
}
}
pub fn with_secret(secret: Secret, chain_code: H256) -> Self {
let extended_secret = ExtendedSecret::with_code(secret, chain_code);
let extended_public = ExtendedPublic::from_secret(&extended_secret)
.expect("Valid `Secret` always produces valid public; qed");
ExtendedKeyPair {
secret: extended_secret,
public: extended_public,
}
}
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).map_err(|_| DerivationError::InvalidSeed)?,
chain_code,
))
}
pub fn secret(&self) -> &ExtendedSecret {
&self.secret
}
pub fn public(&self) -> &ExtendedPublic {
&self.public
}
pub fn derive<T>(&self, index: Derivation<T>) -> Result<Self, DerivationError>
where
T: Label,
{
let derived = self.secret.derive(index);
Ok(ExtendedKeyPair {
public: ExtendedPublic::from_secret(&derived)?,
secret: derived,
})
}
}
// Derivation functions for private and public keys
// Work is based on BIP0032
// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
mod derivation {
use super::{Derivation, Label};
use ethereum_types::{H256, H512, U256, U512};
use keccak;
use math::curve_order;
use parity_crypto::hmac;
use secp256k1::key::{PublicKey, SecretKey};
use SECP256K1;
#[derive(Debug)]
pub enum Error {
InvalidHardenedUse,
InvalidPoint,
MissingIndex,
InvalidSeed,
}
// Deterministic derivation of the key using secp256k1 elliptic curve.
// Derivation can be either hardened or not.
// For hardened derivation, pass u32 index at least 2^31 or custom Derivation::Hard(T) enum
//
// Can panic if passed `private_key` is not a valid secp256k1 private key
// (outside of (0..curve_order()]) field
pub fn private<T>(private_key: H256, chain_code: H256, index: Derivation<T>) -> (H256, H256)
where
T: Label,
{
match index {
Derivation::Soft(index) => private_soft(private_key, chain_code, index),
Derivation::Hard(index) => private_hard(private_key, chain_code, index),
}
}
fn hmac_pair(data: &[u8], private_key: H256, chain_code: H256) -> (H256, H256) {
let private: U256 = private_key.into();
// produces 512-bit derived hmac (I)
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();
// right most 256 bits are new chain code for later derivations
let next_chain_code = H256::from(&i_512[32..64]);
let child_key = private_add(hmac_key, private).into();
(child_key, next_chain_code)
}
// Can panic if passed `private_key` is not a valid secp256k1 private key
// (outside of (0..curve_order()]) field
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)
.expect("Caller should provide valid private key");
let sec_public = PublicKey::from_secret_key(&SECP256K1, &sec_private)
.expect("Caller should provide valid private key");
let public_serialized = sec_public.serialize_vec(&SECP256K1, true);
// curve point (compressed public key) -- index
// 0.33 -- 33..end
data[0..33].copy_from_slice(&public_serialized);
index.store(&mut data[33..]);
hmac_pair(&data, private_key, chain_code)
}
// Deterministic derivation of the key using secp256k1 elliptic curve
// This is hardened derivation and does not allow to associate
// 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();
// 0x00 (padding) -- private_key -- index
// 0 -- 1..33 -- 33..end
private.to_big_endian(&mut data[1..33]);
index.store(&mut data[33..(33 + T::len())]);
hmac_pair(&data, private_key, chain_code)
}
fn private_add(k1: U256, k2: U256) -> U256 {
let sum = U512::from(k1) + U512::from(k2);
modulo(sum, curve_order())
}
// todo: surely can be optimized
fn modulo(u1: U512, u2: U256) -> U256 {
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,
{
let index = match derivation {
Derivation::Soft(index) => index,
Derivation::Hard(_) => {
return Err(Error::InvalidHardenedUse);
}
};
let mut public_sec_raw = [0u8; 65];
public_sec_raw[0] = 4;
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);
let mut data = vec![0u8; 33 + T::len()];
// curve point (compressed public key) -- index
// 0.33 -- 33..end
data[0..33].copy_from_slice(&public_serialized);
index.store(&mut data[33..(33 + T::len())]);
// HMAC512SHA produces [derived private(256); new chain code(256)]
let skey = hmac::SigKey::sha512(&*chain_code);
let i_512 = hmac::sign(&skey, &data[..]);
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.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");
// Adding two points on the elliptic curves (combining two public keys)
new_public
.add_assign(&SECP256K1, &public_sec)
.expect("Addition of two valid points produce valid point");
let serialized = new_public.serialize_vec(&SECP256K1, false);
Ok((H512::from(&serialized[1..65]), new_chain_code))
}
fn sha3(slc: &[u8]) -> H256 {
keccak::Keccak256::keccak256(slc).into()
}
pub fn chain_code(secret: H256) -> H256 {
// 10,000 rounds of sha3
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).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(&serialized[1..65]))
}
pub fn seed_pair(seed: &[u8]) -> (H256, H256) {
let skey = hmac::SigKey::sha512(b"Bitcoin seed");
let i_512 = hmac::sign(&skey, seed);
let master_key = H256::from_slice(&i_512[0..32]);
let chain_code = H256::from_slice(&i_512[32..64]);
(master_key, chain_code)
}
}
#[cfg(test)]
mod tests {
use super::{derivation, Derivation, ExtendedKeyPair, ExtendedPublic, ExtendedSecret};
use ethereum_types::{H128, H256};
use secret::Secret;
use std::str::FromStr;
fn master_chain_basic() -> (H256, H256) {
let seed = H128::from_str("000102030405060708090a0b0c0d0e0f")
.expect("Seed should be valid H128")
.to_vec();
derivation::seed_pair(&*seed)
}
fn test_extended<F>(f: F, test_private: H256)
where
F: Fn(ExtendedSecret) -> ExtendedSecret,
{
let (private_seed, chain_code) = master_chain_basic();
let extended_secret = ExtendedSecret::with_code(Secret::from(private_seed.0), chain_code);
let derived = f(extended_secret);
assert_eq!(**derived.as_raw(), test_private);
}
#[test]
fn smoky() {
let secret =
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
.unwrap();
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(),
&"0927453daed47839608e414a3738dfad10aed17c459bbd9ab53f89b026c834b6".into()
);
assert_eq!(
&**extended_secret.derive(2147483649.into()).as_raw(),
&"44238b6a29c6dcbe9b401364141ba11e2198c289a5fed243a1c11af35c19dc0f".into()
);
// normal
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(), &"f7b3244c96688f92372bfd4def26dc4151529747bab9f188a4ad34e141d47bd66522ff048bc6f19a0a4429b04318b1a8796c000265b4fa200dae5f6dda92dd94".into());
let keypair = ExtendedKeyPair::with_secret(
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
.unwrap(),
064.into(),
);
assert_eq!(
&**keypair
.derive(2147483648u32.into())
.expect("Derivation of keypair should succeed")
.secret()
.as_raw(),
&"edef54414c03196557cf73774bc97a645c9a1df2164ed34f0c2a78d1375a930c".into()
);
}
#[test]
fn h256_soft_match() {
let secret =
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
.unwrap();
let derivation_secret =
H256::from_str("51eaf04f9dbbc1417dc97e789edd0c37ecda88bac490434e367ea81b71b7b015")
.unwrap();
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));
let derived_public0 = extended_public
.derive(Derivation::Soft(derivation_secret))
.expect("First derivation of public should succeed");
let public_from_secret0 = ExtendedPublic::from_secret(&derived_secret0)
.expect("Extended public should be created");
assert_eq!(public_from_secret0.public(), derived_public0.public());
}
#[test]
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(), 1u64.into());
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(), 1.into());
let extended_public = ExtendedPublic::from_secret(&extended_secret)
.expect("Extended public should be created");
let derived_secret0 = extended_secret.derive(0.into());
let derived_public0 = extended_public
.derive(0.into())
.expect("First derivation of public should succeed");
let public_from_secret0 = ExtendedPublic::from_secret(&derived_secret0)
.expect("Extended public should be created");
assert_eq!(public_from_secret0.public(), derived_public0.public());
}
#[test]
fn test_seeds() {
let seed = H128::from_str("000102030405060708090a0b0c0d0e0f")
.expect("Seed should be valid H128")
.to_vec();
// private key from bitcoin test vector
// xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs
let test_private =
H256::from_str("e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35")
.expect("Private should be decoded ok");
let (private_seed, _) = derivation::seed_pair(&*seed);
assert_eq!(private_seed, test_private);
}
#[test]
fn test_vector_1() {
// xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7
// H(0)
test_extended(
|secret| secret.derive(2147483648.into()),
H256::from_str("edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea")
.expect("Private should be decoded ok"),
);
}
#[test]
fn test_vector_2() {
// xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs
// H(0)/1
test_extended(
|secret| secret.derive(2147483648.into()).derive(1.into()),
H256::from_str("3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368")
.expect("Private should be decoded ok"),
);
}
}

View File

@@ -0,0 +1,33 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use tiny_keccak::Keccak;
pub trait Keccak256<T> {
fn keccak256(&self) -> T
where
T: Sized;
}
impl Keccak256<[u8; 32]> for [u8] {
fn keccak256(&self) -> [u8; 32] {
let mut keccak = Keccak::new_keccak256();
let mut result = [0u8; 32];
keccak.update(self);
keccak.finalize(&mut result);
result
}
}

View File

@@ -0,0 +1,120 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::{Address, Error, Public, Secret, SECP256K1};
use keccak::Keccak256;
use rustc_hex::ToHex;
use secp256k1::key;
use std::fmt;
pub fn public_to_address(public: &Public) -> Address {
let hash = public.keccak256();
let mut result = Address::default();
result.copy_from_slice(&hash[12..]);
result
}
#[derive(Debug, Clone, PartialEq)]
/// secp256k1 key pair
pub struct KeyPair {
secret: Secret,
public: Public,
}
impl fmt::Display for KeyPair {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
writeln!(f, "secret: {}", self.secret.to_hex())?;
writeln!(f, "public: {}", self.public.to_hex())?;
write!(f, "address: {}", self.address().to_hex())
}
}
impl KeyPair {
/// Create a pair from secret key
pub fn from_secret(secret: Secret) -> Result<KeyPair, Error> {
let context = &SECP256K1;
let s: key::SecretKey = key::SecretKey::from_slice(context, &secret[..])?;
let pub_key = key::PublicKey::from_secret_key(context, &s)?;
let serialized = pub_key.serialize_vec(context, false);
let mut public = Public::default();
public.copy_from_slice(&serialized[1..65]);
let keypair = KeyPair {
secret: secret,
public: public,
};
Ok(keypair)
}
pub fn from_secret_slice(slice: &[u8]) -> Result<KeyPair, Error> {
Self::from_secret(Secret::from_unsafe_slice(slice)?)
}
pub fn from_keypair(sec: key::SecretKey, publ: key::PublicKey) -> Self {
let context = &SECP256K1;
let serialized = publ.serialize_vec(context, false);
let secret = Secret::from(sec);
let mut public = Public::default();
public.copy_from_slice(&serialized[1..65]);
KeyPair {
secret: secret,
public: public,
}
}
pub fn secret(&self) -> &Secret {
&self.secret
}
pub fn public(&self) -> &Public {
&self.public
}
pub fn address(&self) -> Address {
public_to_address(&self.public)
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use KeyPair;
use Secret;
#[test]
fn from_secret() {
let secret =
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
.unwrap();
let _ = KeyPair::from_secret(secret).unwrap();
}
#[test]
fn keypair_display() {
let expected =
"secret: a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65
public: 8ce0db0b0359ffc5866ba61903cc2518c3675ef2cf380a7e54bde7ea20e6fa1ab45b7617346cd11b7610001ee6ae5b0155c41cad9527cbcdff44ec67848943a4
address: 5b073e9233944b5e729e46d618f0d8edf3d9c34a".to_owned();
let secret =
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
.unwrap();
let kp = KeyPair::from_secret(secret).unwrap();
assert_eq!(format!("{}", kp), expected);
}
}

View File

@@ -1,26 +1,25 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// Parity is free software: you can redistribute it and/or modify
// OpenEthereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// OpenEthereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
// #![warn(missing_docs)]
extern crate byteorder;
extern crate edit_distance;
extern crate parity_crypto;
extern crate ethereum_types;
extern crate mem;
extern crate memzero;
extern crate parity_crypto;
extern crate parity_wordlist;
#[macro_use]
extern crate quick_error;
@@ -40,31 +39,33 @@ extern crate serde_derive;
mod brain;
mod brain_prefix;
mod error;
mod keypair;
mod extended;
mod keccak;
mod keypair;
mod password;
mod prefix;
mod random;
mod signature;
mod secret;
mod extended;
mod signature;
pub mod brain_recover;
pub mod crypto;
pub mod math;
pub use self::parity_wordlist::Error as WordlistError;
pub use self::brain::Brain;
pub use self::brain_prefix::BrainPrefix;
pub use self::error::Error;
pub use self::keypair::{KeyPair, public_to_address};
pub use self::math::public_is_valid;
pub use self::password::Password;
pub use self::prefix::Prefix;
pub use self::random::Random;
pub use self::signature::{sign, verify_public, verify_address, recover, Signature};
pub use self::secret::Secret;
pub use self::extended::{ExtendedPublic, ExtendedSecret, ExtendedKeyPair, DerivationError, Derivation};
pub use self::{
brain::Brain,
brain_prefix::BrainPrefix,
error::Error,
extended::{Derivation, DerivationError, ExtendedKeyPair, ExtendedPublic, ExtendedSecret},
keypair::{public_to_address, KeyPair},
math::public_is_valid,
parity_wordlist::Error as WordlistError,
password::Password,
prefix::Prefix,
random::Random,
secret::Secret,
signature::{recover, sign, verify_address, verify_public, Signature},
};
use ethereum_types::H256;
@@ -72,7 +73,7 @@ pub use ethereum_types::{Address, Public};
pub type Message = H256;
lazy_static! {
pub static ref SECP256K1: secp256k1::Secp256k1 = secp256k1::Secp256k1::new();
pub static ref SECP256K1: secp256k1::Secp256k1 = secp256k1::Secp256k1::new();
}
/// Uninstantiatable error type for infallible generators.
@@ -81,8 +82,8 @@ pub enum Void {}
/// Generates new keypair.
pub trait Generator {
type Error;
type Error;
/// Should be called to generate new keypair.
fn generate(&mut self) -> Result<KeyPair, Self::Error>;
/// Should be called to generate new keypair.
fn generate(&mut self) -> Result<KeyPair, Self::Error>;
}

134
accounts/ethkey/src/math.rs Normal file
View File

@@ -0,0 +1,134 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::{Error, Public, Secret, SECP256K1};
use ethereum_types::{H256, U256};
use secp256k1::{
constants::{CURVE_ORDER, GENERATOR_X, GENERATOR_Y},
key,
};
/// Whether the public key is valid.
pub fn public_is_valid(public: &Public) -> bool {
to_secp256k1_public(public)
.ok()
.map_or(false, |p| p.is_valid())
}
/// Inplace multiply public key by secret key (EC point * scalar)
pub fn public_mul_secret(public: &mut Public, secret: &Secret) -> Result<(), Error> {
let key_secret = secret.to_secp256k1_secret()?;
let mut key_public = to_secp256k1_public(public)?;
key_public.mul_assign(&SECP256K1, &key_secret)?;
set_public(public, &key_public);
Ok(())
}
/// Inplace add one public key to another (EC point + EC point)
pub fn public_add(public: &mut Public, other: &Public) -> Result<(), Error> {
let mut key_public = to_secp256k1_public(public)?;
let other_public = to_secp256k1_public(other)?;
key_public.add_assign(&SECP256K1, &other_public)?;
set_public(public, &key_public);
Ok(())
}
/// Inplace sub one public key from another (EC point - EC point)
pub fn public_sub(public: &mut Public, other: &Public) -> Result<(), Error> {
let mut key_neg_other = to_secp256k1_public(other)?;
key_neg_other.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
let mut key_public = to_secp256k1_public(public)?;
key_public.add_assign(&SECP256K1, &key_neg_other)?;
set_public(public, &key_public);
Ok(())
}
/// Replace public key with its negation (EC point = - EC point)
pub fn public_negate(public: &mut Public) -> Result<(), Error> {
let mut key_public = to_secp256k1_public(public)?;
key_public.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
set_public(public, &key_public);
Ok(())
}
/// Return base point of secp256k1
pub fn generation_point() -> Public {
let mut public_sec_raw = [0u8; 65];
public_sec_raw[0] = 4;
public_sec_raw[1..33].copy_from_slice(&GENERATOR_X);
public_sec_raw[33..65].copy_from_slice(&GENERATOR_Y);
let public_key = key::PublicKey::from_slice(&SECP256K1, &public_sec_raw)
.expect("constructing using predefined constants; qed");
let mut public = Public::default();
set_public(&mut public, &public_key);
public
}
/// Return secp256k1 elliptic curve order
pub fn curve_order() -> U256 {
H256::from_slice(&CURVE_ORDER).into()
}
fn to_secp256k1_public(public: &Public) -> Result<key::PublicKey, Error> {
let public_data = {
let mut temp = [4u8; 65];
(&mut temp[1..65]).copy_from_slice(&public[0..64]);
temp
};
Ok(key::PublicKey::from_slice(&SECP256K1, &public_data)?)
}
fn set_public(public: &mut Public, key_public: &key::PublicKey) {
let key_public_serialized = key_public.serialize_vec(&SECP256K1, false);
public.copy_from_slice(&key_public_serialized[1..65]);
}
#[cfg(test)]
mod tests {
use super::{
super::{Generator, Random},
public_add, public_sub,
};
#[test]
fn public_addition_is_commutative() {
let public1 = Random.generate().unwrap().public().clone();
let public2 = Random.generate().unwrap().public().clone();
let mut left = public1.clone();
public_add(&mut left, &public2).unwrap();
let mut right = public2.clone();
public_add(&mut right, &public1).unwrap();
assert_eq!(left, right);
}
#[test]
fn public_addition_is_reversible_with_subtraction() {
let public1 = Random.generate().unwrap().public().clone();
let public2 = Random.generate().unwrap().public().clone();
let mut sum = public1.clone();
public_add(&mut sum, &public2).unwrap();
public_sub(&mut sum, &public2).unwrap();
assert_eq!(sum, public1);
}
}

View File

@@ -0,0 +1,59 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use std::{fmt, ptr};
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Password(String);
impl fmt::Debug for Password {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Password(******)")
}
}
impl Password {
pub fn as_bytes(&self) -> &[u8] {
self.0.as_bytes()
}
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
// Custom drop impl to zero out memory.
impl Drop for Password {
fn drop(&mut self) {
unsafe {
for byte_ref in self.0.as_mut_vec() {
ptr::write_volatile(byte_ref, 0)
}
}
}
}
impl From<String> for Password {
fn from(s: String) -> Password {
Password(s)
}
}
impl<'a> From<&'a str> for Password {
fn from(s: &'a str) -> Password {
Password::from(String::from(s))
}
}

View File

@@ -0,0 +1,62 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::{Error, Generator, KeyPair, Random};
/// Tries to find keypair with address starting with given prefix.
pub struct Prefix {
prefix: Vec<u8>,
iterations: usize,
}
impl Prefix {
pub fn new(prefix: Vec<u8>, iterations: usize) -> Self {
Prefix {
prefix: prefix,
iterations: iterations,
}
}
}
impl Generator for Prefix {
type Error = Error;
fn generate(&mut self) -> Result<KeyPair, Error> {
for _ in 0..self.iterations {
let keypair = Random.generate()?;
if keypair.address().starts_with(&self.prefix) {
return Ok(keypair);
}
}
Err(Error::Custom("Could not find keypair".into()))
}
}
#[cfg(test)]
mod tests {
use Generator;
use Prefix;
#[test]
fn prefix_generator() {
let prefix = vec![0xffu8];
let keypair = Prefix::new(prefix.clone(), usize::max_value())
.generate()
.unwrap();
assert!(keypair.address().starts_with(&prefix));
}
}

View File

@@ -0,0 +1,45 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::{Generator, KeyPair, SECP256K1};
use rand::os::OsRng;
/// Randomly generates new keypair, instantiating the RNG each time.
pub struct Random;
impl Generator for Random {
type Error = ::std::io::Error;
fn generate(&mut self) -> Result<KeyPair, Self::Error> {
let mut rng = OsRng::new()?;
match rng.generate() {
Ok(pair) => Ok(pair),
Err(void) => match void {}, // LLVM unreachable
}
}
}
impl Generator for OsRng {
type Error = ::Void;
fn generate(&mut self) -> Result<KeyPair, Self::Error> {
let (sec, publ) = SECP256K1
.generate_keypair(self)
.expect("context always created with full capabilities; qed");
Ok(KeyPair::from_keypair(sec, publ))
}
}

View File

@@ -0,0 +1,322 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use ethereum_types::H256;
use memzero::Memzero;
use rustc_hex::ToHex;
use secp256k1::{constants::SECRET_KEY_SIZE as SECP256K1_SECRET_KEY_SIZE, key};
use std::{fmt, ops::Deref, str::FromStr};
use Error;
use SECP256K1;
#[derive(Clone, PartialEq, Eq)]
pub struct Secret {
inner: Memzero<H256>,
}
impl ToHex for Secret {
fn to_hex(&self) -> String {
format!("{:x}", *self.inner)
}
}
impl fmt::LowerHex for Secret {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.inner.fmt(fmt)
}
}
impl fmt::Debug for Secret {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.inner.fmt(fmt)
}
}
impl fmt::Display for Secret {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(
fmt,
"Secret: 0x{:x}{:x}..{:x}{:x}",
self.inner[0], self.inner[1], self.inner[30], self.inner[31]
)
}
}
impl Secret {
/// Creates a `Secret` from the given slice, returning `None` if the slice length != 32.
pub fn from_slice(key: &[u8]) -> Option<Self> {
if key.len() != 32 {
return None;
}
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: Memzero::from(H256::default()),
}
}
/// Imports and validates the key.
pub fn from_unsafe_slice(key: &[u8]) -> Result<Self, Error> {
let secret = key::SecretKey::from_slice(&super::SECP256K1, key)?;
Ok(secret.into())
}
/// Checks validity of this key.
pub fn check_validity(&self) -> Result<(), Error> {
self.to_secp256k1_secret().map(|_| ())
}
/// Inplace add one secret key to another (scalar + scalar)
pub fn add(&mut self, other: &Secret) -> Result<(), Error> {
match (self.is_zero(), other.is_zero()) {
(true, true) | (false, true) => Ok(()),
(true, false) => {
*self = other.clone();
Ok(())
}
(false, false) => {
let mut key_secret = self.to_secp256k1_secret()?;
let other_secret = other.to_secp256k1_secret()?;
key_secret.add_assign(&SECP256K1, &other_secret)?;
*self = key_secret.into();
Ok(())
}
}
}
/// Inplace subtract one secret key from another (scalar - scalar)
pub fn sub(&mut self, other: &Secret) -> Result<(), Error> {
match (self.is_zero(), other.is_zero()) {
(true, true) | (false, true) => Ok(()),
(true, false) => {
*self = other.clone();
self.neg()
}
(false, false) => {
let mut key_secret = self.to_secp256k1_secret()?;
let mut other_secret = other.to_secp256k1_secret()?;
other_secret.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
key_secret.add_assign(&SECP256K1, &other_secret)?;
*self = key_secret.into();
Ok(())
}
}
}
/// Inplace decrease secret key (scalar - 1)
pub fn dec(&mut self) -> Result<(), Error> {
match self.is_zero() {
true => {
*self = key::MINUS_ONE_KEY.into();
Ok(())
}
false => {
let mut key_secret = self.to_secp256k1_secret()?;
key_secret.add_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
*self = key_secret.into();
Ok(())
}
}
}
/// Inplace multiply one secret key to another (scalar * scalar)
pub fn mul(&mut self, other: &Secret) -> Result<(), Error> {
match (self.is_zero(), other.is_zero()) {
(true, true) | (true, false) => Ok(()),
(false, true) => {
*self = Self::zero();
Ok(())
}
(false, false) => {
let mut key_secret = self.to_secp256k1_secret()?;
let other_secret = other.to_secp256k1_secret()?;
key_secret.mul_assign(&SECP256K1, &other_secret)?;
*self = key_secret.into();
Ok(())
}
}
}
/// Inplace negate secret key (-scalar)
pub fn neg(&mut self) -> Result<(), Error> {
match self.is_zero() {
true => Ok(()),
false => {
let mut key_secret = self.to_secp256k1_secret()?;
key_secret.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
*self = key_secret.into();
Ok(())
}
}
}
/// Inplace inverse secret key (1 / scalar)
pub fn inv(&mut self) -> Result<(), Error> {
let mut key_secret = self.to_secp256k1_secret()?;
key_secret.inv_assign(&SECP256K1)?;
*self = key_secret.into();
Ok(())
}
/// Compute power of secret key inplace (secret ^ pow).
/// This function is not intended to be used with large powers.
pub fn pow(&mut self, pow: usize) -> Result<(), Error> {
if self.is_zero() {
return Ok(());
}
match pow {
0 => *self = key::ONE_KEY.into(),
1 => (),
_ => {
let c = self.clone();
for _ in 1..pow {
self.mul(&c)?;
}
}
}
Ok(())
}
/// Create `secp256k1::key::SecretKey` based on this secret
pub fn to_secp256k1_secret(&self) -> Result<key::SecretKey, Error> {
Ok(key::SecretKey::from_slice(&SECP256K1, &self[..])?)
}
}
impl FromStr for Secret {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(H256::from_str(s)
.map_err(|e| Error::Custom(format!("{:?}", e)))?
.into())
}
}
impl From<[u8; 32]> for Secret {
fn from(k: [u8; 32]) -> Self {
Secret {
inner: Memzero::from(H256(k)),
}
}
}
impl From<H256> for Secret {
fn from(s: H256) -> Self {
s.0.into()
}
}
impl From<&'static str> for Secret {
fn from(s: &'static str) -> Self {
s.parse().expect(&format!(
"invalid string literal for {}: '{}'",
stringify!(Self),
s
))
}
}
impl From<key::SecretKey> for Secret {
fn from(key: key::SecretKey) -> Self {
let mut a = [0; SECP256K1_SECRET_KEY_SIZE];
a.copy_from_slice(&key[0..SECP256K1_SECRET_KEY_SIZE]);
a.into()
}
}
impl Deref for Secret {
type Target = H256;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
#[cfg(test)]
mod tests {
use super::{
super::{Generator, Random},
Secret,
};
use std::str::FromStr;
#[test]
fn multiplicating_secret_inversion_with_secret_gives_one() {
let secret = Random.generate().unwrap().secret().clone();
let mut inversion = secret.clone();
inversion.inv().unwrap();
inversion.mul(&secret).unwrap();
assert_eq!(
inversion,
Secret::from_str("0000000000000000000000000000000000000000000000000000000000000001")
.unwrap()
);
}
#[test]
fn secret_inversion_is_reversible_with_inversion() {
let secret = Random.generate().unwrap().secret().clone();
let mut inversion = secret.clone();
inversion.inv().unwrap();
inversion.inv().unwrap();
assert_eq!(inversion, secret);
}
#[test]
fn secret_pow() {
let secret = Random.generate().unwrap().secret().clone();
let mut pow0 = secret.clone();
pow0.pow(0).unwrap();
assert_eq!(
pow0,
Secret::from_str("0000000000000000000000000000000000000000000000000000000000000001")
.unwrap()
);
let mut pow1 = secret.clone();
pow1.pow(1).unwrap();
assert_eq!(pow1, secret);
let mut pow2 = secret.clone();
pow2.pow(2).unwrap();
let mut pow2_expected = secret.clone();
pow2_expected.mul(&secret).unwrap();
assert_eq!(pow2, pow2_expected);
let mut pow3 = secret.clone();
pow3.pow(3).unwrap();
let mut pow3_expected = secret.clone();
pow3_expected.mul(&secret).unwrap();
pow3_expected.mul(&secret).unwrap();
assert_eq!(pow3, pow3_expected);
}
}

View File

@@ -0,0 +1,325 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use ethereum_types::{H256, H520};
use public_to_address;
use rustc_hex::{FromHex, ToHex};
use secp256k1::{
key::{PublicKey, SecretKey},
Error as SecpError, Message as SecpMessage, RecoverableSignature, RecoveryId,
};
use std::{
cmp::PartialEq,
fmt,
hash::{Hash, Hasher},
ops::{Deref, DerefMut},
str::FromStr,
};
use Address;
use Error;
use Message;
use Public;
use Secret;
use SECP256K1;
/// Signature encoded as RSV components
#[repr(C)]
pub struct Signature([u8; 65]);
impl Signature {
/// Get a slice into the 'r' portion of the data.
pub fn r(&self) -> &[u8] {
&self.0[0..32]
}
/// Get a slice into the 's' portion of the data.
pub fn s(&self) -> &[u8] {
&self.0[32..64]
}
/// Get the recovery byte.
pub fn v(&self) -> u8 {
self.0[64]
}
/// Encode the signature into RSV array (V altered to be in "Electrum" notation).
pub fn into_electrum(mut self) -> [u8; 65] {
self.0[64] += 27;
self.0
}
/// Parse bytes as a signature encoded as RSV (V in "Electrum" notation).
/// May return empty (invalid) signature if given data has invalid length.
pub fn from_electrum(data: &[u8]) -> Self {
if data.len() != 65 || data[64] < 27 {
// fallback to empty (invalid) signature
return Signature::default();
}
let mut sig = [0u8; 65];
sig.copy_from_slice(data);
sig[64] -= 27;
Signature(sig)
}
/// 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);
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 {
H256::from_slice(self.s())
<= "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0".into()
}
/// Check if each component of the signature is in range.
pub fn is_valid(&self) -> bool {
self.v() <= 1
&& 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()
}
}
// manual implementation large arrays don't have trait impls by default.
// remove when integer generics exist
impl PartialEq for Signature {
fn eq(&self, other: &Self) -> bool {
&self.0[..] == &other.0[..]
}
}
// manual implementation required in Rust 1.13+, see `std::cmp::AssertParamIsEq`.
impl Eq for Signature {}
// also manual for the same reason, but the pretty printing might be useful.
impl fmt::Debug for Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.debug_struct("Signature")
.field("r", &self.0[0..32].to_hex())
.field("s", &self.0[32..64].to_hex())
.field("v", &self.0[64..65].to_hex())
.finish()
}
}
impl fmt::Display for Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}", self.to_hex())
}
}
impl FromStr for Signature {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.from_hex() {
Ok(ref hex) if hex.len() == 65 => {
let mut data = [0; 65];
data.copy_from_slice(&hex[0..65]);
Ok(Signature(data))
}
_ => Err(Error::InvalidSignature),
}
}
}
impl Default for Signature {
fn default() -> Self {
Signature([0; 65])
}
}
impl Hash for Signature {
fn hash<H: Hasher>(&self, state: &mut H) {
H520::from(self.0).hash(state);
}
}
impl Clone for Signature {
fn clone(&self) -> Self {
Signature(self.0)
}
}
impl From<[u8; 65]> for Signature {
fn from(s: [u8; 65]) -> Self {
Signature(s)
}
}
impl Into<[u8; 65]> for Signature {
fn into(self) -> [u8; 65] {
self.0
}
}
impl From<Signature> for H520 {
fn from(s: Signature) -> Self {
H520::from(s.0)
}
}
impl From<H520> for Signature {
fn from(bytes: H520) -> Self {
Signature(bytes.into())
}
}
impl Deref for Signature {
type Target = [u8; 65];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Signature {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
pub fn sign(secret: &Secret, message: &Message) -> Result<Signature, Error> {
let context = &SECP256K1;
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];
// no need to check if s is low, it always is
data_arr[0..64].copy_from_slice(&data[0..64]);
data_arr[64] = rec_id.to_i32() as u8;
Ok(Signature(data_arr))
}
pub fn verify_public(
public: &Public,
signature: &Signature,
message: &Message,
) -> Result<bool, Error> {
let context = &SECP256K1;
let rsig = RecoverableSignature::from_compact(
context,
&signature[0..64],
RecoveryId::from_i32(signature[64] as i32)?,
)?;
let sig = rsig.to_standard(context);
let pdata: [u8; 65] = {
let mut temp = [4u8; 65];
temp[1..65].copy_from_slice(&**public);
temp
};
let publ = PublicKey::from_slice(context, &pdata)?;
match context.verify(&SecpMessage::from_slice(&message[..])?, &sig, &publ) {
Ok(_) => Ok(true),
Err(SecpError::IncorrectSignature) => Ok(false),
Err(x) => Err(Error::from(x)),
}
}
pub fn verify_address(
address: &Address,
signature: &Signature,
message: &Message,
) -> Result<bool, Error> {
let public = recover(signature, message)?;
let recovered_address = public_to_address(&public);
Ok(address == &recovered_address)
}
pub fn recover(signature: &Signature, message: &Message) -> Result<Public, Error> {
let context = &SECP256K1;
let rsig = RecoverableSignature::from_compact(
context,
&signature[0..64],
RecoveryId::from_i32(signature[64] as i32)?,
)?;
let pubkey = context.recover(&SecpMessage::from_slice(&message[..])?, &rsig)?;
let serialized = pubkey.serialize_vec(context, false);
let mut public = Public::default();
public.copy_from_slice(&serialized[1..65]);
Ok(public)
}
#[cfg(test)]
mod tests {
use super::{recover, sign, verify_address, verify_public, Signature};
use std::str::FromStr;
use Generator;
use Message;
use Random;
#[test]
fn vrs_conversion() {
// given
let keypair = Random.generate().unwrap();
let message = Message::default();
let signature = sign(keypair.secret(), &message).unwrap();
// when
let vrs = signature.clone().into_electrum();
let from_vrs = Signature::from_electrum(&vrs);
// then
assert_eq!(signature, from_vrs);
}
#[test]
fn signature_to_and_from_str() {
let keypair = Random.generate().unwrap();
let message = Message::default();
let signature = sign(keypair.secret(), &message).unwrap();
let string = format!("{}", signature);
let deserialized = Signature::from_str(&string).unwrap();
assert_eq!(signature, deserialized);
}
#[test]
fn sign_and_recover_public() {
let keypair = Random.generate().unwrap();
let message = Message::default();
let signature = sign(keypair.secret(), &message).unwrap();
assert_eq!(keypair.public(), &recover(&signature, &message).unwrap());
}
#[test]
fn sign_and_verify_public() {
let keypair = Random.generate().unwrap();
let message = Message::default();
let signature = sign(keypair.secret(), &message).unwrap();
assert!(verify_public(keypair.public(), &signature, &message).unwrap());
}
#[test]
fn sign_and_verify_address() {
let keypair = Random.generate().unwrap();
let message = Message::default();
let signature = sign(keypair.secret(), &message).unwrap();
assert!(verify_address(&keypair.address(), &signature, &message).unwrap());
}
}

View File

@@ -1,6 +1,7 @@
[package]
description = "Parity Ethereum Key Management"
name = "ethstore"
version = "0.2.0"
version = "0.2.1"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
@@ -12,16 +13,15 @@ serde = "1.0"
serde_json = "1.0"
serde_derive = "1.0"
rustc-hex = "1.0"
tiny-keccak = "1.4"
time = "0.1.34"
itertools = "0.5"
parking_lot = "0.6"
parity-crypto = "0.2"
parking_lot = "0.7"
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

@@ -6,7 +6,7 @@ Parity Ethereum key management.
```
Parity Ethereum key management tool.
Copyright 2015-2018 Parity Technologies (UK) Ltd.
Copyright 2015-2019 Parity Technologies (UK) Ltd.
Usage:
ethstore insert <secret> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
@@ -335,6 +335,5 @@ _This project is a part of the Parity Ethereum toolchain._
- [evmbin](https://github.com/paritytech/parity-ethereum/blob/master/evmbin/) - EVM implementation for Parity Ethereum.
- [ethabi](https://github.com/paritytech/ethabi) - Parity Ethereum function calls encoding.
- [ethstore](https://github.com/paritytech/parity-ethereum/blob/master/ethstore/) - Parity Ethereum key management.
- [ethkey](https://github.com/paritytech/parity-ethereum/blob/master/ethkey/) - Parity Ethereum keys generator.
- [whisper](https://github.com/paritytech/parity-ethereum/blob/master/whisper/) - Implementation of Whisper-v2 PoC.
- [ethstore](https://github.com/paritytech/parity-ethereum/blob/master/accounts/ethstore) - Parity Ethereum key management.
- [ethkey](https://github.com/paritytech/parity-ethereum/blob/master/accounts/ethkey) - Parity Ethereum keys generator.

View File

@@ -1,18 +1,20 @@
[package]
description = "Parity Ethereum Key Management CLI"
name = "ethstore-cli"
version = "0.1.0"
version = "0.1.1"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
docopt = "0.8"
docopt = "1.0"
env_logger = "0.5"
num_cpus = "1.6"
rustc-hex = "1.0"
serde = "1.0"
serde_derive = "1.0"
parking_lot = "0.6"
parking_lot = "0.7"
ethstore = { path = "../" }
dir = { path = '../../util/dir' }
panic_hook = { path = "../../util/panic_hook" }
dir = { path = '../../../util/dir' }
panic_hook = { path = "../../../util/panic-hook" }
[[bin]]
name = "ethstore"

View File

@@ -0,0 +1,66 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use parking_lot::Mutex;
use std::{cmp, collections::VecDeque, sync::Arc, thread};
use ethstore::{ethkey::Password, Error, PresaleWallet};
use num_cpus;
pub fn run(passwords: VecDeque<Password>, wallet_path: &str) -> Result<(), Error> {
let passwords = Arc::new(Mutex::new(passwords));
let mut handles = Vec::new();
for _ in 0..num_cpus::get() {
let passwords = passwords.clone();
let wallet = PresaleWallet::open(&wallet_path)?;
handles.push(thread::spawn(move || {
look_for_password(passwords, wallet);
}));
}
for handle in handles {
handle
.join()
.map_err(|err| Error::Custom(format!("Error finishing thread: {:?}", err)))?;
}
Ok(())
}
fn look_for_password(passwords: Arc<Mutex<VecDeque<Password>>>, wallet: PresaleWallet) {
let mut counter = 0;
while !passwords.lock().is_empty() {
let package = {
let mut passwords = passwords.lock();
let len = passwords.len();
passwords.split_off(cmp::min(len, 32))
};
for pass in package {
counter += 1;
match wallet.decrypt(&pass) {
Ok(_) => {
println!("Found password: {}", pass.as_str());
passwords.lock().clear();
return;
}
_ if counter % 100 == 0 => print!("."),
_ => {}
}
}
}
}

View File

@@ -0,0 +1,363 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
extern crate dir;
extern crate docopt;
extern crate ethstore;
extern crate num_cpus;
extern crate panic_hook;
extern crate parking_lot;
extern crate rustc_hex;
extern crate serde;
extern crate env_logger;
#[macro_use]
extern crate serde_derive;
use std::{collections::VecDeque, env, fmt, fs, io::Read, process};
use docopt::Docopt;
use ethstore::{
accounts_dir::{KeyDirectory, RootDiskDirectory},
ethkey::{Address, Password},
import_accounts, EthStore, PresaleWallet, SecretStore, SecretVaultRef, SimpleSecretStore,
StoreAccountRef,
};
mod crack;
pub const USAGE: &'static str = r#"
Parity Ethereum key management tool.
Copyright 2015-2019 Parity Technologies (UK) Ltd.
Usage:
ethstore insert <secret> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore change-pwd <address> <old-pwd> <new-pwd> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore list [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore import [<password>] [--src DIR] [--dir DIR]
ethstore import-wallet <path> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore find-wallet-pass <path> <password>
ethstore remove <address> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore sign <address> <password> <message> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore public <address> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore list-vaults [--dir DIR]
ethstore create-vault <vault> <password> [--dir DIR]
ethstore change-vault-pwd <vault> <old-pwd> <new-pwd> [--dir DIR]
ethstore move-to-vault <address> <vault> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore move-from-vault <address> <vault> <password> [--dir DIR]
ethstore [-h | --help]
Options:
-h, --help Display this message and exit.
--dir DIR Specify the secret store directory. It may be either
parity, parity-(chain), geth, geth-test
or a path [default: parity].
--vault VAULT Specify vault to use in this operation.
--vault-pwd VAULTPWD Specify vault password to use in this operation. Please note
that this option is required when vault option is set.
Otherwise it is ignored.
--src DIR Specify import source. It may be either
parity, parity-(chain), geth, geth-test
or a path [default: geth].
Commands:
insert Save account with password.
change-pwd Change password.
list List accounts.
import Import accounts from src.
import-wallet Import presale wallet.
find-wallet-pass Tries to open a wallet with list of passwords given.
remove Remove account.
sign Sign message.
public Displays public key for an address.
list-vaults List vaults.
create-vault Create new vault.
change-vault-pwd Change vault password.
move-to-vault Move account to vault from another vault/root directory.
move-from-vault Move account to root directory from given vault.
"#;
#[derive(Debug, Deserialize)]
struct Args {
cmd_insert: bool,
cmd_change_pwd: bool,
cmd_list: bool,
cmd_import: bool,
cmd_import_wallet: bool,
cmd_find_wallet_pass: bool,
cmd_remove: bool,
cmd_sign: bool,
cmd_public: bool,
cmd_list_vaults: bool,
cmd_create_vault: bool,
cmd_change_vault_pwd: bool,
cmd_move_to_vault: bool,
cmd_move_from_vault: bool,
arg_secret: String,
arg_password: String,
arg_old_pwd: String,
arg_new_pwd: String,
arg_address: String,
arg_message: String,
arg_path: String,
arg_vault: String,
flag_src: String,
flag_dir: String,
flag_vault: String,
flag_vault_pwd: String,
}
enum Error {
Ethstore(ethstore::Error),
Docopt(docopt::Error),
}
impl From<ethstore::Error> for Error {
fn from(err: ethstore::Error) -> Self {
Error::Ethstore(err)
}
}
impl From<docopt::Error> for Error {
fn from(err: docopt::Error) -> Self {
Error::Docopt(err)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::Ethstore(ref err) => fmt::Display::fmt(err, f),
Error::Docopt(ref err) => fmt::Display::fmt(err, f),
}
}
}
fn main() {
panic_hook::set_abort();
if env::var("RUST_LOG").is_err() {
env::set_var("RUST_LOG", "warn")
}
env_logger::try_init().expect("Logger initialized only once.");
match execute(env::args()) {
Ok(result) => println!("{}", result),
Err(Error::Docopt(ref e)) => e.exit(),
Err(err) => {
eprintln!("{}", err);
process::exit(1);
}
}
}
fn key_dir(location: &str, password: Option<Password>) -> Result<Box<dyn KeyDirectory>, Error> {
let dir: RootDiskDirectory = match location {
path if path.starts_with("parity") => {
let chain = path.split('-').nth(1).unwrap_or("ethereum");
let mut path = dir::default_data_pathbuf();
path.push("keys");
path.push(chain);
RootDiskDirectory::create(path)?
}
path => RootDiskDirectory::create(path)?,
};
Ok(Box::new(dir.with_password(password)))
}
fn open_args_vault(store: &EthStore, args: &Args) -> Result<SecretVaultRef, Error> {
if args.flag_vault.is_empty() {
return Ok(SecretVaultRef::Root);
}
let vault_pwd = load_password(&args.flag_vault_pwd)?;
store.open_vault(&args.flag_vault, &vault_pwd)?;
Ok(SecretVaultRef::Vault(args.flag_vault.clone()))
}
fn open_args_vault_account(
store: &EthStore,
address: Address,
args: &Args,
) -> Result<StoreAccountRef, Error> {
match open_args_vault(store, args)? {
SecretVaultRef::Root => Ok(StoreAccountRef::root(address)),
SecretVaultRef::Vault(name) => Ok(StoreAccountRef::vault(&name, address)),
}
}
fn format_accounts(accounts: &[Address]) -> String {
accounts
.iter()
.enumerate()
.map(|(i, a)| format!("{:2}: 0x{:x}", i, a))
.collect::<Vec<String>>()
.join("\n")
}
fn format_vaults(vaults: &[String]) -> String {
vaults.join("\n")
}
fn load_password(path: &str) -> Result<Password, Error> {
let mut file = fs::File::open(path).map_err(|e| {
ethstore::Error::Custom(format!("Error opening password file '{}': {}", path, e))
})?;
let mut password = String::new();
file.read_to_string(&mut password).map_err(|e| {
ethstore::Error::Custom(format!("Error reading password file '{}': {}", path, e))
})?;
// drop EOF
let _ = password.pop();
Ok(password.into())
}
fn execute<S, I>(command: I) -> Result<String, Error>
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
let args: Args = Docopt::new(USAGE).and_then(|d| d.argv(command).deserialize())?;
let store = EthStore::open(key_dir(&args.flag_dir, None)?)?;
return if args.cmd_insert {
let secret = args
.arg_secret
.parse()
.map_err(|_| ethstore::Error::InvalidSecret)?;
let password = load_password(&args.arg_password)?;
let vault_ref = open_args_vault(&store, &args)?;
let account_ref = store.insert_account(vault_ref, secret, &password)?;
Ok(format!("0x{:x}", account_ref.address))
} else if args.cmd_change_pwd {
let address = args
.arg_address
.parse()
.map_err(|_| ethstore::Error::InvalidAccount)?;
let old_pwd = load_password(&args.arg_old_pwd)?;
let new_pwd = load_password(&args.arg_new_pwd)?;
let account_ref = open_args_vault_account(&store, address, &args)?;
let ok = store
.change_password(&account_ref, &old_pwd, &new_pwd)
.is_ok();
Ok(format!("{}", ok))
} else if args.cmd_list {
let vault_ref = open_args_vault(&store, &args)?;
let accounts = store.accounts()?;
let accounts: Vec<_> = accounts
.into_iter()
.filter(|a| &a.vault == &vault_ref)
.map(|a| a.address)
.collect();
Ok(format_accounts(&accounts))
} else if args.cmd_import {
let password = match args.arg_password.as_ref() {
"" => None,
_ => Some(load_password(&args.arg_password)?),
};
let src = key_dir(&args.flag_src, password)?;
let dst = key_dir(&args.flag_dir, None)?;
let accounts = import_accounts(&*src, &*dst)?;
Ok(format_accounts(&accounts))
} else if args.cmd_import_wallet {
let wallet = PresaleWallet::open(&args.arg_path)?;
let password = load_password(&args.arg_password)?;
let kp = wallet.decrypt(&password)?;
let vault_ref = open_args_vault(&store, &args)?;
let account_ref = store.insert_account(vault_ref, kp.secret().clone(), &password)?;
Ok(format!("0x{:x}", account_ref.address))
} else if args.cmd_find_wallet_pass {
let passwords = load_password(&args.arg_password)?;
let passwords = passwords
.as_str()
.lines()
.map(|line| str::to_owned(line).into())
.collect::<VecDeque<_>>();
crack::run(passwords, &args.arg_path)?;
Ok(format!("Password not found."))
} else if args.cmd_remove {
let address = args
.arg_address
.parse()
.map_err(|_| ethstore::Error::InvalidAccount)?;
let password = load_password(&args.arg_password)?;
let account_ref = open_args_vault_account(&store, address, &args)?;
let ok = store.remove_account(&account_ref, &password).is_ok();
Ok(format!("{}", ok))
} else if args.cmd_sign {
let address = args
.arg_address
.parse()
.map_err(|_| ethstore::Error::InvalidAccount)?;
let message = args
.arg_message
.parse()
.map_err(|_| ethstore::Error::InvalidMessage)?;
let password = load_password(&args.arg_password)?;
let account_ref = open_args_vault_account(&store, address, &args)?;
let signature = store.sign(&account_ref, &password, &message)?;
Ok(format!("0x{}", signature))
} else if args.cmd_public {
let address = args
.arg_address
.parse()
.map_err(|_| ethstore::Error::InvalidAccount)?;
let password = load_password(&args.arg_password)?;
let account_ref = open_args_vault_account(&store, address, &args)?;
let public = store.public(&account_ref, &password)?;
Ok(format!("0x{:x}", public))
} else if args.cmd_list_vaults {
let vaults = store.list_vaults()?;
Ok(format_vaults(&vaults))
} else if args.cmd_create_vault {
let password = load_password(&args.arg_password)?;
store.create_vault(&args.arg_vault, &password)?;
Ok("OK".to_owned())
} else if args.cmd_change_vault_pwd {
let old_pwd = load_password(&args.arg_old_pwd)?;
let new_pwd = load_password(&args.arg_new_pwd)?;
store.open_vault(&args.arg_vault, &old_pwd)?;
store.change_vault_password(&args.arg_vault, &new_pwd)?;
Ok("OK".to_owned())
} else if args.cmd_move_to_vault {
let address = args
.arg_address
.parse()
.map_err(|_| ethstore::Error::InvalidAccount)?;
let password = load_password(&args.arg_password)?;
let account_ref = open_args_vault_account(&store, address, &args)?;
store.open_vault(&args.arg_vault, &password)?;
store.change_account_vault(SecretVaultRef::Vault(args.arg_vault), account_ref)?;
Ok("OK".to_owned())
} else if args.cmd_move_from_vault {
let address = args
.arg_address
.parse()
.map_err(|_| ethstore::Error::InvalidAccount)?;
let password = load_password(&args.arg_password)?;
store.open_vault(&args.arg_vault, &password)?;
store.change_account_vault(
SecretVaultRef::Root,
StoreAccountRef::vault(&args.arg_vault, address),
)?;
Ok("OK".to_owned())
} else {
Ok(format!("{}", USAGE))
};
}

View File

@@ -0,0 +1,57 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use json;
#[derive(Debug, PartialEq, Clone)]
pub struct Aes128Ctr {
pub iv: [u8; 16],
}
#[derive(Debug, PartialEq, Clone)]
pub enum Cipher {
Aes128Ctr(Aes128Ctr),
}
impl From<json::Aes128Ctr> for Aes128Ctr {
fn from(json: json::Aes128Ctr) -> Self {
Aes128Ctr { iv: json.iv.into() }
}
}
impl Into<json::Aes128Ctr> for Aes128Ctr {
fn into(self) -> json::Aes128Ctr {
json::Aes128Ctr {
iv: From::from(self.iv),
}
}
}
impl From<json::Cipher> for Cipher {
fn from(json: json::Cipher) -> Self {
match json {
json::Cipher::Aes128Ctr(params) => Cipher::Aes128Ctr(From::from(params)),
}
}
}
impl Into<json::Cipher> for Cipher {
fn into(self) -> json::Cipher {
match self {
Cipher::Aes128Ctr(params) => json::Cipher::Aes128Ctr(params.into()),
}
}
}

View File

@@ -0,0 +1,234 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use account::{Aes128Ctr, Cipher, Kdf, Pbkdf2, Prf};
use crypto::{self, Keccak256};
use ethkey::{Password, Secret};
use json;
use random::Random;
use smallvec::SmallVec;
use std::{num::NonZeroU32, str};
use Error;
/// Encrypted data
#[derive(Debug, PartialEq, Clone)]
pub struct Crypto {
/// Encryption parameters
pub cipher: Cipher,
/// Encrypted data buffer
pub ciphertext: Vec<u8>,
/// Key derivation function parameters
pub kdf: Kdf,
/// Message authentication code
pub mac: [u8; 32],
}
impl From<json::Crypto> for Crypto {
fn from(json: json::Crypto) -> Self {
Crypto {
cipher: json.cipher.into(),
ciphertext: json.ciphertext.into(),
kdf: json.kdf.into(),
mac: json.mac.into(),
}
}
}
impl From<Crypto> for json::Crypto {
fn from(c: Crypto) -> Self {
json::Crypto {
cipher: c.cipher.into(),
ciphertext: c.ciphertext.into(),
kdf: c.kdf.into(),
mac: c.mac.into(),
}
}
}
impl str::FromStr for Crypto {
type Err = <json::Crypto as str::FromStr>::Err;
fn from_str(s: &str) -> Result<Self, Self::Err> {
s.parse::<json::Crypto>().map(Into::into)
}
}
impl From<Crypto> for String {
fn from(c: Crypto) -> Self {
json::Crypto::from(c).into()
}
}
impl Crypto {
/// Encrypt account secret
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: NonZeroU32,
) -> Result<Self, crypto::Error> {
let salt: [u8; 32] = Random::random();
let iv: [u8; 16] = Random::random();
// two parts of derived key
// DK = [ DK[0..15] DK[16..31] ] = [derived_left_bits, derived_right_bits]
let (derived_left_bits, derived_right_bits) =
crypto::derive_key_iterations(password.as_bytes(), &salt, iterations);
// preallocated (on-stack in case of `Secret`) buffer to hold cipher
// length = length(plain) as we are using CTR-approach
let plain_len = plain.len();
let mut ciphertext: SmallVec<[u8; 32]> = SmallVec::from_vec(vec![0; plain_len]);
// aes-128-ctr with initial vector of iv
crypto::aes::encrypt_128_ctr(&derived_left_bits, &iv, plain, &mut *ciphertext)?;
// KECCAK(DK[16..31] ++ <ciphertext>), where DK[16..31] - derived_right_bits
let mac = crypto::derive_mac(&derived_right_bits, &*ciphertext).keccak256();
Ok(Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr { iv: iv }),
ciphertext: ciphertext.into_vec(),
kdf: Kdf::Pbkdf2(Pbkdf2 {
dklen: crypto::KEY_LENGTH as u32,
salt: salt.to_vec(),
c: iterations,
prf: Prf::HmacSha256,
}),
mac: mac,
})
}
/// Try to decrypt and convert result to account secret
pub fn secret(&self, password: &Password) -> Result<Secret, Error> {
if self.ciphertext.len() > 32 {
return Err(Error::InvalidSecret);
}
let secret = self.do_decrypt(password, 32)?;
Ok(Secret::from_unsafe_slice(&secret)?)
}
/// Try to decrypt and return result as is
pub fn decrypt(&self, password: &Password) -> Result<Vec<u8>, Error> {
let expected_len = self.ciphertext.len();
self.do_decrypt(password, expected_len)
}
fn do_decrypt(&self, password: &Password, expected_len: usize) -> Result<Vec<u8>, Error> {
let (derived_left_bits, derived_right_bits) = match self.kdf {
Kdf::Pbkdf2(ref params) => {
crypto::derive_key_iterations(password.as_bytes(), &params.salt, params.c)
}
Kdf::Scrypt(ref params) => crypto::scrypt::derive_key(
password.as_bytes(),
&params.salt,
params.n,
params.p,
params.r,
)?,
};
let mac = crypto::derive_mac(&derived_right_bits, &self.ciphertext).keccak256();
if !crypto::is_equal(&mac, &self.mac) {
return Err(Error::InvalidPassword);
}
let mut plain: SmallVec<[u8; 32]> = SmallVec::from_vec(vec![0; expected_len]);
match self.cipher {
Cipher::Aes128Ctr(ref params) => {
// checker by callers
debug_assert!(expected_len >= self.ciphertext.len());
let from = expected_len - self.ciphertext.len();
crypto::aes::decrypt_128_ctr(
&derived_left_bits,
&params.iv,
&self.ciphertext,
&mut plain[from..],
)?;
Ok(plain.into_iter().collect())
}
}
}
}
#[cfg(test)]
mod tests {
use super::{Crypto, Error, NonZeroU32};
use ethkey::{Generator, Random};
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, *ITERATIONS).unwrap();
let secret = crypto.secret(&passwd).unwrap();
assert_eq!(keypair.secret(), &secret);
}
#[test]
fn crypto_with_secret_invalid_password() {
let keypair = Random.generate().unwrap();
let crypto =
Crypto::with_secret(keypair.secret(), &"this is sparta".into(), *ITERATIONS).unwrap();
assert_matches!(
crypto.secret(&"this is sparta!".into()),
Err(Error::InvalidPassword)
)
}
#[test]
fn crypto_with_null_plain_data() {
let original_data = b"";
let passwd = "this is sparta".into();
let crypto = Crypto::with_plain(&original_data[..], &passwd, *ITERATIONS).unwrap();
let decrypted_data = crypto.decrypt(&passwd).unwrap();
assert_eq!(original_data[..], *decrypted_data);
}
#[test]
fn crypto_with_tiny_plain_data() {
let original_data = b"{}";
let passwd = "this is sparta".into();
let crypto = Crypto::with_plain(&original_data[..], &passwd, *ITERATIONS).unwrap();
let decrypted_data = crypto.decrypt(&passwd).unwrap();
assert_eq!(original_data[..], *decrypted_data);
}
#[test]
fn crypto_with_huge_plain_data() {
let original_data: Vec<_> = (1..65536).map(|i| (i % 256) as u8).collect();
let passwd = "this is sparta".into();
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

@@ -0,0 +1,126 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use json;
use std::num::NonZeroU32;
#[derive(Debug, PartialEq, Clone)]
pub enum Prf {
HmacSha256,
}
#[derive(Debug, PartialEq, Clone)]
pub struct Pbkdf2 {
pub c: NonZeroU32,
pub dklen: u32,
pub prf: Prf,
pub salt: Vec<u8>,
}
#[derive(Debug, PartialEq, Clone)]
pub struct Scrypt {
pub dklen: u32,
pub p: u32,
pub n: u32,
pub r: u32,
pub salt: Vec<u8>,
}
#[derive(Debug, PartialEq, Clone)]
pub enum Kdf {
Pbkdf2(Pbkdf2),
Scrypt(Scrypt),
}
impl From<json::Prf> for Prf {
fn from(json: json::Prf) -> Self {
match json {
json::Prf::HmacSha256 => Prf::HmacSha256,
}
}
}
impl Into<json::Prf> for Prf {
fn into(self) -> json::Prf {
match self {
Prf::HmacSha256 => json::Prf::HmacSha256,
}
}
}
impl From<json::Pbkdf2> for Pbkdf2 {
fn from(json: json::Pbkdf2) -> Self {
Pbkdf2 {
c: json.c,
dklen: json.dklen,
prf: From::from(json.prf),
salt: json.salt.into(),
}
}
}
impl Into<json::Pbkdf2> for Pbkdf2 {
fn into(self) -> json::Pbkdf2 {
json::Pbkdf2 {
c: self.c,
dklen: self.dklen,
prf: self.prf.into(),
salt: From::from(self.salt),
}
}
}
impl From<json::Scrypt> for Scrypt {
fn from(json: json::Scrypt) -> Self {
Scrypt {
dklen: json.dklen,
p: json.p,
n: json.n,
r: json.r,
salt: json.salt.into(),
}
}
}
impl Into<json::Scrypt> for Scrypt {
fn into(self) -> json::Scrypt {
json::Scrypt {
dklen: self.dklen,
p: self.p,
n: self.n,
r: self.r,
salt: From::from(self.salt),
}
}
}
impl From<json::Kdf> for Kdf {
fn from(json: json::Kdf) -> Self {
match json {
json::Kdf::Pbkdf2(params) => Kdf::Pbkdf2(From::from(params)),
json::Kdf::Scrypt(params) => Kdf::Scrypt(From::from(params)),
}
}
}
impl Into<json::Kdf> for Kdf {
fn into(self) -> json::Kdf {
match self {
Kdf::Pbkdf2(params) => json::Kdf::Pbkdf2(params.into()),
Kdf::Scrypt(params) => json::Kdf::Scrypt(params.into()),
}
}
}

View File

@@ -1,18 +1,18 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// Parity is free software: you can redistribute it and/or modify
// OpenEthereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// OpenEthereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
mod cipher;
mod crypto;
@@ -20,8 +20,10 @@ mod kdf;
mod safe_account;
mod version;
pub use self::cipher::{Cipher, Aes128Ctr};
pub use self::crypto::Crypto;
pub use self::kdf::{Kdf, Pbkdf2, Scrypt, Prf};
pub use self::safe_account::SafeAccount;
pub use self::version::Version;
pub use self::{
cipher::{Aes128Ctr, Cipher},
crypto::Crypto,
kdf::{Kdf, Pbkdf2, Prf, Scrypt},
safe_account::SafeAccount,
version::Version,
};

View File

@@ -0,0 +1,286 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::crypto::Crypto;
use account::Version;
use crypto;
use ethkey::{
self, crypto::ecdh::agree, sign, Address, KeyPair, Message, Password, Public, Secret, Signature,
};
use json;
use std::num::NonZeroU32;
use Error;
/// Account representation.
#[derive(Debug, PartialEq, Clone)]
pub struct SafeAccount {
/// Account ID
pub id: [u8; 16],
/// Account version
pub version: Version,
/// Account address
pub address: Address,
/// Account private key derivation definition.
pub crypto: Crypto,
/// Account filename
pub filename: Option<String>,
/// Account name
pub name: String,
/// Account metadata
pub meta: String,
}
impl Into<json::KeyFile> for SafeAccount {
fn into(self) -> json::KeyFile {
json::KeyFile {
id: From::from(self.id),
version: self.version.into(),
address: Some(self.address.into()),
crypto: self.crypto.into(),
name: Some(self.name.into()),
meta: Some(self.meta.into()),
}
}
}
impl SafeAccount {
/// Create a new account
pub fn create(
keypair: &KeyPair,
id: [u8; 16],
password: &Password,
iterations: NonZeroU32,
name: String,
meta: String,
) -> Result<Self, crypto::Error> {
Ok(SafeAccount {
id: id,
version: Version::V3,
crypto: Crypto::with_secret(keypair.secret(), password, iterations)?,
address: keypair.address(),
filename: None,
name: name,
meta: meta,
})
}
/// Create a new `SafeAccount` from the given `json`; if it was read from a
/// file, the `filename` should be `Some` name. If it is as yet anonymous, then it
/// can be left `None`.
/// In case `password` is provided, we will attempt to read the secret from the keyfile
/// and derive the address from it instead of reading it directly.
/// Providing password is required for `json::KeyFile`s with no address.
pub fn from_file(
json: json::KeyFile,
filename: Option<String>,
password: &Option<Password>,
) -> Result<Self, Error> {
let crypto = Crypto::from(json.crypto);
let address = match (password, &json.address) {
(None, Some(json_address)) => json_address.into(),
(None, None) => Err(Error::Custom(
"This keystore does not contain address. You need to provide password to import it"
.into(),
))?,
(Some(password), json_address) => {
let derived_address = KeyPair::from_secret(
crypto
.secret(&password)
.map_err(|_| Error::InvalidPassword)?,
)?
.address();
match json_address {
Some(json_address) => {
let json_address = json_address.into();
if derived_address != json_address {
warn!("Detected address mismatch when opening an account. Derived: {:?}, in json got: {:?}",
derived_address, json_address);
}
}
_ => {}
}
derived_address
}
};
Ok(SafeAccount {
id: json.id.into(),
version: json.version.into(),
address,
crypto,
filename,
name: json.name.unwrap_or(String::new()),
meta: json.meta.unwrap_or("{}".to_owned()),
})
}
/// Create a new `SafeAccount` from the given vault `json`; if it was read from a
/// file, the `filename` should be `Some` name. If it is as yet anonymous, then it
/// can be left `None`.
pub fn from_vault_file(
password: &Password,
json: json::VaultKeyFile,
filename: Option<String>,
) -> Result<Self, Error> {
let meta_crypto: Crypto = json.metacrypto.into();
let meta_plain = meta_crypto.decrypt(password)?;
let meta_plain =
json::VaultKeyMeta::load(&meta_plain).map_err(|e| Error::Custom(format!("{:?}", e)))?;
SafeAccount::from_file(
json::KeyFile {
id: json.id,
version: json.version,
crypto: json.crypto,
address: Some(meta_plain.address),
name: meta_plain.name,
meta: meta_plain.meta,
},
filename,
&None,
)
}
/// Create a new `VaultKeyFile` from the given `self`
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),
meta: Some(self.meta),
};
let meta_plain = meta_plain
.write()
.map_err(|e| Error::Custom(format!("{:?}", e)))?;
let meta_crypto = Crypto::with_plain(&meta_plain, password, iterations)?;
Ok(json::VaultKeyFile {
id: self.id.into(),
version: self.version.into(),
crypto: self.crypto.into(),
metacrypto: meta_crypto.into(),
})
}
/// Sign a message.
pub fn sign(&self, password: &Password, message: &Message) -> Result<Signature, Error> {
let secret = self.crypto.secret(password)?;
sign(&secret, message).map_err(From::from)
}
/// Decrypt a message.
pub fn decrypt(
&self,
password: &Password,
shared_mac: &[u8],
message: &[u8],
) -> Result<Vec<u8>, Error> {
let secret = self.crypto.secret(password)?;
ethkey::crypto::ecies::decrypt(&secret, shared_mac, message).map_err(From::from)
}
/// Agree on shared key.
pub fn agree(&self, password: &Password, other: &Public) -> Result<Secret, Error> {
let secret = self.crypto.secret(password)?;
agree(&secret, other).map_err(From::from)
}
/// Derive public key.
pub fn public(&self, password: &Password) -> Result<Public, Error> {
let secret = self.crypto.secret(password)?;
Ok(KeyPair::from_secret(secret)?.public().clone())
}
/// Change account's password.
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(),
version: self.version.clone(),
crypto: Crypto::with_secret(&secret, new_password, iterations)?,
address: self.address.clone(),
filename: self.filename.clone(),
name: self.name.clone(),
meta: self.meta.clone(),
};
Ok(result)
}
/// Check if password matches the account.
pub fn check_password(&self, password: &Password) -> bool {
self.crypto.secret(password).is_ok()
}
}
#[cfg(test)]
mod tests {
use super::{NonZeroU32, SafeAccount};
use ethkey::{verify_public, Generator, Message, Random};
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,
*ITERATIONS,
"Test".to_owned(),
"{}".to_owned(),
);
let signature = account.unwrap().sign(&password, &message).unwrap();
assert!(verify_public(keypair.public(), &signature, &message).unwrap());
}
#[test]
fn change_password() {
let keypair = Random.generate().unwrap();
let first_password = "hello world".into();
let sec_password = "this is sparta".into();
let message = Message::default();
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());
assert!(new_account.sign(&sec_password, &message).is_ok());
}
}

View File

@@ -1,38 +1,38 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// Parity is free software: you can redistribute it and/or modify
// OpenEthereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// OpenEthereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use json;
#[derive(Debug, PartialEq, Clone)]
pub enum Version {
V3,
V3,
}
impl From<json::Version> for Version {
fn from(json: json::Version) -> Self {
match json {
json::Version::V3 => Version::V3,
}
}
fn from(json: json::Version) -> Self {
match json {
json::Version::V3 => Version::V3,
}
}
}
impl Into<json::Version> for Version {
fn into(self) -> json::Version {
match self {
Version::V3 => json::Version::V3,
}
}
fn into(self) -> json::Version {
match self {
Version::V3 => json::Version::V3,
}
}
}

View File

@@ -0,0 +1,608 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::{
vault::{VaultDiskDirectory, VAULT_FILE_NAME},
KeyDirectory, VaultKey, VaultKeyDirectory, VaultKeyDirectoryProvider,
};
use ethkey::Password;
use json::{self, Uuid};
use std::{
collections::HashMap,
fs, io,
io::Write,
path::{Path, PathBuf},
};
use time;
use Error;
use SafeAccount;
const IGNORED_FILES: &'static [&'static str] = &[
"thumbs.db",
"address_book.json",
"dapps_policy.json",
"dapps_accounts.json",
"dapps_history.json",
"vault.json",
];
/// Find a unique filename that does not exist using four-letter random suffix.
pub fn find_unique_filename_using_random_suffix(
parent_path: &Path,
original_filename: &str,
) -> io::Result<String> {
let mut path = parent_path.join(original_filename);
let mut deduped_filename = original_filename.to_string();
if path.exists() {
const MAX_RETRIES: usize = 500;
let mut retries = 0;
while path.exists() {
if retries >= MAX_RETRIES {
return Err(io::Error::new(
io::ErrorKind::Other,
"Exceeded maximum retries when deduplicating filename.",
));
}
let suffix = ::random::random_string(4);
deduped_filename = format!("{}-{}", original_filename, suffix);
path.set_file_name(&deduped_filename);
retries += 1;
}
}
Ok(deduped_filename)
}
/// 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 std::os::unix::fs::OpenOptionsExt;
fs::OpenOptions::new()
.write(true)
.create_new(true)
.mode((libc::S_IWUSR | libc::S_IRUSR) as u32)
.open(file_path)
}
/// Create a new file and restrict permissions to owner only. It errors if the file already exists.
#[cfg(not(unix))]
pub fn create_new_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
fs::OpenOptions::new()
.write(true)
.create_new(true)
.open(file_path)
}
/// Create a new file and restrict permissions to owner only. It replaces the existing file if it already exists.
#[cfg(unix)]
pub fn replace_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
use std::os::unix::fs::PermissionsExt;
let file = fs::File::create(file_path)?;
let mut permissions = file.metadata()?.permissions();
permissions.set_mode((libc::S_IWUSR | libc::S_IRUSR) as u32);
file.set_permissions(permissions)?;
Ok(file)
}
/// Create a new file and restrict permissions to owner only. It replaces the existing file if it already exists.
#[cfg(not(unix))]
pub fn replace_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
fs::File::create(file_path)
}
/// Root keys directory implementation
pub type RootDiskDirectory = DiskDirectory<DiskKeyFileManager>;
/// Disk directory key file manager
pub trait KeyFileManager: Send + Sync {
/// Read `SafeAccount` from given key file stream
fn read<T>(&self, filename: Option<String>, reader: T) -> Result<SafeAccount, Error>
where
T: io::Read;
/// Write `SafeAccount` to given key file stream
fn write<T>(&self, account: SafeAccount, writer: &mut T) -> Result<(), Error>
where
T: io::Write;
}
/// Disk-based keys directory implementation
pub struct DiskDirectory<T>
where
T: KeyFileManager,
{
path: PathBuf,
key_manager: T,
}
/// Keys file manager for root keys directory
#[derive(Default)]
pub struct DiskKeyFileManager {
password: Option<Password>,
}
impl RootDiskDirectory {
pub fn create<P>(path: P) -> Result<Self, Error>
where
P: AsRef<Path>,
{
fs::create_dir_all(&path)?;
Ok(Self::at(path))
}
/// allows to read keyfiles with given password (needed for keyfiles w/o address)
pub fn with_password(&self, password: Option<Password>) -> Self {
DiskDirectory::new(&self.path, DiskKeyFileManager { password })
}
pub fn at<P>(path: P) -> Self
where
P: AsRef<Path>,
{
DiskDirectory::new(path, DiskKeyFileManager::default())
}
}
impl<T> DiskDirectory<T>
where
T: KeyFileManager,
{
/// Create new disk directory instance
pub fn new<P>(path: P, key_manager: T) -> Self
where
P: AsRef<Path>,
{
DiskDirectory {
path: path.as_ref().to_path_buf(),
key_manager: key_manager,
}
}
fn files(&self) -> Result<Vec<PathBuf>, Error> {
Ok(fs::read_dir(&self.path)?
.flat_map(Result::ok)
.filter(|entry| {
let metadata = entry.metadata().ok();
let file_name = entry.file_name();
let name = file_name.to_string_lossy();
// filter directories
metadata.map_or(false, |m| !m.is_dir()) &&
// hidden files
!name.starts_with(".") &&
// other ignored files
!IGNORED_FILES.contains(&&*name)
})
.map(|entry| entry.path())
.collect::<Vec<PathBuf>>())
}
pub fn files_hash(&self) -> Result<u64, Error> {
use std::{collections::hash_map::DefaultHasher, hash::Hasher};
let mut hasher = DefaultHasher::new();
let files = self.files()?;
for file in files {
hasher.write(file.to_str().unwrap_or("").as_bytes())
}
Ok(hasher.finish())
}
fn last_modification_date(&self) -> Result<u64, Error> {
use std::time::{Duration, UNIX_EPOCH};
let duration = fs::metadata(&self.path)?
.modified()?
.duration_since(UNIX_EPOCH)
.unwrap_or(Duration::default());
let timestamp = duration.as_secs() ^ (duration.subsec_nanos() as u64);
Ok(timestamp)
}
/// all accounts found in keys directory
fn files_content(&self) -> Result<HashMap<PathBuf, SafeAccount>, Error> {
// it's not done using one iterator cause
// there is an issue with rustc and it takes tooo much time to compile
let paths = self.files()?;
Ok(paths
.into_iter()
.filter_map(|path| {
let filename = Some(
path.file_name()
.and_then(|n| n.to_str())
.expect("Keys have valid UTF8 names only.")
.to_owned(),
);
fs::File::open(path.clone())
.map_err(Into::into)
.and_then(|file| self.key_manager.read(filename, file))
.map_err(|err| {
warn!("Invalid key file: {:?} ({})", path, err);
err
})
.map(|account| (path, account))
.ok()
})
.collect())
}
/// insert account with given filename. if the filename is a duplicate of any stored account and dedup is set to
/// true, a random suffix is appended to the filename.
pub fn insert_with_filename(
&self,
account: SafeAccount,
mut filename: String,
dedup: bool,
) -> Result<SafeAccount, Error> {
if dedup {
filename = find_unique_filename_using_random_suffix(&self.path, &filename)?;
}
// path to keyfile
let keyfile_path = self.path.join(filename.as_str());
// update account filename
let original_account = account.clone();
let mut account = account;
account.filename = Some(filename);
{
// save the file
let mut file = if dedup {
create_new_file_with_permissions_to_owner(&keyfile_path)?
} else {
replace_file_with_permissions_to_owner(&keyfile_path)?
};
// write key content
self.key_manager
.write(original_account, &mut file)
.map_err(|e| Error::Custom(format!("{:?}", e)))?;
file.flush()?;
file.sync_all()?;
}
Ok(account)
}
/// Get key file manager referece
pub fn key_manager(&self) -> &T {
&self.key_manager
}
}
impl<T> KeyDirectory for DiskDirectory<T>
where
T: KeyFileManager,
{
fn load(&self) -> Result<Vec<SafeAccount>, Error> {
let accounts = self
.files_content()?
.into_iter()
.map(|(_, account)| account)
.collect();
Ok(accounts)
}
fn update(&self, account: SafeAccount) -> Result<SafeAccount, Error> {
// Disk store handles updates correctly iff filename is the same
let filename = account_filename(&account);
self.insert_with_filename(account, filename, false)
}
fn insert(&self, account: SafeAccount) -> Result<SafeAccount, Error> {
let filename = account_filename(&account);
self.insert_with_filename(account, filename, true)
}
fn remove(&self, account: &SafeAccount) -> Result<(), Error> {
// enumerate all entries in keystore
// and find entry with given address
let to_remove = self
.files_content()?
.into_iter()
.find(|&(_, ref acc)| acc.id == account.id && acc.address == account.address);
// remove it
match to_remove {
None => Err(Error::InvalidAccount),
Some((path, _)) => fs::remove_file(path).map_err(From::from),
}
}
fn path(&self) -> Option<&PathBuf> {
Some(&self.path)
}
fn as_vault_provider(&self) -> Option<&dyn VaultKeyDirectoryProvider> {
Some(self)
}
fn unique_repr(&self) -> Result<u64, Error> {
self.last_modification_date()
}
}
impl<T> VaultKeyDirectoryProvider for DiskDirectory<T>
where
T: KeyFileManager,
{
fn create(&self, name: &str, key: VaultKey) -> Result<Box<dyn VaultKeyDirectory>, Error> {
let vault_dir = VaultDiskDirectory::create(&self.path, name, key)?;
Ok(Box::new(vault_dir))
}
fn open(&self, name: &str, key: VaultKey) -> Result<Box<dyn VaultKeyDirectory>, Error> {
let vault_dir = VaultDiskDirectory::at(&self.path, name, key)?;
Ok(Box::new(vault_dir))
}
fn list_vaults(&self) -> Result<Vec<String>, Error> {
Ok(fs::read_dir(&self.path)?
.filter_map(|e| e.ok().map(|e| e.path()))
.filter_map(|path| {
let mut vault_file_path = path.clone();
vault_file_path.push(VAULT_FILE_NAME);
if vault_file_path.is_file() {
path.file_name()
.and_then(|f| f.to_str())
.map(|f| f.to_owned())
} else {
None
}
})
.collect())
}
fn vault_meta(&self, name: &str) -> Result<String, Error> {
VaultDiskDirectory::meta_at(&self.path, name)
}
}
impl KeyFileManager for DiskKeyFileManager {
fn read<T>(&self, filename: Option<String>, reader: T) -> Result<SafeAccount, Error>
where
T: io::Read,
{
let key_file =
json::KeyFile::load(reader).map_err(|e| Error::Custom(format!("{:?}", e)))?;
SafeAccount::from_file(key_file, filename, &self.password)
}
fn write<T>(&self, mut account: SafeAccount, writer: &mut T) -> Result<(), Error>
where
T: io::Write,
{
// when account is moved back to root directory from vault
// => remove vault field from meta
account.meta = json::remove_vault_name_from_json_meta(&account.meta)
.map_err(|err| Error::Custom(format!("{:?}", err)))?;
let key_file: json::KeyFile = account.into();
key_file
.write(writer)
.map_err(|e| Error::Custom(format!("{:?}", e)))
}
}
fn account_filename(account: &SafeAccount) -> String {
// build file path
account.filename.clone().unwrap_or_else(|| {
let timestamp = time::strftime("%Y-%m-%dT%H-%M-%S", &time::now_utc())
.expect("Time-format string is valid.");
format!("UTC--{}Z--{}", timestamp, Uuid::from(account.id))
})
}
#[cfg(test)]
mod test {
extern crate tempdir;
use self::tempdir::TempDir;
use super::{KeyDirectory, RootDiskDirectory, VaultKey};
use account::SafeAccount;
use ethkey::{Generator, Random};
use std::{env, fs, num::NonZeroU32};
lazy_static! {
static ref ITERATIONS: NonZeroU32 = NonZeroU32::new(1024).expect("1024 > 0; qed");
}
#[test]
fn should_create_new_account() {
// given
let mut dir = env::temp_dir();
dir.push("ethstore_should_create_new_account");
let keypair = Random.generate().unwrap();
let password = "hello world".into();
let directory = RootDiskDirectory::create(dir.clone()).unwrap();
// when
let account = SafeAccount::create(
&keypair,
[0u8; 16],
&password,
*ITERATIONS,
"Test".to_owned(),
"{}".to_owned(),
);
let res = directory.insert(account.unwrap());
// then
assert!(res.is_ok(), "Should save account succesfuly.");
assert!(
res.unwrap().filename.is_some(),
"Filename has been assigned."
);
// cleanup
let _ = fs::remove_dir_all(dir);
}
#[test]
fn should_handle_duplicate_filenames() {
// given
let mut dir = env::temp_dir();
dir.push("ethstore_should_handle_duplicate_filenames");
let keypair = Random.generate().unwrap();
let password = "hello world".into();
let directory = RootDiskDirectory::create(dir.clone()).unwrap();
// when
let account = SafeAccount::create(
&keypair,
[0u8; 16],
&password,
*ITERATIONS,
"Test".to_owned(),
"{}".to_owned(),
)
.unwrap();
let filename = "test".to_string();
let dedup = true;
directory
.insert_with_filename(account.clone(), "foo".to_string(), dedup)
.unwrap();
let file1 = directory
.insert_with_filename(account.clone(), filename.clone(), dedup)
.unwrap()
.filename
.unwrap();
let file2 = directory
.insert_with_filename(account.clone(), filename.clone(), dedup)
.unwrap()
.filename
.unwrap();
let file3 = directory
.insert_with_filename(account.clone(), filename.clone(), dedup)
.unwrap()
.filename
.unwrap();
// then
// the first file should have the original names
assert_eq!(file1, filename);
// the following duplicate files should have a suffix appended
assert!(file2 != file3);
assert_eq!(file2.len(), filename.len() + 5);
assert_eq!(file3.len(), filename.len() + 5);
// cleanup
let _ = fs::remove_dir_all(dir);
}
#[test]
fn should_manage_vaults() {
// given
let mut dir = env::temp_dir();
dir.push("should_create_new_vault");
let directory = RootDiskDirectory::create(dir.clone()).unwrap();
let vault_name = "vault";
let password = "password".into();
// then
assert!(directory.as_vault_provider().is_some());
// and when
let before_root_items_count = fs::read_dir(&dir).unwrap().count();
let vault = directory
.as_vault_provider()
.unwrap()
.create(vault_name, VaultKey::new(&password, *ITERATIONS));
// then
assert!(vault.is_ok());
let after_root_items_count = fs::read_dir(&dir).unwrap().count();
assert!(after_root_items_count > before_root_items_count);
// and when
let vault = directory
.as_vault_provider()
.unwrap()
.open(vault_name, VaultKey::new(&password, *ITERATIONS));
// then
assert!(vault.is_ok());
let after_root_items_count2 = fs::read_dir(&dir).unwrap().count();
assert!(after_root_items_count == after_root_items_count2);
// cleanup
let _ = fs::remove_dir_all(dir);
}
#[test]
fn should_list_vaults() {
// given
let temp_path = TempDir::new("").unwrap();
let directory = RootDiskDirectory::create(&temp_path).unwrap();
let vault_provider = directory.as_vault_provider().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();
assert_eq!(vaults.len(), 2);
assert!(vaults.iter().any(|v| &*v == "vault1"));
assert!(vaults.iter().any(|v| &*v == "vault2"));
}
#[test]
fn hash_of_files() {
let temp_path = TempDir::new("").unwrap();
let directory = RootDiskDirectory::create(&temp_path).unwrap();
let hash = directory
.files_hash()
.expect("Files hash should be calculated ok");
assert_eq!(hash, 15130871412783076140);
let keypair = Random.generate().unwrap();
let password = "test pass".into();
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");
assert!(
new_hash != hash,
"hash of the file list should change once directory content changed"
);
}
}

View File

@@ -0,0 +1,77 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use ethkey::Address;
use itertools;
use parking_lot::RwLock;
use std::collections::HashMap;
use super::KeyDirectory;
use Error;
use SafeAccount;
/// Accounts in-memory storage.
#[derive(Default)]
pub struct MemoryDirectory {
accounts: RwLock<HashMap<Address, Vec<SafeAccount>>>,
}
impl KeyDirectory for MemoryDirectory {
fn load(&self) -> Result<Vec<SafeAccount>, Error> {
Ok(itertools::Itertools::flatten(self.accounts.read().values().cloned()).collect())
}
fn update(&self, account: SafeAccount) -> Result<SafeAccount, Error> {
let mut lock = self.accounts.write();
let accounts = lock.entry(account.address.clone()).or_insert_with(Vec::new);
// If the filename is the same we just need to replace the entry
accounts.retain(|acc| acc.filename != account.filename);
accounts.push(account.clone());
Ok(account)
}
fn insert(&self, account: SafeAccount) -> Result<SafeAccount, Error> {
let mut lock = self.accounts.write();
let accounts = lock.entry(account.address.clone()).or_insert_with(Vec::new);
accounts.push(account.clone());
Ok(account)
}
fn remove(&self, account: &SafeAccount) -> Result<(), Error> {
let mut accounts = self.accounts.write();
let is_empty = if let Some(accounts) = accounts.get_mut(&account.address) {
if let Some(position) = accounts.iter().position(|acc| acc == account) {
accounts.remove(position);
}
accounts.is_empty()
} else {
false
};
if is_empty {
accounts.remove(&account.address);
}
Ok(())
}
fn unique_repr(&self) -> Result<u64, Error> {
let mut val = 0u64;
let accounts = self.accounts.read();
for acc in accounts.keys() {
val = val ^ acc.low_u64()
}
Ok(val)
}
}

View File

@@ -0,0 +1,112 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
//! Accounts Directory
use ethkey::Password;
use std::{num::NonZeroU32, path::PathBuf};
use Error;
use SafeAccount;
mod disk;
mod memory;
mod vault;
/// `VaultKeyDirectory::set_key` error
#[derive(Debug)]
pub enum SetKeyError {
/// Error is fatal and directory is probably in inconsistent state
Fatal(Error),
/// Error is non fatal, directory is reverted to pre-operation state
NonFatalOld(Error),
/// Error is non fatal, directory is consistent with new key
NonFatalNew(Error),
}
/// Vault key
#[derive(Clone, PartialEq, Eq)]
pub struct VaultKey {
/// Vault password
pub password: Password,
/// Number of iterations to produce a derived key from password
pub iterations: NonZeroU32,
}
/// Keys directory
pub trait KeyDirectory: Send + Sync {
/// Read keys from directory
fn load(&self) -> Result<Vec<SafeAccount>, Error>;
/// Insert new key to directory
fn insert(&self, account: SafeAccount) -> Result<SafeAccount, Error>;
/// Update key in the directory
fn update(&self, account: SafeAccount) -> Result<SafeAccount, Error>;
/// Remove key from directory
fn remove(&self, account: &SafeAccount) -> Result<(), Error>;
/// Get directory filesystem path, if available
fn path(&self) -> Option<&PathBuf> {
None
}
/// Return vault provider, if available
fn as_vault_provider(&self) -> Option<&dyn VaultKeyDirectoryProvider> {
None
}
/// Unique representation of directory account collection
fn unique_repr(&self) -> Result<u64, Error>;
}
/// Vaults provider
pub trait VaultKeyDirectoryProvider {
/// Create new vault with given key
fn create(&self, name: &str, key: VaultKey) -> Result<Box<dyn VaultKeyDirectory>, Error>;
/// Open existing vault with given key
fn open(&self, name: &str, key: VaultKey) -> Result<Box<dyn VaultKeyDirectory>, Error>;
/// List all vaults
fn list_vaults(&self) -> Result<Vec<String>, Error>;
/// Get vault meta
fn vault_meta(&self, name: &str) -> Result<String, Error>;
}
/// Vault directory
pub trait VaultKeyDirectory: KeyDirectory {
/// Cast to `KeyDirectory`
fn as_key_directory(&self) -> &dyn KeyDirectory;
/// Vault name
fn name(&self) -> &str;
/// Get vault key
fn key(&self) -> VaultKey;
/// Set new key for vault
fn set_key(&self, key: VaultKey) -> Result<(), SetKeyError>;
/// Get vault meta
fn meta(&self) -> String;
/// Set vault meta
fn set_meta(&self, meta: &str) -> Result<(), Error>;
}
pub use self::{
disk::{DiskKeyFileManager, KeyFileManager, RootDiskDirectory},
memory::MemoryDirectory,
vault::VaultDiskDirectory,
};
impl VaultKey {
/// Create new vault key
pub fn new(password: &Password, iterations: NonZeroU32) -> Self {
VaultKey {
password: password.clone(),
iterations: iterations,
}
}
}

View File

@@ -0,0 +1,527 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::{
super::account::Crypto,
disk::{self, DiskDirectory, KeyFileManager},
KeyDirectory, SetKeyError, VaultKey, VaultKeyDirectory,
};
use crypto::Keccak256;
use json;
use parking_lot::Mutex;
use std::{
fs, io,
path::{Path, PathBuf},
};
use Error;
use SafeAccount;
/// Name of vault metadata file
pub const VAULT_FILE_NAME: &'static str = "vault.json";
/// Name of temporary vault metadata file
pub const VAULT_TEMP_FILE_NAME: &'static str = "vault_temp.json";
/// Vault directory implementation
pub type VaultDiskDirectory = DiskDirectory<VaultKeyFileManager>;
/// Vault key file manager
pub struct VaultKeyFileManager {
name: String,
key: VaultKey,
meta: Mutex<String>,
}
impl VaultDiskDirectory {
/// Create new vault directory with given key
pub fn create<P>(root: P, name: &str, key: VaultKey) -> Result<Self, Error>
where
P: AsRef<Path>,
{
// check that vault directory does not exists
let vault_dir_path = make_vault_dir_path(root, name, true)?;
if vault_dir_path.exists() {
return Err(Error::CreationFailed);
}
// create vault && vault file
let vault_meta = "{}";
fs::create_dir_all(&vault_dir_path)?;
if let Err(err) = create_vault_file(&vault_dir_path, &key, vault_meta) {
let _ = fs::remove_dir_all(&vault_dir_path); // can't do anything with this
return Err(err);
}
Ok(DiskDirectory::new(
vault_dir_path,
VaultKeyFileManager::new(name, key, vault_meta),
))
}
/// Open existing vault directory with given key
pub fn at<P>(root: P, name: &str, key: VaultKey) -> Result<Self, Error>
where
P: AsRef<Path>,
{
// check that vault directory exists
let vault_dir_path = make_vault_dir_path(root, name, true)?;
if !vault_dir_path.is_dir() {
return Err(Error::CreationFailed);
}
// check that passed key matches vault file
let meta = read_vault_file(&vault_dir_path, Some(&key))?;
Ok(DiskDirectory::new(
vault_dir_path,
VaultKeyFileManager::new(name, key, &meta),
))
}
/// Read vault meta without actually opening the vault
pub fn meta_at<P>(root: P, name: &str) -> Result<String, Error>
where
P: AsRef<Path>,
{
// check that vault directory exists
let vault_dir_path = make_vault_dir_path(root, name, true)?;
if !vault_dir_path.is_dir() {
return Err(Error::VaultNotFound);
}
// check that passed key matches vault file
read_vault_file(&vault_dir_path, None)
}
fn create_temp_vault(&self, key: VaultKey) -> Result<VaultDiskDirectory, Error> {
let original_path = self
.path()
.expect("self is instance of DiskDirectory; DiskDirectory always returns path; qed");
let mut path: PathBuf = original_path.clone();
let name = self.name();
path.push(name); // to jump to the next level
let mut index = 0;
loop {
let name = format!("{}_temp_{}", name, index);
path.set_file_name(&name);
if !path.exists() {
return VaultDiskDirectory::create(original_path, &name, key);
}
index += 1;
}
}
fn copy_to_vault(&self, vault: &VaultDiskDirectory) -> Result<(), Error> {
for account in self.load()? {
let filename = account.filename.clone().expect(
"self is instance of DiskDirectory; DiskDirectory fills filename in load; qed",
);
vault.insert_with_filename(account, filename, true)?;
}
Ok(())
}
fn delete(&self) -> Result<(), Error> {
let path = self
.path()
.expect("self is instance of DiskDirectory; DiskDirectory always returns path; qed");
fs::remove_dir_all(path).map_err(Into::into)
}
}
impl VaultKeyDirectory for VaultDiskDirectory {
fn as_key_directory(&self) -> &dyn KeyDirectory {
self
}
fn name(&self) -> &str {
&self.key_manager().name
}
fn key(&self) -> VaultKey {
self.key_manager().key.clone()
}
fn set_key(&self, new_key: VaultKey) -> Result<(), SetKeyError> {
let temp_vault = VaultDiskDirectory::create_temp_vault(self, new_key.clone())
.map_err(|err| SetKeyError::NonFatalOld(err))?;
let mut source_path = temp_vault
.path()
.expect(
"temp_vault is instance of DiskDirectory; DiskDirectory always returns path; qed",
)
.clone();
let mut target_path = self
.path()
.expect("self is instance of DiskDirectory; DiskDirectory always returns path; qed")
.clone();
// preserve meta
temp_vault
.set_meta(&self.meta())
.map_err(SetKeyError::NonFatalOld)?;
// jump to next fs level
source_path.push("next");
target_path.push("next");
let temp_accounts = self
.copy_to_vault(&temp_vault)
.and_then(|_| temp_vault.load())
.map_err(|err| {
// ignore error, as we already processing error
let _ = temp_vault.delete();
SetKeyError::NonFatalOld(err)
})?;
// we can't just delete temp vault until all files moved, because
// original vault content has already been partially replaced
// => when error or crash happens here, we can't do anything
for temp_account in temp_accounts {
let filename = temp_account.filename.expect(
"self is instance of DiskDirectory; DiskDirectory fills filename in load; qed",
);
source_path.set_file_name(&filename);
target_path.set_file_name(&filename);
fs::rename(&source_path, &target_path).map_err(|err| SetKeyError::Fatal(err.into()))?;
}
source_path.set_file_name(VAULT_FILE_NAME);
target_path.set_file_name(VAULT_FILE_NAME);
fs::rename(source_path, target_path).map_err(|err| SetKeyError::Fatal(err.into()))?;
temp_vault
.delete()
.map_err(|err| SetKeyError::NonFatalNew(err))
}
fn meta(&self) -> String {
self.key_manager().meta.lock().clone()
}
fn set_meta(&self, meta: &str) -> Result<(), Error> {
let key_manager = self.key_manager();
let vault_path = self
.path()
.expect("self is instance of DiskDirectory; DiskDirectory always returns path; qed");
create_vault_file(vault_path, &key_manager.key, meta)?;
*key_manager.meta.lock() = meta.to_owned();
Ok(())
}
}
impl VaultKeyFileManager {
pub fn new(name: &str, key: VaultKey, meta: &str) -> Self {
VaultKeyFileManager {
name: name.into(),
key: key,
meta: Mutex::new(meta.to_owned()),
}
}
}
impl KeyFileManager for VaultKeyFileManager {
fn read<T>(&self, filename: Option<String>, reader: T) -> Result<SafeAccount, Error>
where
T: io::Read,
{
let vault_file =
json::VaultKeyFile::load(reader).map_err(|e| Error::Custom(format!("{:?}", e)))?;
let mut safe_account =
SafeAccount::from_vault_file(&self.key.password, vault_file, filename.clone())?;
safe_account.meta = json::insert_vault_name_to_json_meta(&safe_account.meta, &self.name)
.map_err(|err| Error::Custom(format!("{:?}", err)))?;
Ok(safe_account)
}
fn write<T>(&self, mut account: SafeAccount, writer: &mut T) -> Result<(), Error>
where
T: io::Write,
{
account.meta = json::remove_vault_name_from_json_meta(&account.meta)
.map_err(|err| Error::Custom(format!("{:?}", err)))?;
let vault_file: json::VaultKeyFile =
account.into_vault_file(self.key.iterations, &self.key.password)?;
vault_file
.write(writer)
.map_err(|e| Error::Custom(format!("{:?}", e)))
}
}
/// Makes path to vault directory, checking that vault name is appropriate
fn make_vault_dir_path<P>(root: P, name: &str, check_name: bool) -> Result<PathBuf, Error>
where
P: AsRef<Path>,
{
// check vault name
if check_name && !check_vault_name(name) {
return Err(Error::InvalidVaultName);
}
let mut vault_dir_path: PathBuf = root.as_ref().into();
vault_dir_path.push(name);
Ok(vault_dir_path)
}
/// Every vault must have unique name => we rely on filesystem to check this
/// => vault name must not contain any fs-special characters to avoid directory traversal
/// => we only allow alphanumeric + separator characters in vault name.
fn check_vault_name(name: &str) -> bool {
!name.is_empty()
&& name
.chars()
.all(|c| c.is_alphanumeric() || c.is_whitespace() || c == '-' || c == '_')
}
/// Vault can be empty, but still must be pluggable => we store vault password in separate file
fn create_vault_file<P>(vault_dir_path: P, key: &VaultKey, meta: &str) -> Result<(), Error>
where
P: AsRef<Path>,
{
let password_hash = key.password.as_bytes().keccak256();
let crypto = Crypto::with_plain(&password_hash, &key.password, key.iterations)?;
let vault_file_path = vault_dir_path.as_ref().join(VAULT_FILE_NAME);
let temp_vault_file_name = disk::find_unique_filename_using_random_suffix(
vault_dir_path.as_ref(),
&VAULT_TEMP_FILE_NAME,
)?;
let temp_vault_file_path = vault_dir_path.as_ref().join(&temp_vault_file_name);
// this method is used to rewrite existing vault file
// => write to temporary file first, then rename temporary file to vault file
let mut vault_file = disk::create_new_file_with_permissions_to_owner(&temp_vault_file_path)?;
let vault_file_contents = json::VaultFile {
crypto: crypto.into(),
meta: Some(meta.to_owned()),
};
vault_file_contents
.write(&mut vault_file)
.map_err(|e| Error::Custom(format!("{:?}", e)))?;
drop(vault_file);
fs::rename(&temp_vault_file_path, &vault_file_path)?;
Ok(())
}
/// When vault is opened => we must check that password matches && read metadata
fn read_vault_file<P>(vault_dir_path: P, key: Option<&VaultKey>) -> Result<String, Error>
where
P: AsRef<Path>,
{
let mut vault_file_path: PathBuf = vault_dir_path.as_ref().into();
vault_file_path.push(VAULT_FILE_NAME);
let vault_file = fs::File::open(vault_file_path)?;
let vault_file_contents =
json::VaultFile::load(vault_file).map_err(|e| Error::Custom(format!("{:?}", e)))?;
let vault_file_meta = vault_file_contents.meta.unwrap_or("{}".to_owned());
let vault_file_crypto: Crypto = vault_file_contents.crypto.into();
if let Some(key) = key {
let password_bytes = vault_file_crypto.decrypt(&key.password)?;
let password_hash = key.password.as_bytes().keccak256();
if password_hash != password_bytes.as_slice() {
return Err(Error::InvalidPassword);
}
}
Ok(vault_file_meta)
}
#[cfg(test)]
mod test {
extern crate tempdir;
use self::tempdir::TempDir;
use super::{
check_vault_name, create_vault_file, make_vault_dir_path, read_vault_file,
VaultDiskDirectory, VaultKey, VAULT_FILE_NAME,
};
use std::{fs, io::Write, num::NonZeroU32, path::PathBuf};
lazy_static! {
static ref ITERATIONS: NonZeroU32 = NonZeroU32::new(1024).expect("1024 > 0; qed");
}
#[test]
fn check_vault_name_succeeds() {
assert!(check_vault_name("vault"));
assert!(check_vault_name("vault with spaces"));
assert!(check_vault_name("vault with tabs"));
assert!(check_vault_name("vault_with_underscores"));
assert!(check_vault_name("vault-with-dashes"));
assert!(check_vault_name("vault-with-digits-123"));
assert!(check_vault_name("vault中文名字"));
}
#[test]
fn check_vault_name_fails() {
assert!(!check_vault_name(""));
assert!(!check_vault_name("."));
assert!(!check_vault_name("*"));
assert!(!check_vault_name("../.bash_history"));
assert!(!check_vault_name("/etc/passwd"));
assert!(!check_vault_name("c:\\windows"));
}
#[test]
fn make_vault_dir_path_succeeds() {
use std::path::Path;
assert_eq!(
&make_vault_dir_path("/home/user/parity", "vault", true).unwrap(),
&Path::new("/home/user/parity/vault")
);
assert_eq!(
&make_vault_dir_path("/home/user/parity", "*bad-name*", false).unwrap(),
&Path::new("/home/user/parity/*bad-name*")
);
}
#[test]
fn make_vault_dir_path_fails() {
assert!(make_vault_dir_path("/home/user/parity", "*bad-name*", true).is_err());
}
#[test]
fn create_vault_file_succeeds() {
// given
let temp_path = TempDir::new("").unwrap();
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();
// when
let result = create_vault_file(&vault_dir, &key, "{}");
// then
assert!(result.is_ok());
let mut vault_file_path = vault_dir.clone();
vault_file_path.push(VAULT_FILE_NAME);
assert!(vault_file_path.exists() && vault_file_path.is_file());
}
#[test]
fn read_vault_file_succeeds() {
// given
let temp_path = TempDir::new("").unwrap();
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();
vault_file_path.push(VAULT_FILE_NAME);
{
let mut vault_file = fs::File::create(vault_file_path).unwrap();
vault_file
.write_all(vault_file_contents.as_bytes())
.unwrap();
}
// when
let result = read_vault_file(&dir, Some(&key));
// then
assert!(result.is_ok());
}
#[test]
fn read_vault_file_fails() {
// given
let temp_path = TempDir::new("").unwrap();
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);
// when
let result = read_vault_file(&dir, Some(&key));
// then
assert!(result.is_err());
// and when given
let vault_file_contents = r#"{"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"0155e3690be19fbfbecabcd440aa284b"},"ciphertext":"4d6938a1f49b7782","kdf":"pbkdf2","kdfparams":{"c":1024,"dklen":32,"prf":"hmac-sha256","salt":"b6a9338a7ccd39288a86dba73bfecd9101b4f3db9c9830e7c76afdbd4f6872e5"},"mac":"16381463ea11c6eb2239a9f339c2e780516d29d234ce30ac5f166f9080b5a262"}}"#;
{
let mut vault_file = fs::File::create(vault_file_path).unwrap();
vault_file
.write_all(vault_file_contents.as_bytes())
.unwrap();
}
// when
let result = read_vault_file(&dir, Some(&key));
// then
assert!(result.is_err());
}
#[test]
fn vault_directory_can_be_created() {
// given
let temp_path = TempDir::new("").unwrap();
let key = VaultKey::new(&"password".into(), *ITERATIONS);
let dir: PathBuf = temp_path.path().into();
// when
let vault = VaultDiskDirectory::create(&dir, "vault", key.clone());
// then
assert!(vault.is_ok());
// and when
let vault = VaultDiskDirectory::at(&dir, "vault", key);
// then
assert!(vault.is_ok());
}
#[test]
fn vault_directory_cannot_be_created_if_already_exists() {
// given
let temp_path = TempDir::new("").unwrap();
let key = VaultKey::new(&"password".into(), *ITERATIONS);
let dir: PathBuf = temp_path.path().into();
let mut vault_dir = dir.clone();
vault_dir.push("vault");
fs::create_dir_all(&vault_dir).unwrap();
// when
let vault = VaultDiskDirectory::create(&dir, "vault", key);
// then
assert!(vault.is_err());
}
#[test]
fn vault_directory_cannot_be_opened_if_not_exists() {
// given
let temp_path = TempDir::new("").unwrap();
let key = VaultKey::new(&"password".into(), *ITERATIONS);
let dir: PathBuf = temp_path.path().into();
// when
let vault = VaultDiskDirectory::at(&dir, "vault", key);
// then
assert!(vault.is_err());
}
}

View File

@@ -0,0 +1,126 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use crypto::{self, Error as EthCryptoError};
use ethkey::{self, DerivationError, Error as EthKeyError};
use std::{fmt, io::Error as IoError};
/// Account-related errors.
#[derive(Debug)]
pub enum Error {
/// IO error
Io(IoError),
/// Invalid Password
InvalidPassword,
/// Account's secret is invalid.
InvalidSecret,
/// Invalid Vault Crypto meta.
InvalidCryptoMeta,
/// Invalid Account.
InvalidAccount,
/// Invalid Message.
InvalidMessage,
/// Invalid Key File
InvalidKeyFile(String),
/// Vaults are not supported.
VaultsAreNotSupported,
/// Unsupported vault
UnsupportedVault,
/// Invalid vault name
InvalidVaultName,
/// Vault not found
VaultNotFound,
/// Account creation failed.
CreationFailed,
/// `EthKey` error
EthKey(EthKeyError),
/// `ethkey::crypto::Error`
EthKeyCrypto(ethkey::crypto::Error),
/// `EthCrypto` error
EthCrypto(EthCryptoError),
/// Derivation error
Derivation(DerivationError),
/// Custom error
Custom(String),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let s = match *self {
Error::Io(ref err) => err.to_string(),
Error::InvalidPassword => "Invalid password".into(),
Error::InvalidSecret => "Invalid secret".into(),
Error::InvalidCryptoMeta => "Invalid crypted metadata".into(),
Error::InvalidAccount => "Invalid account".into(),
Error::InvalidMessage => "Invalid message".into(),
Error::InvalidKeyFile(ref reason) => format!("Invalid key file: {}", reason),
Error::VaultsAreNotSupported => "Vaults are not supported".into(),
Error::UnsupportedVault => "Vault is not supported for this operation".into(),
Error::InvalidVaultName => "Invalid vault name".into(),
Error::VaultNotFound => "Vault not found".into(),
Error::CreationFailed => "Account creation failed".into(),
Error::EthKey(ref err) => err.to_string(),
Error::EthKeyCrypto(ref err) => err.to_string(),
Error::EthCrypto(ref err) => err.to_string(),
Error::Derivation(ref err) => format!("Derivation error: {:?}", err),
Error::Custom(ref s) => s.clone(),
};
write!(f, "{}", s)
}
}
impl From<IoError> for Error {
fn from(err: IoError) -> Self {
Error::Io(err)
}
}
impl From<EthKeyError> for Error {
fn from(err: EthKeyError) -> Self {
Error::EthKey(err)
}
}
impl From<ethkey::crypto::Error> for Error {
fn from(err: ethkey::crypto::Error) -> Self {
Error::EthKeyCrypto(err)
}
}
impl From<EthCryptoError> for Error {
fn from(err: EthCryptoError) -> Self {
Error::EthCrypto(err)
}
}
impl From<crypto::error::ScryptError> for Error {
fn from(err: crypto::error::ScryptError) -> Self {
Error::EthCrypto(err.into())
}
}
impl From<crypto::error::SymmError> for Error {
fn from(err: crypto::error::SymmError) -> Self {
Error::EthCrypto(err.into())
}
}
impl From<DerivationError> for Error {
fn from(err: DerivationError) -> Self {
Error::Derivation(err)
}
}

View File

@@ -0,0 +1,41 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
//! ethkey reexport to make documentation look pretty.
pub use _ethkey::*;
use json;
impl Into<json::H160> for Address {
fn into(self) -> json::H160 {
let a: [u8; 20] = self.into();
From::from(a)
}
}
impl From<json::H160> for Address {
fn from(json: json::H160) -> Self {
let a: [u8; 20] = json.into();
From::from(a)
}
}
impl<'a> From<&'a json::H160> for Address {
fn from(json: &'a json::H160) -> Self {
let mut a = [0u8; 20];
a.copy_from_slice(json);
From::from(a)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,67 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use std::{collections::HashSet, fs, path::Path};
use accounts_dir::{DiskKeyFileManager, KeyDirectory, KeyFileManager};
use ethkey::Address;
use Error;
/// Import an account from a file.
pub fn import_account(path: &Path, dst: &dyn KeyDirectory) -> Result<Address, Error> {
let key_manager = DiskKeyFileManager::default();
let existing_accounts = dst
.load()?
.into_iter()
.map(|a| a.address)
.collect::<HashSet<_>>();
let filename = path
.file_name()
.and_then(|n| n.to_str())
.map(|f| f.to_owned());
let account = fs::File::open(&path)
.map_err(Into::into)
.and_then(|file| key_manager.read(filename, file))?;
let address = account.address.clone();
if !existing_accounts.contains(&address) {
dst.insert(account)?;
}
Ok(address)
}
/// Import all accounts from one directory to the other.
pub fn import_accounts(
src: &dyn KeyDirectory,
dst: &dyn KeyDirectory,
) -> Result<Vec<Address>, Error> {
let accounts = src.load()?;
let existing_accounts = dst
.load()?
.into_iter()
.map(|a| a.address)
.collect::<HashSet<_>>();
accounts
.into_iter()
.filter(|a| !existing_accounts.contains(&a.address))
.map(|a| {
let address = a.address.clone();
dst.insert(a)?;
Ok(address)
})
.collect()
}

View File

@@ -0,0 +1,82 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use rustc_hex::{FromHex, FromHexError, ToHex};
use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
use std::{ops, str};
#[derive(Debug, PartialEq)]
pub struct Bytes(Vec<u8>);
impl ops::Deref for Bytes {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a> Deserialize<'a> for Bytes {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'a>,
{
let s = String::deserialize(deserializer)?;
let data = s
.from_hex()
.map_err(|e| Error::custom(format!("Invalid hex value {}", e)))?;
Ok(Bytes(data))
}
}
impl Serialize for Bytes {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.0.to_hex())
}
}
impl str::FromStr for Bytes {
type Err = FromHexError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
s.from_hex().map(Bytes)
}
}
impl From<&'static str> for Bytes {
fn from(s: &'static str) -> Self {
s.parse().expect(&format!(
"invalid string literal for {}: '{}'",
stringify!(Self),
s
))
}
}
impl From<Vec<u8>> for Bytes {
fn from(v: Vec<u8>) -> Self {
Bytes(v)
}
}
impl From<Bytes> for Vec<u8> {
fn from(b: Bytes) -> Self {
b.0
}
}

View File

@@ -0,0 +1,112 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::{Error, H128};
use serde::{
de::{Error as SerdeError, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};
use std::fmt;
#[derive(Debug, PartialEq)]
pub enum CipherSer {
Aes128Ctr,
}
impl Serialize for CipherSer {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
CipherSer::Aes128Ctr => serializer.serialize_str("aes-128-ctr"),
}
}
}
impl<'a> Deserialize<'a> for CipherSer {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'a>,
{
deserializer.deserialize_any(CipherSerVisitor)
}
}
struct CipherSerVisitor;
impl<'a> Visitor<'a> for CipherSerVisitor {
type Value = CipherSer;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a valid cipher identifier")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: SerdeError,
{
match value {
"aes-128-ctr" => Ok(CipherSer::Aes128Ctr),
_ => Err(SerdeError::custom(Error::UnsupportedCipher)),
}
}
fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
where
E: SerdeError,
{
self.visit_str(value.as_ref())
}
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Aes128Ctr {
pub iv: H128,
}
#[derive(Debug, PartialEq)]
pub enum CipherSerParams {
Aes128Ctr(Aes128Ctr),
}
impl Serialize for CipherSerParams {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
CipherSerParams::Aes128Ctr(ref params) => params.serialize(serializer),
}
}
}
impl<'a> Deserialize<'a> for CipherSerParams {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'a>,
{
Aes128Ctr::deserialize(deserializer)
.map(CipherSerParams::Aes128Ctr)
.map_err(|_| Error::InvalidCipherParams)
.map_err(SerdeError::custom)
}
}
#[derive(Debug, PartialEq)]
pub enum Cipher {
Aes128Ctr(Aes128Ctr),
}

View File

@@ -0,0 +1,218 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::{Bytes, Cipher, CipherSer, CipherSerParams, Kdf, KdfSer, KdfSerParams, H256};
use serde::{
de::{Error, MapAccess, Visitor},
ser::SerializeStruct,
Deserialize, Deserializer, Serialize, Serializer,
};
use serde_json;
use std::{fmt, str};
pub type CipherText = Bytes;
#[derive(Debug, PartialEq)]
pub struct Crypto {
pub cipher: Cipher,
pub ciphertext: CipherText,
pub kdf: Kdf,
pub mac: H256,
}
impl str::FromStr for Crypto {
type Err = serde_json::error::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
serde_json::from_str(s)
}
}
impl From<Crypto> for String {
fn from(c: Crypto) -> Self {
serde_json::to_string(&c)
.expect("serialization cannot fail, cause all crypto keys are strings")
}
}
enum CryptoField {
Cipher,
CipherParams,
CipherText,
Kdf,
KdfParams,
Mac,
Version,
}
impl<'a> Deserialize<'a> for CryptoField {
fn deserialize<D>(deserializer: D) -> Result<CryptoField, D::Error>
where
D: Deserializer<'a>,
{
deserializer.deserialize_any(CryptoFieldVisitor)
}
}
struct CryptoFieldVisitor;
impl<'a> Visitor<'a> for CryptoFieldVisitor {
type Value = CryptoField;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a valid crypto struct description")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: Error,
{
match value {
"cipher" => Ok(CryptoField::Cipher),
"cipherparams" => Ok(CryptoField::CipherParams),
"ciphertext" => Ok(CryptoField::CipherText),
"kdf" => Ok(CryptoField::Kdf),
"kdfparams" => Ok(CryptoField::KdfParams),
"mac" => Ok(CryptoField::Mac),
"version" => Ok(CryptoField::Version),
_ => Err(Error::custom(format!("Unknown field: '{}'", value))),
}
}
}
impl<'a> Deserialize<'a> for Crypto {
fn deserialize<D>(deserializer: D) -> Result<Crypto, D::Error>
where
D: Deserializer<'a>,
{
static FIELDS: &'static [&'static str] = &["id", "version", "crypto", "Crypto", "address"];
deserializer.deserialize_struct("Crypto", FIELDS, CryptoVisitor)
}
}
struct CryptoVisitor;
impl<'a> Visitor<'a> for CryptoVisitor {
type Value = Crypto;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a valid vault crypto object")
}
fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'a>,
{
let mut cipher = None;
let mut cipherparams = None;
let mut ciphertext = None;
let mut kdf = None;
let mut kdfparams = None;
let mut mac = None;
loop {
match visitor.next_key()? {
Some(CryptoField::Cipher) => {
cipher = Some(visitor.next_value()?);
}
Some(CryptoField::CipherParams) => {
cipherparams = Some(visitor.next_value()?);
}
Some(CryptoField::CipherText) => {
ciphertext = Some(visitor.next_value()?);
}
Some(CryptoField::Kdf) => {
kdf = Some(visitor.next_value()?);
}
Some(CryptoField::KdfParams) => {
kdfparams = Some(visitor.next_value()?);
}
Some(CryptoField::Mac) => {
mac = Some(visitor.next_value()?);
}
// skip not required version field (it appears in pyethereum generated keystores)
Some(CryptoField::Version) => visitor.next_value().unwrap_or(()),
None => {
break;
}
}
}
let cipher = match (cipher, cipherparams) {
(Some(CipherSer::Aes128Ctr), Some(CipherSerParams::Aes128Ctr(params))) => {
Cipher::Aes128Ctr(params)
}
(None, _) => return Err(V::Error::missing_field("cipher")),
(Some(_), None) => return Err(V::Error::missing_field("cipherparams")),
};
let ciphertext = match ciphertext {
Some(ciphertext) => ciphertext,
None => return Err(V::Error::missing_field("ciphertext")),
};
let kdf = match (kdf, kdfparams) {
(Some(KdfSer::Pbkdf2), Some(KdfSerParams::Pbkdf2(params))) => Kdf::Pbkdf2(params),
(Some(KdfSer::Scrypt), Some(KdfSerParams::Scrypt(params))) => Kdf::Scrypt(params),
(Some(_), Some(_)) => return Err(V::Error::custom("Invalid cipherparams")),
(None, _) => return Err(V::Error::missing_field("kdf")),
(Some(_), None) => return Err(V::Error::missing_field("kdfparams")),
};
let mac = match mac {
Some(mac) => mac,
None => return Err(V::Error::missing_field("mac")),
};
let result = Crypto {
cipher: cipher,
ciphertext: ciphertext,
kdf: kdf,
mac: mac,
};
Ok(result)
}
}
impl Serialize for Crypto {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut crypto = serializer.serialize_struct("Crypto", 6)?;
match self.cipher {
Cipher::Aes128Ctr(ref params) => {
crypto.serialize_field("cipher", &CipherSer::Aes128Ctr)?;
crypto.serialize_field("cipherparams", params)?;
}
}
crypto.serialize_field("ciphertext", &self.ciphertext)?;
match self.kdf {
Kdf::Pbkdf2(ref params) => {
crypto.serialize_field("kdf", &KdfSer::Pbkdf2)?;
crypto.serialize_field("kdfparams", params)?;
}
Kdf::Scrypt(ref params) => {
crypto.serialize_field("kdf", &KdfSer::Scrypt)?;
crypto.serialize_field("kdfparams", params)?;
}
}
crypto.serialize_field("mac", &self.mac)?;
crypto.end()
}
}

View File

@@ -0,0 +1,50 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use std::fmt;
#[derive(Debug, PartialEq)]
pub enum Error {
UnsupportedCipher,
InvalidCipherParams,
UnsupportedKdf,
InvalidUuid,
UnsupportedVersion,
InvalidCiphertext,
InvalidH256,
InvalidPrf,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
Error::InvalidUuid => write!(f, "Invalid Uuid"),
Error::UnsupportedVersion => write!(f, "Unsupported version"),
Error::UnsupportedKdf => write!(f, "Unsupported kdf"),
Error::InvalidCiphertext => write!(f, "Invalid ciphertext"),
Error::UnsupportedCipher => write!(f, "Unsupported cipher"),
Error::InvalidCipherParams => write!(f, "Invalid cipher params"),
Error::InvalidH256 => write!(f, "Invalid hash"),
Error::InvalidPrf => write!(f, "Invalid prf"),
}
}
}
impl Into<String> for Error {
fn into(self) -> String {
format!("{}", self)
}
}

View File

@@ -0,0 +1,135 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::Error;
use rustc_hex::{FromHex, ToHex};
use serde::{
de::{Error as SerdeError, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};
use std::{fmt, ops, str};
macro_rules! impl_hash {
($name: ident, $size: expr) => {
pub struct $name([u8; $size]);
impl fmt::Debug for $name {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let self_ref: &[u8] = &self.0;
write!(f, "{:?}", self_ref)
}
}
impl PartialEq for $name {
fn eq(&self, other: &Self) -> bool {
let self_ref: &[u8] = &self.0;
let other_ref: &[u8] = &other.0;
self_ref == other_ref
}
}
impl ops::Deref for $name {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Serialize for $name {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.0.to_hex())
}
}
impl<'a> Deserialize<'a> for $name {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'a>,
{
struct HashVisitor;
impl<'b> Visitor<'b> for HashVisitor {
type Value = $name;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a hex-encoded {}", stringify!($name))
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: SerdeError,
{
value.parse().map_err(SerdeError::custom)
}
fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
where
E: SerdeError,
{
self.visit_str(value.as_ref())
}
}
deserializer.deserialize_any(HashVisitor)
}
}
impl str::FromStr for $name {
type Err = Error;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value.from_hex() {
Ok(ref hex) if hex.len() == $size => {
let mut hash = [0u8; $size];
hash.clone_from_slice(hex);
Ok($name(hash))
}
_ => Err(Error::InvalidH256),
}
}
}
impl From<&'static str> for $name {
fn from(s: &'static str) -> Self {
s.parse().expect(&format!(
"invalid string literal for {}: '{}'",
stringify!($name),
s
))
}
}
impl From<[u8; $size]> for $name {
fn from(bytes: [u8; $size]) -> Self {
$name(bytes)
}
}
impl Into<[u8; $size]> for $name {
fn into(self) -> [u8; $size] {
self.0
}
}
};
}
impl_hash!(H128, 16);
impl_hash!(H160, 20);
impl_hash!(H256, 32);

View File

@@ -0,0 +1,179 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
//! Universaly unique identifier.
use super::Error;
use rustc_hex::{FromHex, ToHex};
use serde::{
de::{Error as SerdeError, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};
use std::{fmt, str};
/// Universaly unique identifier.
#[derive(Debug, PartialEq)]
pub struct Uuid([u8; 16]);
impl From<[u8; 16]> for Uuid {
fn from(uuid: [u8; 16]) -> Self {
Uuid(uuid)
}
}
impl<'a> Into<String> for &'a Uuid {
fn into(self) -> String {
let d1 = &self.0[0..4];
let d2 = &self.0[4..6];
let d3 = &self.0[6..8];
let d4 = &self.0[8..10];
let d5 = &self.0[10..16];
[d1, d2, d3, d4, d5]
.iter()
.map(|d| d.to_hex())
.collect::<Vec<String>>()
.join("-")
}
}
impl Into<String> for Uuid {
fn into(self) -> String {
Into::into(&self)
}
}
impl Into<[u8; 16]> for Uuid {
fn into(self) -> [u8; 16] {
self.0
}
}
impl fmt::Display for Uuid {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let s: String = (self as &Uuid).into();
write!(f, "{}", s)
}
}
fn copy_into(from: &str, into: &mut [u8]) -> Result<(), Error> {
let from = from.from_hex().map_err(|_| Error::InvalidUuid)?;
if from.len() != into.len() {
return Err(Error::InvalidUuid);
}
into.copy_from_slice(&from);
Ok(())
}
impl str::FromStr for Uuid {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts: Vec<&str> = s.split("-").collect();
if parts.len() != 5 {
return Err(Error::InvalidUuid);
}
let mut uuid = [0u8; 16];
copy_into(parts[0], &mut uuid[0..4])?;
copy_into(parts[1], &mut uuid[4..6])?;
copy_into(parts[2], &mut uuid[6..8])?;
copy_into(parts[3], &mut uuid[8..10])?;
copy_into(parts[4], &mut uuid[10..16])?;
Ok(Uuid(uuid))
}
}
impl From<&'static str> for Uuid {
fn from(s: &'static str) -> Self {
s.parse().expect(&format!(
"invalid string literal for {}: '{}'",
stringify!(Self),
s
))
}
}
impl Serialize for Uuid {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s: String = self.into();
serializer.serialize_str(&s)
}
}
impl<'a> Deserialize<'a> for Uuid {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'a>,
{
deserializer.deserialize_any(UuidVisitor)
}
}
struct UuidVisitor;
impl<'a> Visitor<'a> for UuidVisitor {
type Value = Uuid;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a valid hex-encoded UUID")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: SerdeError,
{
value.parse().map_err(SerdeError::custom)
}
fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
where
E: SerdeError,
{
self.visit_str(value.as_ref())
}
}
#[cfg(test)]
mod tests {
use super::Uuid;
#[test]
fn uuid_from_str() {
let uuid: Uuid = "3198bc9c-6672-5ab3-d995-4942343ae5b6".into();
assert_eq!(
uuid,
Uuid::from([
0x31, 0x98, 0xbc, 0x9c, 0x66, 0x72, 0x5a, 0xb3, 0xd9, 0x95, 0x49, 0x42, 0x34, 0x3a,
0xe5, 0xb6
])
);
}
#[test]
fn uuid_from_and_to_str() {
let from = "3198bc9c-6672-5ab3-d995-4942343ae5b6";
let uuid: Uuid = from.into();
let to: String = uuid.into();
assert_eq!(from, &to);
}
}

View File

@@ -0,0 +1,186 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::{Bytes, Error};
use serde::{
de::{Error as SerdeError, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};
use std::{fmt, num::NonZeroU32};
#[derive(Debug, PartialEq)]
pub enum KdfSer {
Pbkdf2,
Scrypt,
}
impl Serialize for KdfSer {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
KdfSer::Pbkdf2 => serializer.serialize_str("pbkdf2"),
KdfSer::Scrypt => serializer.serialize_str("scrypt"),
}
}
}
impl<'a> Deserialize<'a> for KdfSer {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'a>,
{
deserializer.deserialize_any(KdfSerVisitor)
}
}
struct KdfSerVisitor;
impl<'a> Visitor<'a> for KdfSerVisitor {
type Value = KdfSer;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a kdf algorithm identifier")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: SerdeError,
{
match value {
"pbkdf2" => Ok(KdfSer::Pbkdf2),
"scrypt" => Ok(KdfSer::Scrypt),
_ => Err(SerdeError::custom(Error::UnsupportedKdf)),
}
}
fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
where
E: SerdeError,
{
self.visit_str(value.as_ref())
}
}
#[derive(Debug, PartialEq)]
pub enum Prf {
HmacSha256,
}
impl Serialize for Prf {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
Prf::HmacSha256 => serializer.serialize_str("hmac-sha256"),
}
}
}
impl<'a> Deserialize<'a> for Prf {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'a>,
{
deserializer.deserialize_any(PrfVisitor)
}
}
struct PrfVisitor;
impl<'a> Visitor<'a> for PrfVisitor {
type Value = Prf;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a prf algorithm identifier")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: SerdeError,
{
match value {
"hmac-sha256" => Ok(Prf::HmacSha256),
_ => Err(SerdeError::custom(Error::InvalidPrf)),
}
}
fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
where
E: SerdeError,
{
self.visit_str(value.as_ref())
}
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Pbkdf2 {
pub c: NonZeroU32,
pub dklen: u32,
pub prf: Prf,
pub salt: Bytes,
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Scrypt {
pub dklen: u32,
pub p: u32,
pub n: u32,
pub r: u32,
pub salt: Bytes,
}
#[derive(Debug, PartialEq)]
pub enum KdfSerParams {
Pbkdf2(Pbkdf2),
Scrypt(Scrypt),
}
impl Serialize for KdfSerParams {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
KdfSerParams::Pbkdf2(ref params) => params.serialize(serializer),
KdfSerParams::Scrypt(ref params) => params.serialize(serializer),
}
}
}
impl<'a> Deserialize<'a> for KdfSerParams {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'a>,
{
use serde_json::{from_value, Value};
let v: Value = Deserialize::deserialize(deserializer)?;
from_value(v.clone())
.map(KdfSerParams::Pbkdf2)
.or_else(|_| from_value(v).map(KdfSerParams::Scrypt))
.map_err(|_| D::Error::custom("Invalid KDF algorithm"))
}
}
#[derive(Debug, PartialEq)]
pub enum Kdf {
Pbkdf2(Pbkdf2),
Scrypt(Scrypt),
}

View File

@@ -0,0 +1,359 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::{Crypto, Uuid, Version, H160};
use serde::{
de::{DeserializeOwned, Error, MapAccess, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};
use serde_json;
use std::{
fmt,
io::{Read, Write},
};
/// Public opaque type representing serializable `KeyFile`.
#[derive(Debug, PartialEq)]
pub struct OpaqueKeyFile {
key_file: KeyFile,
}
impl Serialize for OpaqueKeyFile {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.key_file.serialize(serializer)
}
}
impl<T> From<T> for OpaqueKeyFile
where
T: Into<KeyFile>,
{
fn from(val: T) -> Self {
OpaqueKeyFile {
key_file: val.into(),
}
}
}
#[derive(Debug, PartialEq, Serialize)]
pub struct KeyFile {
pub id: Uuid,
pub version: Version,
pub crypto: Crypto,
pub address: Option<H160>,
pub name: Option<String>,
pub meta: Option<String>,
}
enum KeyFileField {
Id,
Version,
Crypto,
Address,
Name,
Meta,
}
impl<'a> Deserialize<'a> for KeyFileField {
fn deserialize<D>(deserializer: D) -> Result<KeyFileField, D::Error>
where
D: Deserializer<'a>,
{
deserializer.deserialize_any(KeyFileFieldVisitor)
}
}
struct KeyFileFieldVisitor;
impl<'a> Visitor<'a> for KeyFileFieldVisitor {
type Value = KeyFileField;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a valid key file field")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: Error,
{
match value {
"id" => Ok(KeyFileField::Id),
"version" => Ok(KeyFileField::Version),
"crypto" => Ok(KeyFileField::Crypto),
"Crypto" => Ok(KeyFileField::Crypto),
"address" => Ok(KeyFileField::Address),
"name" => Ok(KeyFileField::Name),
"meta" => Ok(KeyFileField::Meta),
_ => Err(Error::custom(format!("Unknown field: '{}'", value))),
}
}
}
impl<'a> Deserialize<'a> for KeyFile {
fn deserialize<D>(deserializer: D) -> Result<KeyFile, D::Error>
where
D: Deserializer<'a>,
{
static FIELDS: &'static [&'static str] = &["id", "version", "crypto", "Crypto", "address"];
deserializer.deserialize_struct("KeyFile", FIELDS, KeyFileVisitor)
}
}
fn none_if_empty<'a, T>(v: Option<serde_json::Value>) -> Option<T>
where
T: DeserializeOwned,
{
v.and_then(|v| {
if v.is_null() {
None
} else {
serde_json::from_value(v).ok()
}
})
}
struct KeyFileVisitor;
impl<'a> Visitor<'a> for KeyFileVisitor {
type Value = KeyFile;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a valid key object")
}
fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'a>,
{
let mut id = None;
let mut version = None;
let mut crypto = None;
let mut address = None;
let mut name = None;
let mut meta = None;
loop {
match visitor.next_key()? {
Some(KeyFileField::Id) => {
id = Some(visitor.next_value()?);
}
Some(KeyFileField::Version) => {
version = Some(visitor.next_value()?);
}
Some(KeyFileField::Crypto) => {
crypto = Some(visitor.next_value()?);
}
Some(KeyFileField::Address) => {
address = Some(visitor.next_value()?);
}
Some(KeyFileField::Name) => name = none_if_empty(visitor.next_value().ok()),
Some(KeyFileField::Meta) => meta = none_if_empty(visitor.next_value().ok()),
None => {
break;
}
}
}
let id = match id {
Some(id) => id,
None => return Err(V::Error::missing_field("id")),
};
let version = match version {
Some(version) => version,
None => return Err(V::Error::missing_field("version")),
};
let crypto = match crypto {
Some(crypto) => crypto,
None => return Err(V::Error::missing_field("crypto")),
};
let result = KeyFile {
id: id,
version: version,
crypto: crypto,
address: address,
name: name,
meta: meta,
};
Ok(result)
}
}
impl KeyFile {
pub fn load<R>(reader: R) -> Result<Self, serde_json::Error>
where
R: Read,
{
serde_json::from_reader(reader)
}
pub fn write<W>(&self, writer: &mut W) -> Result<(), serde_json::Error>
where
W: Write,
{
serde_json::to_writer(writer, self)
}
}
#[cfg(test)]
mod tests {
use json::{Aes128Ctr, Cipher, Crypto, Kdf, KeyFile, Scrypt, Uuid, Version};
use serde_json;
use std::str::FromStr;
#[test]
fn basic_keyfile() {
let json = r#"
{
"address": "6edddfc6349aff20bc6467ccf276c5b52487f7a8",
"crypto": {
"cipher": "aes-128-ctr",
"ciphertext": "7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc",
"cipherparams": {
"iv": "b5a7ec855ec9e2c405371356855fec83"
},
"kdf": "scrypt",
"kdfparams": {
"dklen": 32,
"n": 262144,
"p": 1,
"r": 8,
"salt": "1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209"
},
"mac": "46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f"
},
"id": "8777d9f6-7860-4b9b-88b7-0b57ee6b3a73",
"version": 3,
"name": "Test",
"meta": "{}"
}"#;
let expected = KeyFile {
id: Uuid::from_str("8777d9f6-7860-4b9b-88b7-0b57ee6b3a73").unwrap(),
version: Version::V3,
address: Some("6edddfc6349aff20bc6467ccf276c5b52487f7a8".into()),
crypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: "b5a7ec855ec9e2c405371356855fec83".into(),
}),
ciphertext: "7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc"
.into(),
kdf: Kdf::Scrypt(Scrypt {
n: 262144,
dklen: 32,
p: 1,
r: 8,
salt: "1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209".into(),
}),
mac: "46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f".into(),
},
name: Some("Test".to_owned()),
meta: Some("{}".to_owned()),
};
let keyfile: KeyFile = serde_json::from_str(json).unwrap();
assert_eq!(keyfile, expected);
}
#[test]
fn capital_crypto_keyfile() {
let json = r#"
{
"address": "6edddfc6349aff20bc6467ccf276c5b52487f7a8",
"Crypto": {
"cipher": "aes-128-ctr",
"ciphertext": "7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc",
"cipherparams": {
"iv": "b5a7ec855ec9e2c405371356855fec83"
},
"kdf": "scrypt",
"kdfparams": {
"dklen": 32,
"n": 262144,
"p": 1,
"r": 8,
"salt": "1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209"
},
"mac": "46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f"
},
"id": "8777d9f6-7860-4b9b-88b7-0b57ee6b3a73",
"version": 3
}"#;
let expected = KeyFile {
id: "8777d9f6-7860-4b9b-88b7-0b57ee6b3a73".into(),
version: Version::V3,
address: Some("6edddfc6349aff20bc6467ccf276c5b52487f7a8".into()),
crypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: "b5a7ec855ec9e2c405371356855fec83".into(),
}),
ciphertext: "7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc"
.into(),
kdf: Kdf::Scrypt(Scrypt {
n: 262144,
dklen: 32,
p: 1,
r: 8,
salt: "1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209".into(),
}),
mac: "46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f".into(),
},
name: None,
meta: None,
};
let keyfile: KeyFile = serde_json::from_str(json).unwrap();
assert_eq!(keyfile, expected);
}
#[test]
fn to_and_from_json() {
let file = KeyFile {
id: "8777d9f6-7860-4b9b-88b7-0b57ee6b3a73".into(),
version: Version::V3,
address: Some("6edddfc6349aff20bc6467ccf276c5b52487f7a8".into()),
crypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: "b5a7ec855ec9e2c405371356855fec83".into(),
}),
ciphertext: "7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc"
.into(),
kdf: Kdf::Scrypt(Scrypt {
n: 262144,
dklen: 32,
p: 1,
r: 8,
salt: "1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209".into(),
}),
mac: "46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f".into(),
},
name: Some("Test".to_owned()),
meta: None,
};
let serialized = serde_json::to_string(&file).unwrap();
println!("{}", serialized);
let deserialized = serde_json::from_str(&serialized).unwrap();
assert_eq!(file, deserialized);
}
}

View File

@@ -0,0 +1,48 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
//! Contract interface specification.
mod bytes;
mod cipher;
mod crypto;
mod error;
mod hash;
mod id;
mod kdf;
mod key_file;
mod presale;
mod vault_file;
mod vault_key_file;
mod version;
pub use self::{
bytes::Bytes,
cipher::{Aes128Ctr, Cipher, CipherSer, CipherSerParams},
crypto::{CipherText, Crypto},
error::Error,
hash::{H128, H160, H256},
id::Uuid,
kdf::{Kdf, KdfSer, KdfSerParams, Pbkdf2, Prf, Scrypt},
key_file::{KeyFile, OpaqueKeyFile},
presale::{Encseed, PresaleWallet},
vault_file::VaultFile,
vault_key_file::{
insert_vault_name_to_json_meta, remove_vault_name_from_json_meta, VaultKeyFile,
VaultKeyMeta,
},
version::Version,
};

View File

@@ -1,47 +1,50 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// Parity is free software: you can redistribute it and/or modify
// OpenEthereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// OpenEthereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use std::io::Read;
use super::{Bytes, H160};
use serde_json;
use super::{H160, Bytes};
use std::io::Read;
pub type Encseed = Bytes;
#[derive(Debug, PartialEq, Deserialize)]
pub struct PresaleWallet {
pub encseed: Encseed,
#[serde(rename = "ethaddr")]
pub address: H160,
pub encseed: Encseed,
#[serde(rename = "ethaddr")]
pub address: H160,
}
impl PresaleWallet {
pub fn load<R>(reader: R) -> Result<Self, serde_json::Error> where R: Read {
serde_json::from_reader(reader)
}
pub fn load<R>(reader: R) -> Result<Self, serde_json::Error>
where
R: Read,
{
serde_json::from_reader(reader)
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use serde_json;
use json::{PresaleWallet, H160};
use json::{PresaleWallet, H160};
use serde_json;
use std::str::FromStr;
#[test]
fn presale_wallet() {
let json = r#"
#[test]
fn presale_wallet() {
let json = r#"
{
"encseed": "137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066",
"ethaddr": "ede84640d1a1d3e06902048e67aa7db8d52c2ce1",
@@ -49,18 +52,18 @@ mod tests {
"btcaddr": "1JvqEc6WLhg6GnyrLBe2ztPAU28KRfuseH"
} "#;
let expected = PresaleWallet {
let expected = PresaleWallet {
encseed: "137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066".into(),
address: H160::from_str("ede84640d1a1d3e06902048e67aa7db8d52c2ce1").unwrap(),
};
let wallet: PresaleWallet = serde_json::from_str(json).unwrap();
assert_eq!(expected, wallet);
}
let wallet: PresaleWallet = serde_json::from_str(json).unwrap();
assert_eq!(expected, wallet);
}
#[test]
fn long_presale_wallet() {
let json = r#"
#[test]
fn long_presale_wallet() {
let json = r#"
{
"encseed":
"137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0d",
@@ -69,12 +72,12 @@ mod tests {
"btcaddr": "1JvqEc6WLhg6GnyrLBe2ztPAU28KRfuseH"
} "#;
let expected = PresaleWallet {
let expected = PresaleWallet {
encseed: "137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0d".into(),
address: H160::from_str("ede84640d1a1d3e06902048e67aa7db8d52c2ce1").unwrap(),
};
let wallet: PresaleWallet = serde_json::from_str(json).unwrap();
assert_eq!(expected, wallet);
}
let wallet: PresaleWallet = serde_json::from_str(json).unwrap();
assert_eq!(expected, wallet);
}
}

View File

@@ -0,0 +1,105 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::Crypto;
use serde_json;
use std::io::{Read, Write};
/// Vault meta file
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct VaultFile {
/// Vault password, encrypted with vault password
pub crypto: Crypto,
/// Vault metadata string
pub meta: Option<String>,
}
impl VaultFile {
pub fn load<R>(reader: R) -> Result<Self, serde_json::Error>
where
R: Read,
{
serde_json::from_reader(reader)
}
pub fn write<W>(&self, writer: &mut W) -> Result<(), serde_json::Error>
where
W: Write,
{
serde_json::to_writer(writer, self)
}
}
#[cfg(test)]
mod test {
use json::{Aes128Ctr, Cipher, Crypto, Kdf, Pbkdf2, Prf, VaultFile};
use serde_json;
use std::num::NonZeroU32;
lazy_static! {
static ref ITERATIONS: NonZeroU32 = NonZeroU32::new(1024).expect("1024 > 0; qed");
}
#[test]
fn to_and_from_json() {
let file = VaultFile {
crypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: "0155e3690be19fbfbecabcd440aa284b".into(),
}),
ciphertext: "4d6938a1f49b7782".into(),
kdf: Kdf::Pbkdf2(Pbkdf2 {
c: *ITERATIONS,
dklen: 32,
prf: Prf::HmacSha256,
salt: "b6a9338a7ccd39288a86dba73bfecd9101b4f3db9c9830e7c76afdbd4f6872e5".into(),
}),
mac: "16381463ea11c6eb2239a9f339c2e780516d29d234ce30ac5f166f9080b5a262".into(),
},
meta: Some("{}".into()),
};
let serialized = serde_json::to_string(&file).unwrap();
let deserialized = serde_json::from_str(&serialized).unwrap();
assert_eq!(file, deserialized);
}
#[test]
fn to_and_from_json_no_meta() {
let file = VaultFile {
crypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: "0155e3690be19fbfbecabcd440aa284b".into(),
}),
ciphertext: "4d6938a1f49b7782".into(),
kdf: Kdf::Pbkdf2(Pbkdf2 {
c: *ITERATIONS,
dklen: 32,
prf: Prf::HmacSha256,
salt: "b6a9338a7ccd39288a86dba73bfecd9101b4f3db9c9830e7c76afdbd4f6872e5".into(),
}),
mac: "16381463ea11c6eb2239a9f339c2e780516d29d234ce30ac5f166f9080b5a262".into(),
},
meta: None,
};
let serialized = serde_json::to_string(&file).unwrap();
let deserialized = serde_json::from_str(&serialized).unwrap();
assert_eq!(file, deserialized);
}
}

View File

@@ -0,0 +1,205 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::{Crypto, Uuid, Version, H160};
use serde::de::Error;
use serde_json::{self, error, value::Value};
use std::io::{Read, Write};
/// Meta key name for vault field
const VAULT_NAME_META_KEY: &'static str = "vault";
/// Key file as stored in vaults
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct VaultKeyFile {
/// Key id
pub id: Uuid,
/// Key version
pub version: Version,
/// Secret, encrypted with account password
pub crypto: Crypto,
/// Serialized `VaultKeyMeta`, encrypted with vault password
pub metacrypto: Crypto,
}
/// Data, stored in `VaultKeyFile::metacrypto`
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct VaultKeyMeta {
/// Key address
pub address: H160,
/// Key name
pub name: Option<String>,
/// Key metadata
pub meta: Option<String>,
}
/// Insert vault name to the JSON meta field
pub fn insert_vault_name_to_json_meta(
meta: &str,
vault_name: &str,
) -> Result<String, error::Error> {
let mut meta = if meta.is_empty() {
Value::Object(serde_json::Map::new())
} else {
serde_json::from_str(meta)?
};
if let Some(meta_obj) = meta.as_object_mut() {
meta_obj.insert(
VAULT_NAME_META_KEY.to_owned(),
Value::String(vault_name.to_owned()),
);
serde_json::to_string(meta_obj)
} else {
Err(error::Error::custom(
"Meta is expected to be a serialized JSON object",
))
}
}
/// Remove vault name from the JSON meta field
pub fn remove_vault_name_from_json_meta(meta: &str) -> Result<String, error::Error> {
let mut meta = if meta.is_empty() {
Value::Object(serde_json::Map::new())
} else {
serde_json::from_str(meta)?
};
if let Some(meta_obj) = meta.as_object_mut() {
meta_obj.remove(VAULT_NAME_META_KEY);
serde_json::to_string(meta_obj)
} else {
Err(error::Error::custom(
"Meta is expected to be a serialized JSON object",
))
}
}
impl VaultKeyFile {
pub fn load<R>(reader: R) -> Result<Self, serde_json::Error>
where
R: Read,
{
serde_json::from_reader(reader)
}
pub fn write<W>(&self, writer: &mut W) -> Result<(), serde_json::Error>
where
W: Write,
{
serde_json::to_writer(writer, self)
}
}
impl VaultKeyMeta {
pub fn load(bytes: &[u8]) -> Result<Self, serde_json::Error> {
serde_json::from_slice(&bytes)
}
pub fn write(&self) -> Result<Vec<u8>, serde_json::Error> {
let s = serde_json::to_string(self)?;
Ok(s.as_bytes().into())
}
}
#[cfg(test)]
mod test {
use json::{
insert_vault_name_to_json_meta, remove_vault_name_from_json_meta, Aes128Ctr, Cipher,
Crypto, Kdf, Pbkdf2, Prf, VaultKeyFile, Version,
};
use serde_json;
use std::num::NonZeroU32;
lazy_static! {
static ref ITERATIONS: NonZeroU32 = NonZeroU32::new(10240).expect("10240 > 0; qed");
}
#[test]
fn to_and_from_json() {
let file = VaultKeyFile {
id: "08d82c39-88e3-7a71-6abb-89c8f36c3ceb".into(),
version: Version::V3,
crypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: "fecb968bbc8c7e608a89ebcfe53a41d0".into(),
}),
ciphertext: "4befe0a66d9a4b6fec8e39eb5c90ac5dafdeaab005fff1af665fd1f9af925c91".into(),
kdf: Kdf::Pbkdf2(Pbkdf2 {
c: *ITERATIONS,
dklen: 32,
prf: Prf::HmacSha256,
salt: "f17731e84ecac390546692dbd4ccf6a3a2720dc9652984978381e61c28a471b2".into(),
}),
mac: "7c7c3daafb24cf11eb3079dfb9064a11e92f309a0ee1dd676486bab119e686b7".into(),
},
metacrypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: "9c353fb3f894fc05946843616c26bb3f".into(),
}),
ciphertext: "fef0d113d7576c1702daf380ad6f4c5408389e57991cae2a174facd74bd549338e1014850bddbab7eb486ff5f5c9c5532800c6a6d4db2be2212cd5cd3769244ab230e1f369e8382a9e6d7c0a".into(),
kdf: Kdf::Pbkdf2(Pbkdf2 {
c: *ITERATIONS,
dklen: 32,
prf: Prf::HmacSha256,
salt: "aca82865174a82249a198814b263f43a631f272cbf7ed329d0f0839d259c652a".into(),
}),
mac: "b7413946bfe459d2801268dc331c04b3a84d92be11ef4dd9a507f895e8d9b5bd".into(),
}
};
let serialized = serde_json::to_string(&file).unwrap();
let deserialized = serde_json::from_str(&serialized).unwrap();
assert_eq!(file, deserialized);
}
#[test]
fn vault_name_inserted_to_json_meta() {
assert_eq!(
insert_vault_name_to_json_meta(r#""#, "MyVault").unwrap(),
r#"{"vault":"MyVault"}"#
);
assert_eq!(
insert_vault_name_to_json_meta(r#"{"tags":["kalabala"]}"#, "MyVault").unwrap(),
r#"{"tags":["kalabala"],"vault":"MyVault"}"#
);
}
#[test]
fn vault_name_not_inserted_to_json_meta() {
assert!(insert_vault_name_to_json_meta(r#"///3533"#, "MyVault").is_err());
assert!(insert_vault_name_to_json_meta(r#""string""#, "MyVault").is_err());
}
#[test]
fn vault_name_removed_from_json_meta() {
assert_eq!(
remove_vault_name_from_json_meta(r#"{"vault":"MyVault"}"#).unwrap(),
r#"{}"#
);
assert_eq!(
remove_vault_name_from_json_meta(r#"{"tags":["kalabala"],"vault":"MyVault"}"#).unwrap(),
r#"{"tags":["kalabala"]}"#
);
}
#[test]
fn vault_name_not_removed_from_json_meta() {
assert!(remove_vault_name_from_json_meta(r#"///3533"#).is_err());
assert!(remove_vault_name_from_json_meta(r#""string""#).is_err());
}
}

View File

@@ -0,0 +1,67 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::Error;
use serde::{
de::{Error as SerdeError, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};
use std::fmt;
#[derive(Debug, PartialEq)]
pub enum Version {
V3,
}
impl Serialize for Version {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
Version::V3 => serializer.serialize_u64(3),
}
}
}
impl<'a> Deserialize<'a> for Version {
fn deserialize<D>(deserializer: D) -> Result<Version, D::Error>
where
D: Deserializer<'a>,
{
deserializer.deserialize_any(VersionVisitor)
}
}
struct VersionVisitor;
impl<'a> Visitor<'a> for VersionVisitor {
type Value = Version;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a valid key version identifier")
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where
E: SerdeError,
{
match value {
3 => Ok(Version::V3),
_ => Err(SerdeError::custom(Error::UnsupportedVersion)),
}
}
}

View File

@@ -1,24 +1,23 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// Parity is free software: you can redistribute it and/or modify
// OpenEthereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// OpenEthereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
//! Ethereum key-management.
#![warn(missing_docs)]
extern crate dir;
extern crate itertools;
extern crate libc;
extern crate parking_lot;
@@ -27,15 +26,16 @@ extern crate rustc_hex;
extern crate serde;
extern crate serde_json;
extern crate smallvec;
extern crate time;
extern crate tiny_keccak;
extern crate tempdir;
extern crate time;
extern crate parity_crypto as crypto;
extern crate ethereum_types;
extern crate ethkey as _ethkey;
extern crate parity_crypto as crypto;
extern crate parity_wordlist;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[macro_use]
@@ -58,18 +58,20 @@ mod presale;
mod random;
mod secret_store;
pub use self::account::{SafeAccount, Crypto};
pub use self::error::Error;
pub use self::ethstore::{EthStore, EthMultiStore};
pub use self::import::{import_account, import_accounts, read_geth_accounts};
pub use self::json::OpaqueKeyFile as KeyFile;
pub use self::presale::PresaleWallet;
pub use self::secret_store::{
SecretVaultRef, StoreAccountRef, SimpleSecretStore, SecretStore,
Derivation, IndexDerivation,
pub use self::{
account::{Crypto, SafeAccount},
error::Error,
ethstore::{EthMultiStore, EthStore},
import::{import_account, import_accounts},
json::OpaqueKeyFile as KeyFile,
parity_wordlist::random_phrase,
presale::PresaleWallet,
random::random_string,
secret_store::{
Derivation, IndexDerivation, SecretStore, SecretVaultRef, SimpleSecretStore,
StoreAccountRef,
},
};
pub use self::random::random_string;
pub use self::parity_wordlist::random_phrase;
/// An opaque wrapper for secret.
pub struct OpaqueSecret(::ethkey::Secret);

View File

@@ -0,0 +1,103 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use crypto::{self, pbkdf2, Keccak256};
use ethkey::{Address, KeyPair, Password, Secret};
use json;
use std::{fs, num::NonZeroU32, path::Path};
use Error;
/// Pre-sale wallet.
pub struct PresaleWallet {
iv: [u8; 16],
ciphertext: Vec<u8>,
address: Address,
}
impl From<json::PresaleWallet> for PresaleWallet {
fn from(wallet: json::PresaleWallet) -> Self {
let mut iv = [0u8; 16];
iv.copy_from_slice(&wallet.encseed[..16]);
let mut ciphertext = vec![];
ciphertext.extend_from_slice(&wallet.encseed[16..]);
PresaleWallet {
iv: iv,
ciphertext: ciphertext,
address: Address::from(wallet.address),
}
}
}
impl PresaleWallet {
/// Open a pre-sale wallet.
pub fn open<P>(path: P) -> Result<Self, Error>
where
P: AsRef<Path>,
{
let file = fs::File::open(path)?;
let presale =
json::PresaleWallet::load(file).map_err(|e| Error::InvalidKeyFile(format!("{}", e)))?;
Ok(PresaleWallet::from(presale))
}
/// Decrypt the wallet.
pub fn decrypt(&self, password: &Password) -> Result<KeyPair, Error> {
let mut derived_key = [0u8; 32];
let salt = pbkdf2::Salt(password.as_bytes());
let sec = pbkdf2::Secret(password.as_bytes());
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)
.map_err(|_| Error::InvalidPassword)?;
let unpadded = &key[..len];
let secret = Secret::from_unsafe_slice(&unpadded.keccak256())?;
if let Ok(kp) = KeyPair::from_secret(secret) {
if kp.address() == self.address {
return Ok(kp);
}
}
Err(Error::InvalidPassword)
}
}
#[cfg(test)]
mod tests {
use super::PresaleWallet;
use json;
#[test]
fn test() {
let json = r#"
{
"encseed": "137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066",
"ethaddr": "ede84640d1a1d3e06902048e67aa7db8d52c2ce1",
"email": "123@gmail.com",
"btcaddr": "1JvqEc6WLhg6GnyrLBe2ztPAU28KRfuseH"
} "#;
let wallet = json::PresaleWallet::load(json.as_bytes()).unwrap();
let wallet = PresaleWallet::from(wallet);
assert!(wallet.decrypt(&"123".into()).is_ok());
assert!(wallet.decrypt(&"124".into()).is_err());
}
}

View File

@@ -0,0 +1,47 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use rand::{OsRng, Rng};
pub trait Random {
fn random() -> Self
where
Self: Sized;
}
impl Random for [u8; 16] {
fn random() -> Self {
let mut result = [0u8; 16];
let mut rng = OsRng::new().unwrap();
rng.fill_bytes(&mut result);
result
}
}
impl Random for [u8; 32] {
fn random() -> Self {
let mut result = [0u8; 32];
let mut rng = OsRng::new().unwrap();
rng.fill_bytes(&mut result);
result
}
}
/// 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.gen_ascii_chars().take(length).collect()
}

View File

@@ -0,0 +1,268 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use ethereum_types::H256;
use ethkey::{Address, Message, Password, Public, Secret, Signature};
use json::{OpaqueKeyFile, Uuid};
use std::{
cmp::Ordering,
hash::{Hash, Hasher},
path::PathBuf,
};
use Error;
use OpaqueSecret;
/// Key directory reference
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum SecretVaultRef {
/// Reference to key in root directory
Root,
/// Referenc to key in specific vault
Vault(String),
}
/// Stored account reference
#[derive(Debug, Clone, PartialEq, Eq, Ord)]
pub struct StoreAccountRef {
/// Account address
pub address: Address,
/// Vault reference
pub vault: SecretVaultRef,
}
impl PartialOrd for StoreAccountRef {
fn partial_cmp(&self, other: &StoreAccountRef) -> Option<Ordering> {
Some(
self.address
.cmp(&other.address)
.then_with(|| self.vault.cmp(&other.vault)),
)
}
}
impl ::std::borrow::Borrow<Address> for StoreAccountRef {
fn borrow(&self) -> &Address {
&self.address
}
}
/// Simple Secret Store API
pub trait SimpleSecretStore: Send + Sync {
/// Inserts new accounts to the store (or vault) with given password.
fn insert_account(
&self,
vault: SecretVaultRef,
secret: Secret,
password: &Password,
) -> Result<StoreAccountRef, Error>;
/// Inserts new derived account to the store (or vault) with given password.
fn insert_derived(
&self,
vault: SecretVaultRef,
account_ref: &StoreAccountRef,
password: &Password,
derivation: Derivation,
) -> Result<StoreAccountRef, Error>;
/// Changes accounts password.
fn change_password(
&self,
account: &StoreAccountRef,
old_password: &Password,
new_password: &Password,
) -> Result<(), Error>;
/// Exports key details for account.
fn export_account(
&self,
account: &StoreAccountRef,
password: &Password,
) -> Result<OpaqueKeyFile, Error>;
/// Entirely removes account from the store and underlying storage.
fn remove_account(&self, account: &StoreAccountRef, password: &Password) -> Result<(), Error>;
/// Generates new derived account.
fn generate_derived(
&self,
account_ref: &StoreAccountRef,
password: &Password,
derivation: Derivation,
) -> Result<Address, Error>;
/// Sign a message with given account.
fn sign(
&self,
account: &StoreAccountRef,
password: &Password,
message: &Message,
) -> Result<Signature, Error>;
/// Sign a message with derived account.
fn sign_derived(
&self,
account_ref: &StoreAccountRef,
password: &Password,
derivation: Derivation,
message: &Message,
) -> Result<Signature, Error>;
/// Decrypt a messages with given account.
fn decrypt(
&self,
account: &StoreAccountRef,
password: &Password,
shared_mac: &[u8],
message: &[u8],
) -> Result<Vec<u8>, Error>;
/// Agree on shared key.
fn agree(
&self,
account: &StoreAccountRef,
password: &Password,
other: &Public,
) -> Result<Secret, Error>;
/// Returns all accounts in this secret store.
fn accounts(&self) -> Result<Vec<StoreAccountRef>, Error>;
/// Get reference to some account with given address.
/// This method could be removed if we will guarantee that there is max(1) account for given address.
fn account_ref(&self, address: &Address) -> Result<StoreAccountRef, Error>;
/// Create new vault with given password
fn create_vault(&self, name: &str, password: &Password) -> Result<(), Error>;
/// Open vault with given password
fn open_vault(&self, name: &str, password: &Password) -> Result<(), Error>;
/// Close vault
fn close_vault(&self, name: &str) -> Result<(), Error>;
/// List all vaults
fn list_vaults(&self) -> Result<Vec<String>, Error>;
/// List all currently opened vaults
fn list_opened_vaults(&self) -> Result<Vec<String>, Error>;
/// Change vault password
fn change_vault_password(&self, name: &str, new_password: &Password) -> Result<(), Error>;
/// Cnage account' vault
fn change_account_vault(
&self,
vault: SecretVaultRef,
account: StoreAccountRef,
) -> Result<StoreAccountRef, Error>;
/// Get vault metadata string.
fn get_vault_meta(&self, name: &str) -> Result<String, Error>;
/// Set vault metadata string.
fn set_vault_meta(&self, name: &str, meta: &str) -> Result<(), Error>;
}
/// Secret Store API
pub trait SecretStore: SimpleSecretStore {
/// Returns a raw opaque Secret that can be later used to sign a message.
fn raw_secret(
&self,
account: &StoreAccountRef,
password: &Password,
) -> Result<OpaqueSecret, Error>;
/// Signs a message with raw secret.
fn sign_with_secret(
&self,
secret: &OpaqueSecret,
message: &Message,
) -> Result<Signature, Error> {
Ok(::ethkey::sign(&secret.0, message)?)
}
/// Imports presale wallet
fn import_presale(
&self,
vault: SecretVaultRef,
json: &[u8],
password: &Password,
) -> Result<StoreAccountRef, Error>;
/// Imports existing JSON wallet
fn import_wallet(
&self,
vault: SecretVaultRef,
json: &[u8],
password: &Password,
gen_id: bool,
) -> Result<StoreAccountRef, Error>;
/// Copies account between stores and vaults.
fn copy_account(
&self,
new_store: &dyn SimpleSecretStore,
new_vault: SecretVaultRef,
account: &StoreAccountRef,
password: &Password,
new_password: &Password,
) -> Result<(), Error>;
/// Checks if password matches given account.
fn test_password(&self, account: &StoreAccountRef, password: &Password) -> Result<bool, Error>;
/// Returns a public key for given account.
fn public(&self, account: &StoreAccountRef, password: &Password) -> Result<Public, Error>;
/// Returns uuid of an account.
fn uuid(&self, account: &StoreAccountRef) -> Result<Uuid, Error>;
/// Returns account's name.
fn name(&self, account: &StoreAccountRef) -> Result<String, Error>;
/// Returns account's metadata.
fn meta(&self, account: &StoreAccountRef) -> Result<String, Error>;
/// Modifies account metadata.
fn set_name(&self, account: &StoreAccountRef, name: String) -> Result<(), Error>;
/// Modifies account name.
fn set_meta(&self, account: &StoreAccountRef, meta: String) -> Result<(), Error>;
/// Returns local path of the store.
fn local_path(&self) -> PathBuf;
}
impl StoreAccountRef {
/// Create reference to root account with given address
pub fn root(address: Address) -> Self {
StoreAccountRef::new(SecretVaultRef::Root, address)
}
/// Create reference to vault account with given address
pub fn vault(vault_name: &str, address: Address) -> Self {
StoreAccountRef::new(SecretVaultRef::Vault(vault_name.to_owned()), address)
}
/// Create new account reference
pub fn new(vault_ref: SecretVaultRef, address: Address) -> Self {
StoreAccountRef {
vault: vault_ref,
address: address,
}
}
}
impl Hash for StoreAccountRef {
fn hash<H: Hasher>(&self, state: &mut H) {
self.address.hash(state);
}
}
/// Node in hierarchical derivation.
pub struct IndexDerivation {
/// Node is soft (allows proof of parent from parent node).
pub soft: bool,
/// Index sequence of the node.
pub index: u32,
}
/// Derivation scheme for keys
pub enum Derivation {
/// Hierarchical derivation
Hierarchical(Vec<IndexDerivation>),
/// Hash derivation, soft.
SoftHash(H256),
/// Hash derivation, hard.
HardHash(H256),
}

View File

@@ -0,0 +1,197 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
extern crate ethstore;
extern crate rand;
mod util;
use ethstore::{
accounts_dir::RootDiskDirectory,
ethkey::{verify_address, Generator, KeyPair, Random, Secret},
EthStore, SecretVaultRef, SimpleSecretStore, StoreAccountRef,
};
use util::TransientDir;
#[test]
fn secret_store_create() {
let dir = TransientDir::create().unwrap();
let _ = EthStore::open(Box::new(dir)).unwrap();
}
#[test]
#[should_panic]
fn secret_store_open_not_existing() {
let dir = TransientDir::open();
let _ = EthStore::open(Box::new(dir)).unwrap();
}
fn random_secret() -> Secret {
Random.generate().unwrap().secret().clone()
}
#[test]
fn secret_store_create_account() {
let dir = TransientDir::create().unwrap();
let store = EthStore::open(Box::new(dir)).unwrap();
assert_eq!(store.accounts().unwrap().len(), 0);
assert!(store
.insert_account(SecretVaultRef::Root, random_secret(), &"".into())
.is_ok());
assert_eq!(store.accounts().unwrap().len(), 1);
assert!(store
.insert_account(SecretVaultRef::Root, random_secret(), &"".into())
.is_ok());
assert_eq!(store.accounts().unwrap().len(), 2);
}
#[test]
fn secret_store_sign() {
let dir = TransientDir::create().unwrap();
let store = EthStore::open(Box::new(dir)).unwrap();
assert!(store
.insert_account(SecretVaultRef::Root, random_secret(), &"".into())
.is_ok());
let accounts = store.accounts().unwrap();
assert_eq!(accounts.len(), 1);
assert!(store
.sign(&accounts[0], &"".into(), &Default::default())
.is_ok());
assert!(store
.sign(&accounts[0], &"1".into(), &Default::default())
.is_err());
}
#[test]
fn secret_store_change_password() {
let dir = TransientDir::create().unwrap();
let store = EthStore::open(Box::new(dir)).unwrap();
assert!(store
.insert_account(SecretVaultRef::Root, random_secret(), &"".into())
.is_ok());
let accounts = store.accounts().unwrap();
assert_eq!(accounts.len(), 1);
assert!(store
.sign(&accounts[0], &"".into(), &Default::default())
.is_ok());
assert!(store
.change_password(&accounts[0], &"".into(), &"1".into())
.is_ok());
assert!(store
.sign(&accounts[0], &"".into(), &Default::default())
.is_err());
assert!(store
.sign(&accounts[0], &"1".into(), &Default::default())
.is_ok());
}
#[test]
fn secret_store_remove_account() {
let dir = TransientDir::create().unwrap();
let store = EthStore::open(Box::new(dir)).unwrap();
assert!(store
.insert_account(SecretVaultRef::Root, random_secret(), &"".into())
.is_ok());
let accounts = store.accounts().unwrap();
assert_eq!(accounts.len(), 1);
assert!(store.remove_account(&accounts[0], &"".into()).is_ok());
assert_eq!(store.accounts().unwrap().len(), 0);
assert!(store.remove_account(&accounts[0], &"".into()).is_err());
}
fn test_path() -> &'static str {
match ::std::fs::metadata("ethstore") {
Ok(_) => "ethstore/tests/res/geth_keystore",
Err(_) => "tests/res/geth_keystore",
}
}
fn pat_path() -> &'static str {
match ::std::fs::metadata("ethstore") {
Ok(_) => "ethstore/tests/res/pat",
Err(_) => "tests/res/pat",
}
}
fn ciphertext_path() -> &'static str {
match ::std::fs::metadata("ethstore") {
Ok(_) => "ethstore/tests/res/ciphertext",
Err(_) => "tests/res/ciphertext",
}
}
#[test]
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("3f49624084b67849c7b4e805c5988c21a430f9d9".into()),
StoreAccountRef::root("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf".into()),
StoreAccountRef::root("63121b431a52f8043c16fcf0d1df9cb7b5f66649".into()),
]
);
}
#[test]
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("3f49624084b67849c7b4e805c5988c21a430f9d9".into()),
StoreAccountRef::root("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf".into()),
]
);
}
#[test]
fn test_decrypting_files_with_short_ciphertext() {
// 31e9d1e6d844bd3a536800ef8d8be6a9975db509, 30
let kp1 = KeyPair::from_secret(
"000081c29e8142bb6a81bef5a92bda7a8328a5c85bb2f9542e76f9b0f94fc018"
.parse()
.unwrap(),
)
.unwrap();
// d1e64e5480bfaf733ba7d48712decb8227797a4e , 31
let kp2 = KeyPair::from_secret(
"00fa7b3db73dc7dfdf8c5fbdb796d741e4488628c41fc4febd9160a866ba0f35"
.parse()
.unwrap(),
)
.unwrap();
let dir = RootDiskDirectory::at(ciphertext_path());
let store = EthStore::open(Box::new(dir)).unwrap();
let accounts = store.accounts().unwrap();
assert_eq!(
accounts,
vec![
StoreAccountRef::root("31e9d1e6d844bd3a536800ef8d8be6a9975db509".into()),
StoreAccountRef::root("d1e64e5480bfaf733ba7d48712decb8227797a4e".into()),
]
);
let message = Default::default();
let s1 = store.sign(&accounts[0], &"foo".into(), &message).unwrap();
let s2 = store.sign(&accounts[1], &"foo".into(), &message).unwrap();
assert!(verify_address(&accounts[0].address, &s1, &message).unwrap());
assert!(verify_address(&kp1.address(), &s1, &message).unwrap());
assert!(verify_address(&kp2.address(), &s2, &message).unwrap());
}

View File

@@ -1,18 +1,18 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// Parity is free software: you can redistribute it and/or modify
// OpenEthereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// OpenEthereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
mod transient_dir;

View File

@@ -0,0 +1,82 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use ethstore::{
accounts_dir::{KeyDirectory, RootDiskDirectory},
Error, SafeAccount,
};
use rand::{OsRng, Rng};
use std::{env, fs, path::PathBuf};
pub fn random_dir() -> PathBuf {
let mut rng = OsRng::new().unwrap();
let mut dir = env::temp_dir();
dir.push(format!("{:x}-{:x}", rng.next_u64(), rng.next_u64()));
dir
}
pub struct TransientDir {
dir: RootDiskDirectory,
path: PathBuf,
}
impl TransientDir {
pub fn create() -> Result<Self, Error> {
let path = random_dir();
let result = TransientDir {
dir: RootDiskDirectory::create(&path)?,
path: path,
};
Ok(result)
}
pub fn open() -> Self {
let path = random_dir();
TransientDir {
dir: RootDiskDirectory::at(&path),
path: path,
}
}
}
impl Drop for TransientDir {
fn drop(&mut self) {
fs::remove_dir_all(&self.path).expect("Expected to remove temp dir");
}
}
impl KeyDirectory for TransientDir {
fn load(&self) -> Result<Vec<SafeAccount>, Error> {
self.dir.load()
}
fn update(&self, account: SafeAccount) -> Result<SafeAccount, Error> {
self.dir.update(account)
}
fn insert(&self, account: SafeAccount) -> Result<SafeAccount, Error> {
self.dir.insert(account)
}
fn remove(&self, account: &SafeAccount) -> Result<(), Error> {
self.dir.remove(account)
}
fn unique_repr(&self) -> Result<u64, Error> {
self.dir.unique_repr()
}
}

View File

@@ -0,0 +1,71 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
//! Account Metadata
use std::{collections::HashMap, time::Instant};
use ethkey::{Address, Password};
use serde_derive::{Deserialize, Serialize};
use serde_json;
/// Type of unlock.
#[derive(Clone, PartialEq)]
pub enum Unlock {
/// If account is unlocked temporarily, it should be locked after first usage.
OneTime,
/// Account unlocked permanently can always sign message.
/// Use with caution.
Perm,
/// Account unlocked with a timeout
Timed(Instant),
}
/// Data associated with account.
#[derive(Clone)]
pub struct AccountData {
pub unlock: Unlock,
pub password: Password,
}
/// Collected account metadata
#[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct AccountMeta {
/// The name of the account.
pub name: String,
/// The rest of the metadata of the account.
pub meta: String,
/// The 128-bit Uuid of the account, if it has one (brain-wallets don't).
pub uuid: Option<String>,
}
impl AccountMeta {
/// Read a hash map of Address -> AccountMeta
pub fn read<R>(reader: R) -> Result<HashMap<Address, Self>, serde_json::Error>
where
R: ::std::io::Read,
{
serde_json::from_reader(reader)
}
/// Write a hash map of Address -> AccountMeta
pub fn write<W>(m: &HashMap<Address, Self>, writer: &mut W) -> Result<(), serde_json::Error>
where
W: ::std::io::Write,
{
serde_json::to_writer(writer, m)
}
}

46
accounts/src/error.rs Normal file
View File

@@ -0,0 +1,46 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use std::fmt;
use ethstore::Error as SSError;
/// Signing error
#[derive(Debug)]
pub enum SignError {
/// Account is not unlocked
NotUnlocked,
/// Account does not exist.
NotFound,
/// Low-level error from store
SStore(SSError),
}
impl fmt::Display for SignError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
SignError::NotUnlocked => write!(f, "Account is locked"),
SignError::NotFound => write!(f, "Account does not exist"),
SignError::SStore(ref e) => write!(f, "{}", e),
}
}
}
impl From<SSError> for SignError {
fn from(e: SSError) -> Self {
SignError::SStore(e)
}
}

841
accounts/src/lib.rs Normal file
View File

@@ -0,0 +1,841 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
#![warn(missing_docs)]
//! Account management.
mod account_data;
mod error;
mod stores;
use self::{
account_data::{AccountData, Unlock},
stores::AddressBook,
};
use std::{
collections::HashMap,
time::{Duration, Instant},
};
use ethkey::{Address, Generator, Message, Password, Public, Random, Secret};
use ethstore::{
accounts_dir::MemoryDirectory, random_string, EthMultiStore, EthStore, OpaqueSecret,
SecretStore, SecretVaultRef, SimpleSecretStore, StoreAccountRef,
};
use log::*;
use parking_lot::RwLock;
pub use ethkey::Signature;
pub use ethstore::{Derivation, Error, IndexDerivation, KeyFile};
pub use self::{account_data::AccountMeta, error::SignError};
type AccountToken = Password;
/// Account management settings.
#[derive(Debug, Default)]
pub struct AccountProviderSettings {
/// Store raw account secret when unlocking the account permanently.
pub unlock_keep_secret: bool,
/// Disallowed accounts.
pub blacklisted_accounts: Vec<Address>,
}
/// Account management.
/// Responsible for unlocking accounts.
pub struct AccountProvider {
/// For performance reasons some methods can re-use unlocked secrets.
unlocked_secrets: RwLock<HashMap<StoreAccountRef, OpaqueSecret>>,
/// Unlocked account data.
unlocked: RwLock<HashMap<StoreAccountRef, AccountData>>,
/// Address book.
address_book: RwLock<AddressBook>,
/// Accounts on disk
sstore: Box<dyn SecretStore>,
/// Accounts unlocked with rolling tokens
transient_sstore: EthMultiStore,
/// When unlocking account permanently we additionally keep a raw secret in memory
/// to increase the performance of transaction signing.
unlock_keep_secret: bool,
/// Disallowed accounts.
blacklisted_accounts: Vec<Address>,
}
fn transient_sstore() -> EthMultiStore {
EthMultiStore::open(Box::new(MemoryDirectory::default()))
.expect("MemoryDirectory load always succeeds; qed")
}
impl AccountProvider {
/// Creates new account provider.
pub fn new(sstore: Box<dyn SecretStore>, settings: AccountProviderSettings) -> Self {
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",
account.address);
}
}
// Remove blacklisted accounts from address book.
let mut address_book = AddressBook::new(&sstore.local_path());
for addr in &settings.blacklisted_accounts {
address_book.remove(*addr);
}
AccountProvider {
unlocked_secrets: RwLock::new(HashMap::new()),
unlocked: RwLock::new(HashMap::new()),
address_book: RwLock::new(address_book),
sstore: sstore,
transient_sstore: transient_sstore(),
unlock_keep_secret: settings.unlock_keep_secret,
blacklisted_accounts: settings.blacklisted_accounts,
}
}
/// Creates not disk backed provider.
pub fn transient_provider() -> Self {
AccountProvider {
unlocked_secrets: RwLock::new(HashMap::new()),
unlocked: RwLock::new(HashMap::new()),
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(),
unlock_keep_secret: false,
blacklisted_accounts: vec![],
}
}
/// Creates new random account.
pub fn new_account(&self, password: &Password) -> Result<Address, Error> {
self.new_account_and_public(password).map(|d| d.0)
}
/// Creates new random account and returns address and public key
pub fn new_account_and_public(&self, password: &Password) -> Result<(Address, Public), Error> {
let acc = Random
.generate()
.expect("secp context has generation capabilities; qed");
let public = acc.public().clone();
let secret = acc.secret().clone();
let account = self
.sstore
.insert_account(SecretVaultRef::Root, secret, password)?;
Ok((account.address, public))
}
/// Inserts new account into underlying store.
/// Does not unlock account!
pub fn insert_account(&self, secret: Secret, password: &Password) -> Result<Address, Error> {
let account = self
.sstore
.insert_account(SecretVaultRef::Root, secret, password)?;
if self.blacklisted_accounts.contains(&account.address) {
self.sstore.remove_account(&account, password)?;
return Err(Error::InvalidAccount.into());
}
Ok(account.address)
}
/// Generates new derived account based on the existing one
/// If password is not provided, account must be unlocked
/// New account will be created with the same password (if save: true)
pub fn derive_account(
&self,
address: &Address,
password: Option<Password>,
derivation: Derivation,
save: bool,
) -> Result<Address, SignError> {
let account = self.sstore.account_ref(&address)?;
let password = password
.map(Ok)
.unwrap_or_else(|| self.password(&account))?;
Ok(if save {
self.sstore
.insert_derived(SecretVaultRef::Root, &account, &password, derivation)?
.address
} else {
self.sstore
.generate_derived(&account, &password, derivation)?
})
}
/// Import a new presale wallet.
pub fn import_presale(
&self,
presale_json: &[u8],
password: &Password,
) -> Result<Address, Error> {
let account = self
.sstore
.import_presale(SecretVaultRef::Root, presale_json, password)?;
Ok(Address::from(account.address).into())
}
/// Import a new wallet.
pub fn import_wallet(
&self,
json: &[u8],
password: &Password,
gen_id: bool,
) -> Result<Address, Error> {
let account = self
.sstore
.import_wallet(SecretVaultRef::Root, json, password, gen_id)?;
if self.blacklisted_accounts.contains(&account.address) {
self.sstore.remove_account(&account, password)?;
return Err(Error::InvalidAccount.into());
}
Ok(Address::from(account.address).into())
}
/// Checks whether an account with a given address is present.
pub fn has_account(&self, address: Address) -> bool {
self.sstore.account_ref(&address).is_ok() && !self.blacklisted_accounts.contains(&address)
}
/// Returns addresses of all accounts.
pub fn accounts(&self) -> Result<Vec<Address>, Error> {
let accounts = self.sstore.accounts()?;
Ok(accounts
.into_iter()
.map(|a| a.address)
.filter(|address| !self.blacklisted_accounts.contains(address))
.collect())
}
/// Returns the address of default account.
pub fn default_account(&self) -> Result<Address, Error> {
Ok(self.accounts()?.first().cloned().unwrap_or_default())
}
/// Returns each address along with metadata.
pub fn addresses_info(&self) -> HashMap<Address, AccountMeta> {
self.address_book.read().get()
}
/// Returns each address along with metadata.
pub fn set_address_name(&self, account: Address, name: String) {
self.address_book.write().set_name(account, name)
}
/// Returns each address along with metadata.
pub fn set_address_meta(&self, account: Address, meta: String) {
self.address_book.write().set_meta(account, meta)
}
/// Removes and address from the address book
pub fn remove_address(&self, addr: Address) {
self.address_book.write().remove(addr)
}
/// Returns each account along with name and meta.
pub fn accounts_info(&self) -> Result<HashMap<Address, AccountMeta>, Error> {
let r = self
.sstore
.accounts()?
.into_iter()
.filter(|a| !self.blacklisted_accounts.contains(&a.address))
.map(|a| {
(
a.address.clone(),
self.account_meta(a.address).ok().unwrap_or_default(),
)
})
.collect();
Ok(r)
}
/// 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
})
}
/// Returns account public key.
pub fn account_public(&self, address: Address, password: &Password) -> Result<Public, Error> {
self.sstore
.public(&self.sstore.account_ref(&address)?, password)
}
/// Returns each account along with name and meta.
pub fn set_account_name(&self, address: Address, name: String) -> Result<(), Error> {
self.sstore
.set_name(&self.sstore.account_ref(&address)?, name)?;
Ok(())
}
/// Returns each account along with name and meta.
pub fn set_account_meta(&self, address: Address, meta: String) -> Result<(), Error> {
self.sstore
.set_meta(&self.sstore.account_ref(&address)?, meta)?;
Ok(())
}
/// Returns `true` if the password for `account` is `password`. `false` if not.
pub fn test_password(&self, address: &Address, password: &Password) -> Result<bool, Error> {
self.sstore
.test_password(&self.sstore.account_ref(&address)?, password)
.map_err(Into::into)
}
/// Permanently removes an account.
pub fn kill_account(&self, address: &Address, password: &Password) -> Result<(), Error> {
self.sstore
.remove_account(&self.sstore.account_ref(&address)?, &password)?;
Ok(())
}
/// Changes the password of `account` from `password` to `new_password`. Fails if incorrect `password` given.
pub fn change_password(
&self,
address: &Address,
password: Password,
new_password: Password,
) -> Result<(), Error> {
self.sstore
.change_password(&self.sstore.account_ref(address)?, &password, &new_password)
}
/// Exports an account for given address.
pub fn export_account(&self, address: &Address, password: Password) -> Result<KeyFile, Error> {
self.sstore
.export_account(&self.sstore.account_ref(address)?, &password)
}
/// Helper method used for unlocking accounts.
fn unlock_account(
&self,
address: Address,
password: Password,
unlock: Unlock,
) -> Result<(), Error> {
let account = self.sstore.account_ref(&address)?;
// check if account is already unlocked permanently, if it is, do nothing
let mut unlocked = self.unlocked.write();
if let Some(data) = unlocked.get(&account) {
if let Unlock::Perm = data.unlock {
return Ok(());
}
}
if self.unlock_keep_secret && unlock == Unlock::Perm {
// verify password and get the secret
let secret = self.sstore.raw_secret(&account, &password)?;
self.unlocked_secrets
.write()
.insert(account.clone(), secret);
} else {
// verify password by signing dump message
// result may be discarded
let _ = self.sstore.sign(&account, &password, &Default::default())?;
}
let data = AccountData {
unlock: unlock,
password: password,
};
unlocked.insert(account, data);
Ok(())
}
fn password(&self, account: &StoreAccountRef) -> Result<Password, SignError> {
let mut unlocked = self.unlocked.write();
let data = unlocked.get(account).ok_or(SignError::NotUnlocked)?.clone();
if let Unlock::OneTime = data.unlock {
unlocked
.remove(account)
.expect("data exists: so key must exist: qed");
}
if let Unlock::Timed(ref end) = data.unlock {
if Instant::now() > *end {
unlocked
.remove(account)
.expect("data exists: so key must exist: qed");
return Err(SignError::NotUnlocked);
}
}
Ok(data.password)
}
/// Unlocks account permanently.
pub fn unlock_account_permanently(
&self,
account: Address,
password: Password,
) -> Result<(), Error> {
self.unlock_account(account, password, Unlock::Perm)
}
/// Unlocks account temporarily (for one signing).
pub fn unlock_account_temporarily(
&self,
account: Address,
password: Password,
) -> Result<(), Error> {
self.unlock_account(account, password, Unlock::OneTime)
}
/// Unlocks account temporarily with a timeout.
pub fn unlock_account_timed(
&self,
account: Address,
password: Password,
duration: Duration,
) -> Result<(), Error> {
self.unlock_account(account, password, Unlock::Timed(Instant::now() + duration))
}
/// Checks if given account is unlocked
pub fn is_unlocked(&self, address: &Address) -> bool {
let unlocked = self.unlocked.read();
let unlocked_secrets = self.unlocked_secrets.read();
self.sstore
.account_ref(address)
.map(|r| unlocked.get(&r).is_some() || unlocked_secrets.get(&r).is_some())
.unwrap_or(false)
}
/// Checks if given account is unlocked permanently
pub fn is_unlocked_permanently(&self, address: &Address) -> bool {
let unlocked = self.unlocked.read();
self.sstore
.account_ref(address)
.map(|r| {
unlocked
.get(&r)
.map_or(false, |account| account.unlock == Unlock::Perm)
})
.unwrap_or(false)
}
/// Signs the message. If password is not provided the account must be unlocked.
pub fn sign(
&self,
address: Address,
password: Option<Password>,
message: Message,
) -> Result<Signature, SignError> {
let account = self.sstore.account_ref(&address)?;
match self.unlocked_secrets.read().get(&account) {
Some(secret) => Ok(self.sstore.sign_with_secret(&secret, &message)?),
None => {
let password = password
.map(Ok)
.unwrap_or_else(|| self.password(&account))?;
Ok(self.sstore.sign(&account, &password, &message)?)
}
}
}
/// Signs message using the derived secret. If password is not provided the account must be unlocked.
pub fn sign_derived(
&self,
address: &Address,
password: Option<Password>,
derivation: Derivation,
message: Message,
) -> Result<Signature, SignError> {
let account = self.sstore.account_ref(address)?;
let password = password
.map(Ok)
.unwrap_or_else(|| self.password(&account))?;
Ok(self
.sstore
.sign_derived(&account, &password, derivation, &message)?)
}
/// Signs given message with supplied token. Returns a token to use in next signing within this session.
pub fn sign_with_token(
&self,
address: Address,
token: AccountToken,
message: Message,
) -> Result<(Signature, AccountToken), SignError> {
let account = self.sstore.account_ref(&address)?;
let is_std_password = self.sstore.test_password(&account, &token)?;
let new_token = Password::from(random_string(16));
let signature = if is_std_password {
// Insert to transient store
self.sstore.copy_account(
&self.transient_sstore,
SecretVaultRef::Root,
&account,
&token,
&new_token,
)?;
// sign
self.sstore.sign(&account, &token, &message)?
} else {
// check transient store
self.transient_sstore
.change_password(&account, &token, &new_token)?;
// and sign
self.transient_sstore.sign(&account, &new_token, &message)?
};
Ok((signature, new_token))
}
/// Decrypts a message with given token. Returns a token to use in next operation for this account.
pub fn decrypt_with_token(
&self,
address: Address,
token: AccountToken,
shared_mac: &[u8],
message: &[u8],
) -> Result<(Vec<u8>, AccountToken), SignError> {
let account = self.sstore.account_ref(&address)?;
let is_std_password = self.sstore.test_password(&account, &token)?;
let new_token = Password::from(random_string(16));
let message = if is_std_password {
// Insert to transient store
self.sstore.copy_account(
&self.transient_sstore,
SecretVaultRef::Root,
&account,
&token,
&new_token,
)?;
// decrypt
self.sstore.decrypt(&account, &token, shared_mac, message)?
} else {
// check transient store
self.transient_sstore
.change_password(&account, &token, &new_token)?;
// and decrypt
self.transient_sstore
.decrypt(&account, &token, shared_mac, message)?
};
Ok((message, new_token))
}
/// Decrypts a message. If password is not provided the account must be unlocked.
pub fn decrypt(
&self,
address: Address,
password: Option<Password>,
shared_mac: &[u8],
message: &[u8],
) -> Result<Vec<u8>, SignError> {
let account = self.sstore.account_ref(&address)?;
let password = password
.map(Ok)
.unwrap_or_else(|| self.password(&account))?;
Ok(self
.sstore
.decrypt(&account, &password, shared_mac, message)?)
}
/// Agree on shared key.
pub fn agree(
&self,
address: Address,
password: Option<Password>,
other_public: &Public,
) -> Result<Secret, SignError> {
let account = self.sstore.account_ref(&address)?;
let password = password
.map(Ok)
.unwrap_or_else(|| self.password(&account))?;
Ok(self.sstore.agree(&account, &password, other_public)?)
}
/// Create new vault.
pub fn create_vault(&self, name: &str, password: &Password) -> Result<(), Error> {
self.sstore.create_vault(name, password).map_err(Into::into)
}
/// Open existing vault.
pub fn open_vault(&self, name: &str, password: &Password) -> Result<(), Error> {
self.sstore.open_vault(name, password).map_err(Into::into)
}
/// Close previously opened vault.
pub fn close_vault(&self, name: &str) -> Result<(), Error> {
self.sstore.close_vault(name).map_err(Into::into)
}
/// List all vaults
pub fn list_vaults(&self) -> Result<Vec<String>, Error> {
self.sstore.list_vaults().map_err(Into::into)
}
/// List all currently opened vaults
pub fn list_opened_vaults(&self) -> Result<Vec<String>, Error> {
self.sstore.list_opened_vaults().map_err(Into::into)
}
/// Change vault password.
pub fn change_vault_password(&self, name: &str, new_password: &Password) -> Result<(), Error> {
self.sstore
.change_vault_password(name, new_password)
.map_err(Into::into)
}
/// Change vault of the given address.
pub fn change_vault(&self, address: Address, new_vault: &str) -> Result<(), Error> {
let new_vault_ref = if new_vault.is_empty() {
SecretVaultRef::Root
} else {
SecretVaultRef::Vault(new_vault.to_owned())
};
let old_account_ref = self.sstore.account_ref(&address)?;
self.sstore
.change_account_vault(new_vault_ref, old_account_ref)
.map_err(Into::into)
.map(|_| ())
}
/// Get vault metadata string.
pub fn get_vault_meta(&self, name: &str) -> Result<String, Error> {
self.sstore.get_vault_meta(name).map_err(Into::into)
}
/// Set vault metadata string.
pub fn set_vault_meta(&self, name: &str, meta: &str) -> Result<(), Error> {
self.sstore.set_vault_meta(name, meta).map_err(Into::into)
}
}
#[cfg(test)]
mod tests {
use super::{AccountProvider, Unlock};
use ethereum_types::H256;
use ethkey::{Address, Generator, Random};
use ethstore::{Derivation, StoreAccountRef};
use std::time::{Duration, Instant};
#[test]
fn unlock_account_temp() {
let kp = Random.generate().unwrap();
let ap = AccountProvider::transient_provider();
assert!(ap
.insert_account(kp.secret().clone(), &"test".into())
.is_ok());
assert!(ap
.unlock_account_temporarily(kp.address(), "test1".into())
.is_err());
assert!(ap
.unlock_account_temporarily(kp.address(), "test".into())
.is_ok());
assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
assert!(ap.sign(kp.address(), None, Default::default()).is_err());
}
#[test]
fn derived_account_nosave() {
let kp = Random.generate().unwrap();
let ap = AccountProvider::transient_provider();
assert!(ap
.insert_account(kp.secret().clone(), &"base".into())
.is_ok());
assert!(ap
.unlock_account_permanently(kp.address(), "base".into())
.is_ok());
let derived_addr = ap
.derive_account(
&kp.address(),
None,
Derivation::SoftHash(H256::from(999)),
false,
)
.expect("Derivation should not fail");
assert!(
ap.unlock_account_permanently(derived_addr, "base".into())
.is_err(),
"There should be an error because account is not supposed to be saved"
);
}
#[test]
fn derived_account_save() {
let kp = Random.generate().unwrap();
let ap = AccountProvider::transient_provider();
assert!(ap
.insert_account(kp.secret().clone(), &"base".into())
.is_ok());
assert!(ap
.unlock_account_permanently(kp.address(), "base".into())
.is_ok());
let derived_addr = ap
.derive_account(
&kp.address(),
None,
Derivation::SoftHash(H256::from(999)),
true,
)
.expect("Derivation should not fail");
assert!(
ap.unlock_account_permanently(derived_addr, "base_wrong".into())
.is_err(),
"There should be an error because password is invalid"
);
assert!(
ap.unlock_account_permanently(derived_addr, "base".into())
.is_ok(),
"Should be ok because account is saved and password is valid"
);
}
#[test]
fn derived_account_sign() {
let kp = Random.generate().unwrap();
let ap = AccountProvider::transient_provider();
assert!(ap
.insert_account(kp.secret().clone(), &"base".into())
.is_ok());
assert!(ap
.unlock_account_permanently(kp.address(), "base".into())
.is_ok());
let derived_addr = ap
.derive_account(
&kp.address(),
None,
Derivation::SoftHash(H256::from(1999)),
true,
)
.expect("Derivation should not fail");
ap.unlock_account_permanently(derived_addr, "base".into())
.expect("Should be ok because account is saved and password is valid");
let msg = Default::default();
let signed_msg1 = ap
.sign(derived_addr, None, msg)
.expect("Signing with existing unlocked account should not fail");
let signed_msg2 = ap
.sign_derived(
&kp.address(),
None,
Derivation::SoftHash(H256::from(1999)),
msg,
)
.expect("Derived signing with existing unlocked account should not fail");
assert_eq!(signed_msg1, signed_msg2, "Signed messages should match");
}
#[test]
fn unlock_account_perm() {
let kp = Random.generate().unwrap();
let ap = AccountProvider::transient_provider();
assert!(ap
.insert_account(kp.secret().clone(), &"test".into())
.is_ok());
assert!(ap
.unlock_account_permanently(kp.address(), "test1".into())
.is_err());
assert!(ap
.unlock_account_permanently(kp.address(), "test".into())
.is_ok());
assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
assert!(ap
.unlock_account_temporarily(kp.address(), "test".into())
.is_ok());
assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
}
#[test]
fn unlock_account_timer() {
let kp = Random.generate().unwrap();
let ap = AccountProvider::transient_provider();
assert!(ap
.insert_account(kp.secret().clone(), &"test".into())
.is_ok());
assert!(ap
.unlock_account_timed(kp.address(), "test1".into(), Duration::from_secs(60))
.is_err());
assert!(ap
.unlock_account_timed(kp.address(), "test".into(), Duration::from_secs(60))
.is_ok());
assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
ap.unlocked
.write()
.get_mut(&StoreAccountRef::root(kp.address()))
.unwrap()
.unlock = Unlock::Timed(Instant::now());
assert!(ap.sign(kp.address(), None, Default::default()).is_err());
}
#[test]
fn should_sign_and_return_token() {
// given
let kp = Random.generate().unwrap();
let ap = AccountProvider::transient_provider();
assert!(ap
.insert_account(kp.secret().clone(), &"test".into())
.is_ok());
// when
let (_signature, token) = ap
.sign_with_token(kp.address(), "test".into(), Default::default())
.unwrap();
// then
ap.sign_with_token(kp.address(), token.clone(), Default::default())
.expect("First usage of token should be correct.");
assert!(
ap.sign_with_token(kp.address(), token, Default::default())
.is_err(),
"Second usage of the same token should fail."
);
}
#[test]
fn should_not_return_blacklisted_account() {
// given
let mut ap = AccountProvider::transient_provider();
let acc = ap.new_account(&"test".into()).unwrap();
ap.blacklisted_accounts = vec![acc];
// then
assert_eq!(
ap.accounts_info()
.unwrap()
.keys()
.cloned()
.collect::<Vec<Address>>(),
vec![]
);
assert_eq!(ap.accounts().unwrap(), vec![]);
}
}

237
accounts/src/stores.rs Normal file
View File

@@ -0,0 +1,237 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
//! Address Book Store
use std::{
collections::HashMap,
fmt, fs, hash, ops,
path::{Path, PathBuf},
};
use ethkey::Address;
use log::{trace, warn};
use crate::AccountMeta;
/// Disk-backed map from Address to String. Uses JSON.
pub struct AddressBook {
cache: DiskMap<Address, AccountMeta>,
}
impl AddressBook {
/// Creates new address book at given directory.
pub fn new(path: &Path) -> Self {
let mut r = AddressBook {
cache: DiskMap::new(path, "address_book.json"),
};
r.cache.revert(AccountMeta::read);
r
}
/// Creates transient address book (no changes are saved to disk).
pub fn transient() -> Self {
AddressBook {
cache: DiskMap::transient(),
}
}
/// Get the address book.
pub fn get(&self) -> HashMap<Address, AccountMeta> {
self.cache.clone()
}
fn save(&self) {
self.cache.save(AccountMeta::write)
}
/// Sets new name for given address.
pub fn set_name(&mut self, a: Address, name: String) {
{
let x = self.cache.entry(a).or_insert_with(|| AccountMeta {
name: Default::default(),
meta: "{}".to_owned(),
uuid: None,
});
x.name = name;
}
self.save();
}
/// Sets new meta for given address.
pub fn set_meta(&mut self, a: Address, meta: String) {
{
let x = self.cache.entry(a).or_insert_with(|| AccountMeta {
name: "Anonymous".to_owned(),
meta: Default::default(),
uuid: None,
});
x.meta = meta;
}
self.save();
}
/// Removes an entry
pub fn remove(&mut self, a: Address) {
self.cache.remove(&a);
self.save();
}
}
/// Disk-serializable HashMap
#[derive(Debug)]
struct DiskMap<K: hash::Hash + Eq, V> {
path: PathBuf,
cache: HashMap<K, V>,
transient: bool,
}
impl<K: hash::Hash + Eq, V> ops::Deref for DiskMap<K, V> {
type Target = HashMap<K, V>;
fn deref(&self) -> &Self::Target {
&self.cache
}
}
impl<K: hash::Hash + Eq, V> ops::DerefMut for DiskMap<K, V> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.cache
}
}
impl<K: hash::Hash + Eq, V> DiskMap<K, V> {
pub fn new(path: &Path, file_name: &str) -> Self {
let mut path = path.to_owned();
path.push(file_name);
trace!(target: "diskmap", "path={:?}", path);
DiskMap {
path: path,
cache: HashMap::new(),
transient: false,
}
}
pub fn transient() -> Self {
let mut map = DiskMap::new(&PathBuf::new(), "diskmap.json".into());
map.transient = true;
map
}
fn revert<F, E>(&mut self, read: F)
where
F: Fn(fs::File) -> Result<HashMap<K, V>, E>,
E: fmt::Display,
{
if self.transient {
return;
}
trace!(target: "diskmap", "revert {:?}", self.path);
let _ = fs::File::open(self.path.clone())
.map_err(|e| trace!(target: "diskmap", "Couldn't open disk map: {}", e))
.and_then(|f| {
read(f).map_err(|e| warn!(target: "diskmap", "Couldn't read disk map: {}", e))
})
.and_then(|m| {
self.cache = m;
Ok(())
});
}
fn save<F, E>(&self, write: F)
where
F: Fn(&HashMap<K, V>, &mut fs::File) -> Result<(), E>,
E: fmt::Display,
{
if self.transient {
return;
}
trace!(target: "diskmap", "save {:?}", self.path);
let _ = fs::File::create(self.path.clone())
.map_err(|e| warn!(target: "diskmap", "Couldn't open disk map for writing: {}", e))
.and_then(|mut f| {
write(&self.cache, &mut f)
.map_err(|e| warn!(target: "diskmap", "Couldn't write to disk map: {}", e))
});
}
}
#[cfg(test)]
mod tests {
use super::AddressBook;
use crate::account_data::AccountMeta;
use std::collections::HashMap;
use tempdir::TempDir;
#[test]
fn should_save_and_reload_address_book() {
let tempdir = TempDir::new("").unwrap();
let mut b = AddressBook::new(tempdir.path());
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![(
1,
AccountMeta {
name: "One".to_owned(),
meta: "{1:1}".to_owned(),
uuid: None
}
)]
.into_iter()
.map(|(a, b)| (a.into(), b))
.collect::<HashMap<_, _>>()
);
}
#[test]
fn should_remove_address() {
let tempdir = TempDir::new("").unwrap();
let mut b = AddressBook::new(tempdir.path());
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![
(
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

@@ -1,4 +1,5 @@
[package]
description = "Parity Ethereum Chain Specification"
name = "chainspec"
version = "0.1.0"
authors = ["Marek Kotewicz <marek@parity.io>"]

View File

@@ -1,49 +1,51 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// Parity is free software: you can redistribute it and/or modify
// OpenEthereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// OpenEthereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
extern crate serde_json;
extern crate ethjson;
extern crate serde_json;
use std::{fs, env, process};
use ethjson::spec::Spec;
use std::{env, fs, process};
fn quit(s: &str) -> ! {
println!("{}", s);
process::exit(1);
println!("{}", s);
process::exit(1);
}
fn main() {
let mut args = env::args();
if args.len() != 2 {
quit("You need to specify chainspec.json\n\
let mut args = env::args();
if args.len() != 2 {
quit(
"You need to specify chainspec.json\n\
\n\
./chainspec <chainspec.json>");
}
./chainspec <chainspec.json>",
);
}
let path = args.nth(1).expect("args.len() == 2; qed");
let file = match fs::File::open(&path) {
Ok(file) => file,
Err(_) => quit(&format!("{} could not be opened", path)),
};
let path = args.nth(1).expect("args.len() == 2; qed");
let file = match fs::File::open(&path) {
Ok(file) => file,
Err(_) => quit(&format!("{} could not be opened", path)),
};
let spec: Result<Spec, _> = serde_json::from_reader(file);
let spec: Result<Spec, _> = serde_json::from_reader(file);
if let Err(err) = spec {
quit(&format!("{} {}", path, err.to_string()));
}
if let Err(err) = spec {
quit(&format!("{} {}", path, err.to_string()));
}
println!("{} is valid", path);
println!("{} is valid", path);
}

14
cli-signer/Cargo.toml Normal file
View File

@@ -0,0 +1,14 @@
[package]
description = "OpenEthereum CLI Signer Tool"
homepage = "https://github.com/openethereum/openethereum"
license = "GPL-3.0"
name = "cli-signer"
version = "1.4.0"
authors = ["Parity <admin@parity.io>"]
[dependencies]
ethereum-types = "0.4"
futures = "0.1"
rpassword = "1.0"
parity-rpc = { path = "../rpc" }
parity-rpc-client = { path = "rpc-client" }

View File

@@ -0,0 +1,21 @@
[package]
description = "OpenEthereum RPC Client"
homepage = "https://github.com/openethereum/openethereum"
license = "GPL-3.0"
name = "parity-rpc-client"
version = "1.4.0"
authors = ["Parity <admin@parity.io>"]
[dependencies]
ethereum-types = "0.4"
futures = "0.1"
log = "0.4"
serde = "1.0"
serde_json = "1.0"
url = "2"
matches = "0.1"
parking_lot = "0.9"
jsonrpc-core = "15.0.0"
jsonrpc-ws-server = "15.0.0"
parity-rpc = { path = "../../rpc" }
keccak-hash = "0.1"

View File

@@ -0,0 +1,327 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use std::{
collections::BTreeMap,
fmt::{Debug, Error as FmtError, Formatter},
io::{BufRead, BufReader},
sync::{
atomic::{AtomicUsize, Ordering},
Arc,
},
thread, time,
};
use hash::keccak;
use parking_lot::Mutex;
use std::{fs::File, path::PathBuf};
use url::Url;
use ws::ws::{
self, Error as WsError, ErrorKind as WsErrorKind, Handler, Handshake, Message, Request,
Result as WsResult, Sender,
};
use serde::de::DeserializeOwned;
use serde_json::{self as json, Error as JsonError, Value as JsonValue};
use futures::{done, oneshot, Canceled, Complete, Future};
use jsonrpc_core::{
request::MethodCall,
response::{Failure, Output, Success},
Error as JsonRpcError, Id, Params, Version,
};
use BoxFuture;
/// The actual websocket connection handler, passed into the
/// event loop of ws-rs
struct RpcHandler {
pending: Pending,
// Option is used here as temporary storage until connection
// is setup and the values are moved into the new `Rpc`
complete: Option<Complete<Result<Rpc, RpcError>>>,
auth_code: String,
out: Option<Sender>,
}
impl RpcHandler {
fn new(out: Sender, auth_code: String, complete: Complete<Result<Rpc, RpcError>>) -> Self {
RpcHandler {
out: Some(out),
auth_code: auth_code,
pending: Pending::new(),
complete: Some(complete),
}
}
}
impl Handler for RpcHandler {
fn build_request(&mut self, url: &Url) -> WsResult<Request> {
match Request::from_url(url) {
Ok(mut r) => {
let timestamp = time::UNIX_EPOCH
.elapsed()
.map_err(|err| WsError::new(WsErrorKind::Internal, format!("{}", err)))?;
let secs = timestamp.as_secs();
let hashed = keccak(format!("{}:{}", self.auth_code, secs));
let proto = format!("{:x}_{}", hashed, secs);
r.add_protocol(&proto);
Ok(r)
}
Err(e) => Err(WsError::new(WsErrorKind::Internal, format!("{}", e))),
}
}
fn on_error(&mut self, err: WsError) {
match self.complete.take() {
Some(c) => match c.send(Err(RpcError::WsError(err))) {
Ok(_) => {}
Err(_) => warn!(target: "rpc-client", "Unable to notify about error."),
},
None => warn!(target: "rpc-client", "unexpected error: {}", err),
}
}
fn on_open(&mut self, _: Handshake) -> WsResult<()> {
match (self.complete.take(), self.out.take()) {
(Some(c), Some(out)) => {
let res = c.send(Ok(Rpc {
out: out,
counter: AtomicUsize::new(0),
pending: self.pending.clone(),
}));
if let Err(_) = res {
warn!(target: "rpc-client", "Unable to open a connection.")
}
Ok(())
}
_ => {
let msg = format!("on_open called twice");
Err(WsError::new(WsErrorKind::Internal, msg))
}
}
}
fn on_message(&mut self, msg: Message) -> WsResult<()> {
let ret: Result<JsonValue, JsonRpcError>;
let response_id;
let string = &msg.to_string();
match json::from_str::<Output>(&string) {
Ok(Output::Success(Success {
result,
id: Id::Num(id),
..
})) => {
ret = Ok(result);
response_id = id as usize;
}
Ok(Output::Failure(Failure {
error,
id: Id::Num(id),
..
})) => {
ret = Err(error);
response_id = id as usize;
}
Err(e) => {
warn!(
target: "rpc-client",
"recieved invalid message: {}\n {:?}",
string,
e
);
return Ok(());
}
_ => {
warn!(
target: "rpc-client",
"recieved invalid message: {}",
string
);
return Ok(());
}
}
match self.pending.remove(response_id) {
Some(c) => {
if let Err(_) = c.send(ret.map_err(|err| RpcError::JsonRpc(err))) {
warn!(target: "rpc-client", "Unable to send response.")
}
}
None => warn!(
target: "rpc-client",
"warning: unexpected id: {}",
response_id
),
}
Ok(())
}
}
/// Keeping track of issued requests to be matched up with responses
#[derive(Clone)]
struct Pending(Arc<Mutex<BTreeMap<usize, Complete<Result<JsonValue, RpcError>>>>>);
impl Pending {
fn new() -> Self {
Pending(Arc::new(Mutex::new(BTreeMap::new())))
}
fn insert(&mut self, k: usize, v: Complete<Result<JsonValue, RpcError>>) {
self.0.lock().insert(k, v);
}
fn remove(&mut self, k: usize) -> Option<Complete<Result<JsonValue, RpcError>>> {
self.0.lock().remove(&k)
}
}
fn get_authcode(path: &PathBuf) -> Result<String, RpcError> {
if let Ok(fd) = File::open(path) {
if let Some(Ok(line)) = BufReader::new(fd).lines().next() {
let mut parts = line.split(';');
let token = parts.next();
if let Some(code) = token {
return Ok(code.into());
}
}
}
Err(RpcError::NoAuthCode)
}
/// The handle to the connection
pub struct Rpc {
out: Sender,
counter: AtomicUsize,
pending: Pending,
}
impl Rpc {
/// Blocking, returns a new initialized connection or RpcError
pub fn new(url: &str, authpath: &PathBuf) -> Result<Self, RpcError> {
let rpc = Self::connect(url, authpath).map(|rpc| rpc).wait()?;
rpc
}
/// Non-blocking, returns a future
pub fn connect(url: &str, authpath: &PathBuf) -> BoxFuture<Result<Self, RpcError>, Canceled> {
let (c, p) = oneshot::<Result<Self, RpcError>>();
match get_authcode(authpath) {
Err(e) => return Box::new(done(Ok(Err(e)))),
Ok(code) => {
let url = String::from(url);
// The ws::connect takes a FnMut closure, which means c cannot
// be moved into it, since it's consumed on complete.
// Therefore we wrap it in an option and pick it out once.
let mut once = Some(c);
thread::spawn(move || {
let conn = ws::connect(url, |out| {
// this will panic if the closure is called twice,
// which it should never be.
let c = once.take().expect("connection closure called only once");
RpcHandler::new(out, code.clone(), c)
});
match conn {
Err(err) => {
// since ws::connect is only called once, it cannot
// both fail and succeed.
let c = once.take().expect("connection closure called only once");
let _ = c.send(Err(RpcError::WsError(err)));
}
// c will complete on the `on_open` event in the Handler
_ => (),
}
});
Box::new(p)
}
}
}
/// Non-blocking, returns a future of the request response
pub fn request<T>(
&mut self,
method: &'static str,
params: Vec<JsonValue>,
) -> BoxFuture<Result<T, RpcError>, Canceled>
where
T: DeserializeOwned + Send + Sized,
{
let (c, p) = oneshot::<Result<JsonValue, RpcError>>();
let id = self.counter.fetch_add(1, Ordering::Relaxed);
self.pending.insert(id, c);
let request = MethodCall {
jsonrpc: Some(Version::V2),
method: method.to_owned(),
params: Params::Array(params),
id: Id::Num(id as u64),
};
let serialized = json::to_string(&request).expect("request is serializable");
let _ = self.out.send(serialized);
Box::new(p.map(|result| match result {
Ok(json) => {
let t: T = json::from_value(json)?;
Ok(t)
}
Err(err) => Err(err),
}))
}
}
pub enum RpcError {
WrongVersion(String),
ParseError(JsonError),
MalformedResponse(String),
JsonRpc(JsonRpcError),
WsError(WsError),
Canceled(Canceled),
UnexpectedId,
NoAuthCode,
}
impl Debug for RpcError {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
RpcError::WrongVersion(ref s) => write!(f, "Expected version 2.0, got {}", s),
RpcError::ParseError(ref err) => write!(f, "ParseError: {}", err),
RpcError::MalformedResponse(ref s) => write!(f, "Malformed response: {}", s),
RpcError::JsonRpc(ref json) => write!(f, "JsonRpc error: {:?}", json),
RpcError::WsError(ref s) => write!(f, "Websocket error: {}", s),
RpcError::Canceled(ref s) => write!(f, "Futures error: {:?}", s),
RpcError::UnexpectedId => write!(f, "Unexpected response id"),
RpcError::NoAuthCode => write!(f, "No authcodes available"),
}
}
}
impl From<JsonError> for RpcError {
fn from(err: JsonError) -> RpcError {
RpcError::ParseError(err)
}
}
impl From<WsError> for RpcError {
fn from(err: WsError) -> RpcError {
RpcError::WsError(err)
}
}
impl From<Canceled> for RpcError {
fn from(err: Canceled) -> RpcError {
RpcError::Canceled(err)
}
}

View File

@@ -0,0 +1,90 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
pub mod client;
pub mod signer_client;
extern crate ethereum_types;
extern crate futures;
extern crate jsonrpc_core;
extern crate jsonrpc_ws_server as ws;
extern crate keccak_hash as hash;
extern crate parity_rpc as rpc;
extern crate parking_lot;
extern crate serde;
extern crate serde_json;
extern crate url;
#[macro_use]
extern crate log;
#[cfg(test)]
#[macro_use]
extern crate matches;
/// Boxed future response.
pub type BoxFuture<T, E> = Box<dyn futures::Future<Item = T, Error = E> + Send>;
#[cfg(test)]
mod tests {
use client::{Rpc, RpcError};
use futures::Future;
use rpc;
use std::path::PathBuf;
#[test]
fn test_connection_refused() {
let (_srv, port, mut authcodes) = rpc::tests::ws::serve();
let _ = authcodes.generate_new();
authcodes.to_file(&authcodes.path).unwrap();
let connect = Rpc::connect(&format!("ws://127.0.0.1:{}", port - 1), &authcodes.path);
let _ = connect
.map(|conn| {
assert!(matches!(&conn, &Err(RpcError::WsError(_))));
})
.wait();
}
#[test]
fn test_authcode_fail() {
let (_srv, port, _) = rpc::tests::ws::serve();
let path = PathBuf::from("nonexist");
let connect = Rpc::connect(&format!("ws://127.0.0.1:{}", port), &path);
let _ = connect
.map(|conn| {
assert!(matches!(&conn, &Err(RpcError::NoAuthCode)));
})
.wait();
}
#[test]
fn test_authcode_correct() {
let (_srv, port, mut authcodes) = rpc::tests::ws::serve();
let _ = authcodes.generate_new();
authcodes.to_file(&authcodes.path).unwrap();
let connect = Rpc::connect(&format!("ws://127.0.0.1:{}", port), &authcodes.path);
let _ = connect.map(|conn| assert!(conn.is_ok())).wait();
}
}

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