Compare commits
189 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb03f380ab | ||
|
|
31720e6151 | ||
|
|
92776e4acf | ||
|
|
c754a028e0 | ||
|
|
085035fa2e | ||
|
|
4ba600fcc4 | ||
|
|
0487c5b7a7 | ||
|
|
cc44ae9cb5 | ||
|
|
f26a7fe6fa | ||
|
|
a66e36bf41 | ||
|
|
c4c27cfa56 | ||
|
|
7bf16cce1b | ||
|
|
69d6d8239f | ||
|
|
6654d02163 | ||
|
|
885f45c8c1 | ||
|
|
62ccdd7ad4 | ||
|
|
aae451de9e | ||
|
|
baeda93474 | ||
|
|
7a28f72abc | ||
|
|
1ab06ce2d2 | ||
|
|
b0cc44aabb | ||
|
|
c983efe895 | ||
|
|
650948feed | ||
|
|
4e76cce0b7 | ||
|
|
9e9045ab94 | ||
|
|
d86333af6b | ||
|
|
28b5906d9e | ||
|
|
24f6d8296b | ||
|
|
9c5e35548d | ||
|
|
92b5b5644f | ||
|
|
8fb47b52f5 | ||
|
|
14361cc7b1 | ||
|
|
2257bc8e2f | ||
|
|
461b2d4853 | ||
|
|
941f2380c4 | ||
|
|
cb31220a4a | ||
|
|
9e09d5b6bf | ||
|
|
a04c5b180a | ||
|
|
db7a8c4ac7 | ||
|
|
fac356c701 | ||
|
|
90eb61091a | ||
|
|
f6998cb04e | ||
|
|
897a94641e | ||
|
|
3f677c6168 | ||
|
|
1cd93e4ceb | ||
|
|
03b96a7c0a | ||
|
|
869fa6fda8 | ||
|
|
bc2f5586ee | ||
|
|
16f435b906 | ||
|
|
0a170efaa5 | ||
|
|
1356d6d8d5 | ||
|
|
0a9114203b | ||
|
|
2b05eb43a9 | ||
|
|
dd2c27958c | ||
|
|
6737484eda | ||
|
|
9fe991db1c | ||
|
|
6cf441fc9e | ||
|
|
99e37844fd | ||
|
|
8348147a4f | ||
|
|
bd7273061e | ||
|
|
4f447c50b2 | ||
|
|
692cd10d4a | ||
|
|
86446d713a | ||
|
|
d1487b3177 | ||
|
|
8e7a08f865 | ||
|
|
0d75d01c84 | ||
|
|
1c75e8eb47 | ||
|
|
431b27d3e1 | ||
|
|
d97cf34138 | ||
|
|
e6f75bccfe | ||
|
|
c039ab79b5 | ||
|
|
9436e88d27 | ||
|
|
652f5032a2 | ||
|
|
d7a7f034db | ||
|
|
27c32d3629 | ||
|
|
0d2993e46d | ||
|
|
e4168c2985 | ||
|
|
9d3771458d | ||
|
|
ff0ce70169 | ||
|
|
811d165458 | ||
|
|
d57944ffb9 | ||
|
|
991f0cac6e | ||
|
|
b2d338bf35 | ||
|
|
ef80698deb | ||
|
|
e12a5159a8 | ||
|
|
0455aa96bf | ||
|
|
9aaedad64f | ||
|
|
ea6b0ec164 | ||
|
|
679d6c6f2b | ||
|
|
ec96091369 | ||
|
|
0a535bf485 | ||
|
|
dcaff6f4c8 | ||
|
|
5e7d42e4a4 | ||
|
|
99a13c4e66 | ||
|
|
060205ab27 | ||
|
|
9f775a7673 | ||
|
|
d477670cb9 | ||
|
|
54c9c382e7 | ||
|
|
9108a3bb50 | ||
|
|
c1cced3662 | ||
|
|
5ea4c22868 | ||
|
|
f1b7d8ab34 | ||
|
|
9c9ddaccec | ||
|
|
68a08df9c3 | ||
|
|
1e6d889fc7 | ||
|
|
443115f885 | ||
|
|
cab073ba00 | ||
|
|
7f9589d678 | ||
|
|
899c1a4b0e | ||
|
|
e3f7b70c38 | ||
|
|
6e49ff1d98 | ||
|
|
0c7f998c25 | ||
|
|
23ea4798e0 | ||
|
|
2632310b6a | ||
|
|
c4dd156113 | ||
|
|
06a7ca221c | ||
|
|
04931618ed | ||
|
|
dbc4d85f0a | ||
|
|
bd45cd4a5e | ||
|
|
8c02211dc3 | ||
|
|
eb18e7ade7 | ||
|
|
8ddd508a44 | ||
|
|
857809f693 | ||
|
|
ca0045482c | ||
|
|
1c2c683ae3 | ||
|
|
7c8d404cf8 | ||
|
|
d293f94a6f | ||
|
|
a60d0e440d | ||
|
|
9e294d577a | ||
|
|
6d5d419e14 | ||
|
|
1b4d9c2d39 | ||
|
|
a91e562021 | ||
|
|
d7f690c8ba | ||
|
|
7f1ff152ca | ||
|
|
beb6438ef5 | ||
|
|
e25a660a11 | ||
|
|
a7887fa9f1 | ||
|
|
a6915778bb | ||
|
|
249f81cbc5 | ||
|
|
373036bb7a | ||
|
|
ed296312aa | ||
|
|
d27c36cf75 | ||
|
|
c737056000 | ||
|
|
6f5bd845ad | ||
|
|
fed4864939 | ||
|
|
acd7192b17 | ||
|
|
21cb08586b | ||
|
|
4d1cb01da0 | ||
|
|
0e548ce7c5 | ||
|
|
236692cfd5 | ||
|
|
322dfbcd78 | ||
|
|
1bad20ae38 | ||
|
|
113c35af0a | ||
|
|
5c47116889 | ||
|
|
23fc5517b5 | ||
|
|
7e948a088f | ||
|
|
102bc7809f | ||
|
|
c2bd1a0e76 | ||
|
|
de72643898 | ||
|
|
e0f71b0c17 | ||
|
|
66f3c50842 | ||
|
|
373fdb65e9 | ||
|
|
58a1671076 | ||
|
|
e0a21e5aae | ||
|
|
3f33370e7d | ||
|
|
06fa900504 | ||
|
|
29d7a0e3c9 | ||
|
|
e8106016c8 | ||
|
|
d716bae3d5 | ||
|
|
f48b09b76e | ||
|
|
f54944bbfc | ||
|
|
ff722cac72 | ||
|
|
eeee90def5 | ||
|
|
47a02480c4 | ||
|
|
bbefdec973 | ||
|
|
f864f72bb5 | ||
|
|
6623de4e61 | ||
|
|
33284e988e | ||
|
|
9d7d6f7108 | ||
|
|
81b52c7336 | ||
|
|
fb17ae7751 | ||
|
|
9bcb589785 | ||
|
|
2e00f656d0 | ||
|
|
87f893265d | ||
|
|
d4205da484 | ||
|
|
ca0d1f5eb7 | ||
|
|
e76a545970 | ||
|
|
ec7282d05c | ||
|
|
ea3083bd3b |
@@ -180,10 +180,28 @@ windows:
|
||||
paths:
|
||||
- parity.zip
|
||||
name: "x86_64-pc-windows-msvc_parity"
|
||||
android-armv7:
|
||||
stage: build
|
||||
image: parity/parity-android:latest
|
||||
only:
|
||||
- beta
|
||||
- tags
|
||||
- stable
|
||||
- triggers
|
||||
script:
|
||||
- cargo build --target=armv7-linux-androideabi
|
||||
tags:
|
||||
- rust-arm
|
||||
allow_failure: true
|
||||
artifacts:
|
||||
paths:
|
||||
- parity.zip
|
||||
name: "armv7-linux-androideabi_parity"
|
||||
docker-build:
|
||||
stage: build
|
||||
only:
|
||||
- tags
|
||||
- master
|
||||
- beta
|
||||
- stable
|
||||
- triggers
|
||||
|
||||
629
CHANGELOG.md
629
CHANGELOG.md
@@ -1,386 +1,273 @@
|
||||
## Parity [v1.9.3](https://github.com/paritytech/parity/releases/tag/v1.9.3) (2018-02-20)
|
||||
## Parity [v1.10.2](https://github.com/paritytech/parity/releases/tag/v1.10.2) (2018-04-24)
|
||||
|
||||
Parity 1.9.3 is a bug-fix release to improve performance and stability.
|
||||
Parity 1.10.2 is a bug-fix release to improve performance and stability.
|
||||
|
||||
The full list of included changes:
|
||||
|
||||
- Backports ([#7945](https://github.com/paritytech/parity/pull/7945))
|
||||
- ECIP 1041 - Remove Difficulty Bomb ([#7905](https://github.com/paritytech/parity/pull/7905))
|
||||
- spec: Validate required divisor fields are not 0 ([#7933](https://github.com/paritytech/parity/pull/7933))
|
||||
- Kovan WASM fork code ([#7849](https://github.com/paritytech/parity/pull/7849))
|
||||
- Gitlab Cargo Cache ([#7944](https://github.com/paritytech/parity/pull/7944))
|
||||
- Bump react-qr-reader ([#7943](https://github.com/paritytech/parity/pull/7943))
|
||||
- Update react-qr-reader
|
||||
- Explicit webrtc-adapter dependency (package-lock workaround)
|
||||
- Iframe with allow (QR, new Chrome policy)
|
||||
- Backport of [#7844](https://github.com/paritytech/parity/pull/7844) and [#7917](https://github.com/paritytech/parity/pull/7917) to beta ([#7940](https://github.com/paritytech/parity/pull/7940))
|
||||
- Randomize the peer we dispatch to
|
||||
- Fix a division by zero in light client RPC handler
|
||||
- Wallet allowJsEval: true ([#7913](https://github.com/paritytech/parity/pull/7913))
|
||||
- Wallet allowJsEval: true
|
||||
- Fix unsafe wallet.
|
||||
- Enable unsafe-eval for all dapps.
|
||||
- Fix CSP for dapps that require eval. ([#7867](https://github.com/paritytech/parity/pull/7867)) ([#7903](https://github.com/paritytech/parity/pull/7903))
|
||||
- Add allowJsEval to manifest.
|
||||
- Enable 'unsafe-eval' if requested in manifest.
|
||||
- Fix snap build beta ([#7895](https://github.com/paritytech/parity/pull/7895))
|
||||
- Fix snapcraft grade to stable ([#7894](https://github.com/paritytech/parity/pull/7894))
|
||||
- Backport Master CI PRs to Beta ([#7890](https://github.com/paritytech/parity/pull/7890))
|
||||
- Add binary identifiers and sha256sum to builds ([#7830](https://github.com/paritytech/parity/pull/7830))
|
||||
- Fix checksums and auto-update push ([#7846](https://github.com/paritytech/parity/pull/7846))
|
||||
- Update gitlab-build.sh ([#7855](https://github.com/paritytech/parity/pull/7855))
|
||||
- Fix installer binary names for macos and windows ([#7881](https://github.com/paritytech/parity/pull/7881))
|
||||
- Update gitlab-test.sh ([#7883](https://github.com/paritytech/parity/pull/7883))
|
||||
- Fix snapcraft nightly ([#7884](https://github.com/paritytech/parity/pull/7884))
|
||||
- Backport Core PRs to beta ([#7891](https://github.com/paritytech/parity/pull/7891))
|
||||
- Update back-references more aggressively after answering from cache ([#7578](https://github.com/paritytech/parity/pull/7578))
|
||||
- Updated WASM Runtime & new interpreter (wasmi) ([#7796](https://github.com/paritytech/parity/pull/7796))
|
||||
- Adjust storage update evm-style ([#7812](https://github.com/paritytech/parity/pull/7812))
|
||||
- Add new EF ropstens nodes ([#7824](https://github.com/paritytech/parity/pull/7824))
|
||||
- Store updater metadata in a single place ([#7832](https://github.com/paritytech/parity/pull/7832))
|
||||
- WASM: Disable internal memory ([#7842](https://github.com/paritytech/parity/pull/7842))
|
||||
- Add a timeout for light client sync requests ([#7848](https://github.com/paritytech/parity/pull/7848))
|
||||
- Flush keyfiles. Resolves [#7632](https://github.com/paritytech/parity/issues/7632) ([#7868](https://github.com/paritytech/parity/pull/7868))
|
||||
- Fix wallet import ([#7873](https://github.com/paritytech/parity/pull/7873))
|
||||
- Update Parity beta to 1.10.2 + Backports ([#8455](https://github.com/paritytech/parity/pull/8455))
|
||||
- Update Parity beta to 1.10.2
|
||||
- Allow 32-bit pipelines to fail ([#8454](https://github.com/paritytech/parity/pull/8454))
|
||||
- Disable 32-bit targets for Gitlab
|
||||
- Rename Linux pipelines
|
||||
- Update wasmi ([#8452](https://github.com/paritytech/parity/pull/8452))
|
||||
- Fix Cargo.lock
|
||||
- Backports ([#8450](https://github.com/paritytech/parity/pull/8450))
|
||||
- Use forked app_dirs crate for reverted Windows dir behavior ([#8438](https://github.com/paritytech/parity/pull/8438))
|
||||
- Remove unused app_dirs dependency in CLI
|
||||
- Use forked app_dirs crate for reverted Windows dir behavior
|
||||
- Remove Tendermint extra_info due to seal inconsistencies ([#8367](https://github.com/paritytech/parity/pull/8367))
|
||||
- Handle queue import errors a bit more gracefully ([#8385](https://github.com/paritytech/parity/pull/8385))
|
||||
- Improve VM executor stack size estimation rules ([#8439](https://github.com/paritytech/parity/pull/8439))
|
||||
- Improve VM executor stack size estimation rules
|
||||
- Typo: docs add "(Debug build)" comment
|
||||
- Fix an off by one typo and set minimal stack size
|
||||
- Use saturating_sub to avoid potential overflow
|
||||
|
||||
## Parity [v1.9.2](https://github.com/paritytech/parity/releases/tag/v1.9.2) (2018-02-02)
|
||||
## Parity [v1.10.1](https://github.com/paritytech/parity/releases/tag/v1.10.1) (2018-04-17)
|
||||
|
||||
Parity 1.9.2 is a bug-fix release to improve performance and stability. It adds additional bootnodes for the Ropsten test network.
|
||||
Parity 1.10.1 is a bug-fix release to improve performance and stability. Among other changes, you can now use `--warp-barrier [BLOCK]` to specify a minimum block number to `--warp` to. This is useful in cases where clients restore to outdated snapshots far behind the latest chain head.
|
||||
|
||||
The full list of included changes:
|
||||
|
||||
- Backports beta ([#7780](https://github.com/paritytech/parity/pull/7780))
|
||||
- Bump beta to 1.9.2
|
||||
- Update ropsten.json ([#7776](https://github.com/paritytech/parity/pull/7776))
|
||||
- Snapcraft push beta
|
||||
|
||||
## Parity [v1.9.1](https://github.com/paritytech/parity/releases/tag/v1.9.1) (2018-02-01)
|
||||
|
||||
Parity 1.9.1 is a bug-fix release to improve performance and stability. It restores ERC-20 token balances, improves networking, fixes database corruptions on client shutdown, and fixes issues with the `--password` command-line flag. Happy syncing, fellow Ethereans!
|
||||
|
||||
In addition, this stabilizes Kovan and other Proof-of-Authority networks. If you run a network with AuRa engine, updating is highly encouraged!
|
||||
|
||||
The full list of included changes:
|
||||
|
||||
- Beta Backports ([#7756](https://github.com/paritytech/parity/pull/7756))
|
||||
- Filter-out nodes.json ([#7716](https://github.com/paritytech/parity/pull/7716))
|
||||
- Filter-out nodes.json
|
||||
- network: sort node table nodes by failure ratio
|
||||
- network: fix node table tests
|
||||
- network: fit node failure percentage into buckets of 5%
|
||||
- network: consider number of attempts in sorting of node table
|
||||
- network: fix node table grumbles
|
||||
- Fix client not being dropped on shutdown ([#7695](https://github.com/paritytech/parity/pull/7695))
|
||||
- parity: wait for client to drop on shutdown
|
||||
- parity: fix grumbles in shutdown wait
|
||||
- parity: increase shutdown timeouts
|
||||
- Wrap --help output to 120 characters ([#7626](https://github.com/paritytech/parity/pull/7626))
|
||||
- Update Clap dependency and remove workarounds
|
||||
- WIP
|
||||
- Remove line breaks in help messages for now
|
||||
- Multiple values can only be separated by commas (closes [#7428](https://github.com/paritytech/parity/issues/7428))
|
||||
- Grumbles; refactor repeating code; add constant
|
||||
- Use a single Wrapper rather than allocate a new one for each call
|
||||
- Wrap --help to 120 characters rather than 100 characte
|
||||
- Token filter balances (throttle) ([#7742](https://github.com/paritytech/parity/pull/7742))
|
||||
- Token filter balances (throttle)
|
||||
- Cleanups
|
||||
- Remove unused uniq
|
||||
- Update @parity/shared to 2.2.23
|
||||
- Remove unused code paths
|
||||
- Bump beta to 1.9.1 ([#7751](https://github.com/paritytech/parity/pull/7751))
|
||||
- Explicitly add branch name ([#7754](https://github.com/paritytech/parity/pull/7754))
|
||||
- Explicitly add branch name
|
||||
- Fix cargo update branch to beta
|
||||
- Revert revert revert ([#7715](https://github.com/paritytech/parity/pull/7715))
|
||||
- This reverts commit 568dc33.
|
||||
|
||||
## Parity [v1.9.0](https://github.com/paritytech/parity/releases/tag/v1.9.0) "Velocity" (2018-01-25)
|
||||
|
||||
We are happy to announce our newest Parity 1.9 release. Among others, it enables the following features:
|
||||
|
||||
- It integrates the fully reworked Parity Wallet and DApps browser (a.k.a. "UI 2.0", [#6819](https://github.com/paritytech/parity/pull/6819)).
|
||||
- It enables devp2p snappy compression ([#6683](https://github.com/paritytech/parity/pull/6683)).
|
||||
- AuRa Proof-of-Authority chains now disable uncles by default ([#7006](https://github.com/paritytech/parity/pull/7006)). Existing PoA chains can go through a "maximum uncle count transition" to achieve more stability ([#7196](https://github.com/paritytech/parity/pull/7196)).
|
||||
- Added Expanse's Byzantium hard-fork ([#7463](https://github.com/paritytech/parity/pull/7463)).
|
||||
- Added support for Ellaism chain ([#7222](https://github.com/paritytech/parity/pull/7222)).
|
||||
|
||||
Further, users upgrading from 1.8 should acknowledge the following changes:
|
||||
|
||||
- Fixed DELEGATECALL's from/to field ([#7568](https://github.com/paritytech/parity/pull/7568)).
|
||||
- Set zero nonce and gas price for calls by default ([#6954](https://github.com/paritytech/parity/pull/6954)).
|
||||
- Create pending blocks with all transactions from the queue ([#6942](https://github.com/paritytech/parity/pull/6942)).
|
||||
- Remove RPC parameter leniency now that Mist formats correctly ([#6651](https://github.com/paritytech/parity/pull/6651)). Parity stops accepting decimal-formatted block numbers and stops parsing the empty string as empty bytes.
|
||||
- Public nodes do not support the user interface anymore. If you are running a public node, please stay on the 1.8 branch of the stable releases.
|
||||
|
||||
Additional noteworthy changes:
|
||||
|
||||
- `ethstore` and `ethkey` have been significantly improved ([#6961](https://github.com/paritytech/parity/pull/6961)):
|
||||
- `ethstore` now supports brute forcing pre-sale wallets given a password list for recovery.
|
||||
- `ethkey` now supports multi-threaded generation of prefix-matching addresses.
|
||||
- `ethkey` now supports prefix-matching brain wallets.
|
||||
- `ethkey` now supports brain-wallets recovery-phrases lookup. This helps to find a correct phrase if you know the address you want to get yet you made a typo backing the phrase up, or forgot a word.
|
||||
|
||||
Read more about Parity 1.9 in our [blog post](http://paritytech.io/velocity-the-fastest-parity-released/).
|
||||
|
||||
The full list of included changes:
|
||||
|
||||
- Add scroll when when too many accounts ([#7677](https://github.com/paritytech/parity/pull/7677)) ([#7679](https://github.com/paritytech/parity/pull/7679))
|
||||
- Update installer.nsi
|
||||
- Fix conditions in gitlab-test ([#7676](https://github.com/paritytech/parity/pull/7676))
|
||||
- Fix conditions in gitlab-test
|
||||
- Update gitlab-test.sh
|
||||
- Remove cargo cache
|
||||
- Backports to beta ([#7660](https://github.com/paritytech/parity/pull/7660))
|
||||
- Improve handling of RocksDB corruption ([#7630](https://github.com/paritytech/parity/pull/7630))
|
||||
- Kvdb-rocksdb: update rust-rocksdb version
|
||||
- Kvdb-rocksdb: mark corruptions and attempt repair on db open
|
||||
- Kvdb-rocksdb: better corruption detection on open
|
||||
- Kvdb-rocksdb: add corruption_file_name const
|
||||
- Kvdb-rocksdb: rename mark_corruption to check_for_corruption
|
||||
- Hardening of CSP ([#7621](https://github.com/paritytech/parity/pull/7621))
|
||||
- Fixed delegatecall's from/to ([#7568](https://github.com/paritytech/parity/pull/7568))
|
||||
- Fixed delegatecall's from/to, closes [#7166](https://github.com/paritytech/parity/issues/7166)
|
||||
- Added tests for delegatecall traces, [#7167](https://github.com/paritytech/parity/issues/7167)
|
||||
- Light client RPCs ([#7603](https://github.com/paritytech/parity/pull/7603))
|
||||
- Implement registrar.
|
||||
- Implement eth_getCode
|
||||
- Don't wait for providers.
|
||||
- Don't wait for providers.
|
||||
- Fix linting and wasm tests.
|
||||
- Problem: AttachedProtocols don't get registered ([#7610](https://github.com/paritytech/parity/pull/7610))
|
||||
- Fix Temporarily Invalid blocks handling ([#7613](https://github.com/paritytech/parity/pull/7613))
|
||||
- Handle temporarily invalid blocks in sync.
|
||||
- Bump beta to 1.10.1 ([#8350](https://github.com/paritytech/parity/pull/8350))
|
||||
- Bump beta to 1.10.1
|
||||
- Unflag critical release
|
||||
- Backports ([#8346](https://github.com/paritytech/parity/pull/8346))
|
||||
- Warp-only sync with warp-barrier [blocknumber] flag. ([#8228](https://github.com/paritytech/parity/pull/8228))
|
||||
- Warp-only sync with warp-after [blocknumber] flag.
|
||||
- Fix tests.
|
||||
- Add docker build for beta ([#7671](https://github.com/paritytech/parity/pull/7671))
|
||||
- Add docker build for beta
|
||||
- Add cargo cache
|
||||
- Fix snapcraft build for beta ([#7670](https://github.com/paritytech/parity/pull/7670))
|
||||
- Update Parity.pkgproj
|
||||
- update gitlab build from master
|
||||
- Update references to dapp sources ([#7634](https://github.com/paritytech/parity/pull/7634)) ([#7636](https://github.com/paritytech/parity/pull/7636))
|
||||
- Update tokenreg ([#7618](https://github.com/paritytech/parity/pull/7618)) ([#7619](https://github.com/paritytech/parity/pull/7619))
|
||||
- Fix cache:key ([#7598](https://github.com/paritytech/parity/pull/7598))
|
||||
- Make 1.9 beta ([#7533](https://github.com/paritytech/parity/pull/7533))
|
||||
- Trigger js-precompiled ([#7535](https://github.com/paritytech/parity/pull/7535))
|
||||
- RocksDB fix ([#7512](https://github.com/paritytech/parity/pull/7512))
|
||||
- Update js-api ([#7510](https://github.com/paritytech/parity/pull/7510))
|
||||
- Expose default gas price percentile configuration in CLI ([#7497](https://github.com/paritytech/parity/pull/7497))
|
||||
- Use https connection ([#7503](https://github.com/paritytech/parity/pull/7503))
|
||||
- More thorough changes detection ([#7472](https://github.com/paritytech/parity/pull/7472))
|
||||
- Fix small layout issues ([#7500](https://github.com/paritytech/parity/pull/7500))
|
||||
- Show all accounts on Topbar ([#7498](https://github.com/paritytech/parity/pull/7498))
|
||||
- Update Parity Mainnet Bootnodes ([#7476](https://github.com/paritytech/parity/pull/7476))
|
||||
- Fixed panic when io is not available for export block ([#7495](https://github.com/paritytech/parity/pull/7495))
|
||||
- Advance AuRa step as far as we can and prevent invalid blocks. ([#7451](https://github.com/paritytech/parity/pull/7451))
|
||||
- Update package-lock in js-old ([#7494](https://github.com/paritytech/parity/pull/7494))
|
||||
- Update issue template and readme ([#7450](https://github.com/paritytech/parity/pull/7450))
|
||||
- Update package-lock.json pinned versions ([#7492](https://github.com/paritytech/parity/pull/7492))
|
||||
- Explicit pre-precompiled push checkout ([#7474](https://github.com/paritytech/parity/pull/7474))
|
||||
- Trigger js-precompiled ([#7473](https://github.com/paritytech/parity/pull/7473))
|
||||
- Expanse Byzantium update w/ correct metropolis difficulty increment divisor ([#7463](https://github.com/paritytech/parity/pull/7463))
|
||||
- Updated icons ([#7469](https://github.com/paritytech/parity/pull/7469))
|
||||
- Cleanup certifications ([#7454](https://github.com/paritytech/parity/pull/7454))
|
||||
- Fix css lint (updated stylelint) ([#7471](https://github.com/paritytech/parity/pull/7471))
|
||||
- Upgrade markdown-loader & marked ([#7467](https://github.com/paritytech/parity/pull/7467))
|
||||
- Remove JS test for removed code ([#7461](https://github.com/paritytech/parity/pull/7461))
|
||||
- Pull in dapp-status ([#7457](https://github.com/paritytech/parity/pull/7457))
|
||||
- Bump openssl crate ([#7455](https://github.com/paritytech/parity/pull/7455))
|
||||
- Signer updates from global Redux state ([#7452](https://github.com/paritytech/parity/pull/7452))
|
||||
- Remove expanse chain ([#7437](https://github.com/paritytech/parity/pull/7437))
|
||||
- Store tokens with repeatable id ([#7435](https://github.com/paritytech/parity/pull/7435))
|
||||
- Strict config parsing ([#7433](https://github.com/paritytech/parity/pull/7433))
|
||||
- Upgrade to RocksDB 5.8.8 and tune settings to reduce space amplification ([#7348](https://github.com/paritytech/parity/pull/7348))
|
||||
- Fix status layout ([#7432](https://github.com/paritytech/parity/pull/7432))
|
||||
- Fix tracing failed calls. ([#7412](https://github.com/paritytech/parity/pull/7412))
|
||||
- Problem: sending any Whisper message fails ([#7421](https://github.com/paritytech/parity/pull/7421))
|
||||
- Wait for future blocks in AuRa ([#7368](https://github.com/paritytech/parity/pull/7368))
|
||||
- Fix final feature. ([#7426](https://github.com/paritytech/parity/pull/7426))
|
||||
- Use RwLock for state DB ([#7425](https://github.com/paritytech/parity/pull/7425))
|
||||
- Update branding on UI ([#7370](https://github.com/paritytech/parity/pull/7370))
|
||||
- Changelog for 1.8.5 and 1.7.11 ([#7401](https://github.com/paritytech/parity/pull/7401))
|
||||
- Added checking tx-type using transactions permission contract for miners ([#7359](https://github.com/paritytech/parity/pull/7359))
|
||||
- Standalone dir crate, replaces [#7383](https://github.com/paritytech/parity/issues/7383) ([#7409](https://github.com/paritytech/parity/pull/7409))
|
||||
- SecretStore: secretstore_signRawHash method ([#7336](https://github.com/paritytech/parity/pull/7336))
|
||||
- SecretStore: return error 404 when there's no key shares for given key on all nodes ([#7331](https://github.com/paritytech/parity/pull/7331))
|
||||
- SecretStore: PoA integration initial version ([#7101](https://github.com/paritytech/parity/pull/7101))
|
||||
- Update bootnodes ([#7363](https://github.com/paritytech/parity/pull/7363))
|
||||
- Fix default CORS settings. ([#7387](https://github.com/paritytech/parity/pull/7387))
|
||||
- Fix version ([#7390](https://github.com/paritytech/parity/pull/7390))
|
||||
- Wasm runtime update ([#7356](https://github.com/paritytech/parity/pull/7356))
|
||||
- Parity-version pr reopen ([#7136](https://github.com/paritytech/parity/pull/7136))
|
||||
- Get rid of clippy remainings. ([#7355](https://github.com/paritytech/parity/pull/7355))
|
||||
- Avoid using ok_or with allocated argument ([#7357](https://github.com/paritytech/parity/pull/7357))
|
||||
- Make accounts refresh time configurable. ([#7345](https://github.com/paritytech/parity/pull/7345))
|
||||
- Enable traces for DEV chain ([#7327](https://github.com/paritytech/parity/pull/7327))
|
||||
- Problem: AuRa's unsafeties around step duration ([#7282](https://github.com/paritytech/parity/pull/7282))
|
||||
- Problem: Cargo.toml file contains [project] key ([#7346](https://github.com/paritytech/parity/pull/7346))
|
||||
- Fix broken flex modal layouts ([#7343](https://github.com/paritytech/parity/pull/7343))
|
||||
- Fix dappIcon & Fix Signer Pending ([#7338](https://github.com/paritytech/parity/pull/7338))
|
||||
- Fix wallet token/badge icons not showing up ([#7333](https://github.com/paritytech/parity/pull/7333))
|
||||
- Add Ellaism coin in chain config ([#7222](https://github.com/paritytech/parity/pull/7222))
|
||||
- Update bootnodes ([#7296](https://github.com/paritytech/parity/pull/7296))
|
||||
- Adds `personal_signTransaction` RPC method ([#6991](https://github.com/paritytech/parity/pull/6991))
|
||||
- Fix double initialization of embeded providers. ([#7326](https://github.com/paritytech/parity/pull/7326))
|
||||
- Transaction Pool re-implementation ([#6994](https://github.com/paritytech/parity/pull/6994))
|
||||
- UI package bump ([#7318](https://github.com/paritytech/parity/pull/7318))
|
||||
- Test framework and basic test for whisper ([#7011](https://github.com/paritytech/parity/pull/7011))
|
||||
- CI js-precompiled trigger ([#7316](https://github.com/paritytech/parity/pull/7316))
|
||||
- Fix inject.js & Signer store duplication ([#7299](https://github.com/paritytech/parity/pull/7299))
|
||||
- Detect different node, same-key signing in aura ([#7245](https://github.com/paritytech/parity/pull/7245))
|
||||
- New warp enodes ([#7287](https://github.com/paritytech/parity/pull/7287))
|
||||
- CSS fixes for v1 ([#7285](https://github.com/paritytech/parity/pull/7285))
|
||||
- Wallet subscriptions & refresh ([#7283](https://github.com/paritytech/parity/pull/7283))
|
||||
- Update inject web3 dependencies ([#7286](https://github.com/paritytech/parity/pull/7286))
|
||||
- Some padding around dapp image ([#7276](https://github.com/paritytech/parity/pull/7276))
|
||||
- Expand available middleware methods ([#7275](https://github.com/paritytech/parity/pull/7275))
|
||||
- Inject parity script to all dapps // Expand dapps to any ZIP file ([#7260](https://github.com/paritytech/parity/pull/7260))
|
||||
- New Homepage ([#7266](https://github.com/paritytech/parity/pull/7266))
|
||||
- Update kovan HF block number. ([#7259](https://github.com/paritytech/parity/pull/7259))
|
||||
- CHANGELOG for 1.7.10 and 1.8.4 ([#7265](https://github.com/paritytech/parity/pull/7265))
|
||||
- Remove extraneous id hashing ([#7269](https://github.com/paritytech/parity/pull/7269))
|
||||
- Simplify status + content display overlaps/page fixing ([#7264](https://github.com/paritytech/parity/pull/7264))
|
||||
- UI redirect to 127.0.0.1 when localhost requested ([#7236](https://github.com/paritytech/parity/pull/7236))
|
||||
- Usability improvements to security token Dialog [#7112](https://github.com/paritytech/parity/issues/7112) ([#7134](https://github.com/paritytech/parity/pull/7134))
|
||||
- Don't display unneeded notifications ([#7237](https://github.com/paritytech/parity/pull/7237))
|
||||
- Reduce max block timestamp drift to 15 seconds ([#7240](https://github.com/paritytech/parity/pull/7240))
|
||||
- Increase allowed time drift to 10s. ([#7238](https://github.com/paritytech/parity/pull/7238))
|
||||
- Improve building from source ([#7239](https://github.com/paritytech/parity/pull/7239))
|
||||
- Fix/Update method permissions ([#7233](https://github.com/paritytech/parity/pull/7233))
|
||||
- Fix aura difficulty race ([#7198](https://github.com/paritytech/parity/pull/7198))
|
||||
- Dependency updates ([#7226](https://github.com/paritytech/parity/pull/7226))
|
||||
- Display all dapps (shell) & wallet tabs (v1) by default ([#7213](https://github.com/paritytech/parity/pull/7213))
|
||||
- Rework dapps list ([#7206](https://github.com/paritytech/parity/pull/7206))
|
||||
- Add contributing guidelines and code of conduct. ([#7157](https://github.com/paritytech/parity/pull/7157))
|
||||
- Make Signing Requests more visible ([#7204](https://github.com/paritytech/parity/pull/7204))
|
||||
- Send each log as a separate notification ([#7175](https://github.com/paritytech/parity/pull/7175))
|
||||
- Deleting a mistake comment in calc difficulty ([#7154](https://github.com/paritytech/parity/pull/7154))
|
||||
- Maximum uncle count transition ([#7196](https://github.com/paritytech/parity/pull/7196))
|
||||
- Update FirstRun for UI-2 ([#7195](https://github.com/paritytech/parity/pull/7195))
|
||||
- Update mocha import stubs ([#7191](https://github.com/paritytech/parity/pull/7191))
|
||||
- Escape inifinite loop in estimte_gas ([#7075](https://github.com/paritytech/parity/pull/7075))
|
||||
- New account selector UI in top bar ([#7179](https://github.com/paritytech/parity/pull/7179))
|
||||
- Removed ethcore-util dependency from ethcore-network ([#7180](https://github.com/paritytech/parity/pull/7180))
|
||||
- WASM test runner utility upgrade ([#7147](https://github.com/paritytech/parity/pull/7147))
|
||||
- React 16 ([#7174](https://github.com/paritytech/parity/pull/7174))
|
||||
- Assorted improvements for ethstore and ethkey ([#6961](https://github.com/paritytech/parity/pull/6961))
|
||||
- Delete unused package.json (dist bundles) ([#7173](https://github.com/paritytech/parity/pull/7173))
|
||||
- Remove *.css.map & *.js.map ([#7168](https://github.com/paritytech/parity/pull/7168))
|
||||
- Use git flag to remove old js artifacts ([#7165](https://github.com/paritytech/parity/pull/7165))
|
||||
- Cleanup JS build artifacts ([#7164](https://github.com/paritytech/parity/pull/7164))
|
||||
- Fixes typo in user config path ([#7159](https://github.com/paritytech/parity/pull/7159))
|
||||
- Pull in new dapp-{methods,visible} dapps ([#7150](https://github.com/paritytech/parity/pull/7150))
|
||||
- WASM test runner utility ([#7142](https://github.com/paritytech/parity/pull/7142))
|
||||
- WASM Remove blockhash error ([#7121](https://github.com/paritytech/parity/pull/7121))
|
||||
- ECIP-1039: Monetary policy rounding specification ([#7067](https://github.com/paritytech/parity/pull/7067))
|
||||
- Fixed `RotatingLogger` after migrating to new arrayvec ([#7129](https://github.com/paritytech/parity/pull/7129))
|
||||
- Push to correct shell branch ([#7135](https://github.com/paritytech/parity/pull/7135))
|
||||
- Update js-precompiled ref, trigger JS build ([#7132](https://github.com/paritytech/parity/pull/7132))
|
||||
- Fixed build && test ([#7128](https://github.com/paritytech/parity/pull/7128))
|
||||
- Update packages, pull in compiled-only repos ([#7125](https://github.com/paritytech/parity/pull/7125))
|
||||
- Cleanup top bar, add Home icon for navigation ([#7118](https://github.com/paritytech/parity/pull/7118))
|
||||
- WASM storage_read and storage_write don't return anything ([#7110](https://github.com/paritytech/parity/pull/7110))
|
||||
- Local dapp development URL ([#7100](https://github.com/paritytech/parity/pull/7100))
|
||||
- Remove unused and duplicated files in js-old ([#7082](https://github.com/paritytech/parity/pull/7082))
|
||||
- Optimize & group dapp requests ([#7083](https://github.com/paritytech/parity/pull/7083))
|
||||
- WASM parse payload from panics ([#7097](https://github.com/paritytech/parity/pull/7097))
|
||||
- Fix no-default-features. ([#7096](https://github.com/paritytech/parity/pull/7096))
|
||||
- Updated eth-secp256k1 ([#7090](https://github.com/paritytech/parity/pull/7090))
|
||||
- Improve Github Issue Template ([#7099](https://github.com/paritytech/parity/pull/7099))
|
||||
- Changes necessary to upload crates to crates.io ([#7020](https://github.com/paritytech/parity/pull/7020))
|
||||
- Reopened 6860 - iterate over both buffered and unbuffered database entries ([#7048](https://github.com/paritytech/parity/pull/7048))
|
||||
- SecretStore: servers set change session api ([#6925](https://github.com/paritytech/parity/pull/6925))
|
||||
- Disable uncles by default ([#7006](https://github.com/paritytech/parity/pull/7006))
|
||||
- Squashed ethcore-network changes which introduce error-chain ([#7040](https://github.com/paritytech/parity/pull/7040))
|
||||
- Removed redundant imports ([#7057](https://github.com/paritytech/parity/pull/7057))
|
||||
- CHANGELOG for 1.7.8, 1.7.9, 1.8.2, and 1.8.3 ([#7055](https://github.com/paritytech/parity/pull/7055))
|
||||
- Properly display Signer errors (Snackbar display popup) ([#7053](https://github.com/paritytech/parity/pull/7053))
|
||||
- Add the desktop file for the snap ([#7059](https://github.com/paritytech/parity/pull/7059))
|
||||
- Small performance gain in allocations ([#7054](https://github.com/paritytech/parity/pull/7054))
|
||||
- Bump JSON-RPC version ([#7051](https://github.com/paritytech/parity/pull/7051))
|
||||
- Fix nonce reservation ([#7025](https://github.com/paritytech/parity/pull/7025))
|
||||
- Fixed ethstore-cli output ([#7052](https://github.com/paritytech/parity/pull/7052))
|
||||
- Add mui for embed compilation ([#7049](https://github.com/paritytech/parity/pull/7049))
|
||||
- Update the snap metadata to keep working strictly confined ([#6993](https://github.com/paritytech/parity/pull/6993))
|
||||
- Remove unused js packages (dapp cleanups) ([#7046](https://github.com/paritytech/parity/pull/7046))
|
||||
- Gitlog location update ([#7042](https://github.com/paritytech/parity/pull/7042))
|
||||
- Move git logging to .git-release.log ([#7041](https://github.com/paritytech/parity/pull/7041))
|
||||
- Start from rust root in release update step ([#7039](https://github.com/paritytech/parity/pull/7039))
|
||||
- Complete token merge, remove unused files ([#7037](https://github.com/paritytech/parity/pull/7037))
|
||||
- Add missing cargo-push.sh shell variable ([#7036](https://github.com/paritytech/parity/pull/7036))
|
||||
- Fix npm start script ([#7034](https://github.com/paritytech/parity/pull/7034))
|
||||
- Update executable flags on release scripts ([#7035](https://github.com/paritytech/parity/pull/7035))
|
||||
- Fix v1 precompiled ([#7033](https://github.com/paritytech/parity/pull/7033))
|
||||
- Push precompiled to correct branch (v1) ([#7031](https://github.com/paritytech/parity/pull/7031))
|
||||
- Update v1 Wallet Dapp ([#6935](https://github.com/paritytech/parity/pull/6935))
|
||||
- WASM tests update ([#7018](https://github.com/paritytech/parity/pull/7018))
|
||||
- Events in WASM runtime ([#6967](https://github.com/paritytech/parity/pull/6967))
|
||||
- Adds validate_node_url() and refactors boot node check ([#6907](https://github.com/paritytech/parity/pull/6907)) ([#6970](https://github.com/paritytech/parity/pull/6970))
|
||||
- Fix windows build (with ui rebuild) ([#7016](https://github.com/paritytech/parity/pull/7016))
|
||||
- Make CLI arguments parsing more backwards compatible ([#7004](https://github.com/paritytech/parity/pull/7004))
|
||||
- Fixes for parity-extension ([#6990](https://github.com/paritytech/parity/pull/6990))
|
||||
- Update ethcore-bigint ([#6992](https://github.com/paritytech/parity/pull/6992))
|
||||
- Get local transactions by hash in the light client ([#6874](https://github.com/paritytech/parity/pull/6874))
|
||||
- Warn when blacklisted account present in store ([#6875](https://github.com/paritytech/parity/pull/6875))
|
||||
- Skip nonce check for gas estimation ([#6997](https://github.com/paritytech/parity/pull/6997))
|
||||
- Creating pending block with all transactions from the queue ([#6942](https://github.com/paritytech/parity/pull/6942))
|
||||
- Removes `MAX_TX_TO_IMPORT` from `ChainSync` ([#6976](https://github.com/paritytech/parity/pull/6976))
|
||||
- SecretStore: versioned keys ([#6910](https://github.com/paritytech/parity/pull/6910))
|
||||
- Removes `FUTURE_QUEUE_LIMITS_SHIFT` ([#6962](https://github.com/paritytech/parity/pull/6962))
|
||||
- Set zero nonce and gas price for calls by default ([#6954](https://github.com/paritytech/parity/pull/6954))
|
||||
- Add hint in ActionParams for splitting code/data ([#6957](https://github.com/paritytech/parity/pull/6957))
|
||||
- Return decoded seal fields. ([#6932](https://github.com/paritytech/parity/pull/6932))
|
||||
- Fix serialization of status in transaction receipts. ([#6926](https://github.com/paritytech/parity/pull/6926))
|
||||
- Reserve nonces for signing ([#6834](https://github.com/paritytech/parity/pull/6834))
|
||||
- Windows fixes ([#6921](https://github.com/paritytech/parity/pull/6921))
|
||||
- Don't add {css,js}.map from dapps ([#6931](https://github.com/paritytech/parity/pull/6931))
|
||||
- Fix JSON tracing for sub-calls. ([#6842](https://github.com/paritytech/parity/pull/6842))
|
||||
- Shell updates (bonds, updated Dapps) ([#6897](https://github.com/paritytech/parity/pull/6897))
|
||||
- Fix [#6228](https://github.com/paritytech/parity/issues/6228): do not display eth price in cli for etc ([#6877](https://github.com/paritytech/parity/pull/6877))
|
||||
- Fix mining help ([#6885](https://github.com/paritytech/parity/pull/6885))
|
||||
- Refactor static context check in CREATE. ([#6886](https://github.com/paritytech/parity/pull/6886))
|
||||
- Cleanup some configuration options ([#6878](https://github.com/paritytech/parity/pull/6878))
|
||||
- Fix serialization of non-localized transactions ([#6868](https://github.com/paritytech/parity/pull/6868))
|
||||
- Updated ntp to version 0.3 ([#6854](https://github.com/paritytech/parity/pull/6854))
|
||||
- Align README with 1.8 and prepare CHANGELOG with 1.8.1 ([#6833](https://github.com/paritytech/parity/pull/6833))
|
||||
- Return error on timed unlock ([#6777](https://github.com/paritytech/parity/pull/6777))
|
||||
- Fix dapps tests in master ([#6866](https://github.com/paritytech/parity/pull/6866))
|
||||
- Ethstore optimizations ([#6827](https://github.com/paritytech/parity/pull/6827))
|
||||
- Add ECIP1017 to Morden config ([#6810](https://github.com/paritytech/parity/pull/6810))
|
||||
- Remove all package publishing to npm ([#6838](https://github.com/paritytech/parity/pull/6838))
|
||||
- Util crates use tempdir crate instead of devtools to create temp path ([#6807](https://github.com/paritytech/parity/pull/6807))
|
||||
- Trigger js build ([#6836](https://github.com/paritytech/parity/pull/6836))
|
||||
- Clean-up scripts. ([#6832](https://github.com/paritytech/parity/pull/6832))
|
||||
- Tweaked snapshot sync threshold ([#6829](https://github.com/paritytech/parity/pull/6829))
|
||||
- Integrate UI 2 ([#6819](https://github.com/paritytech/parity/pull/6819))
|
||||
- Refresh cached tokens based on registry info & random balances ([#6818](https://github.com/paritytech/parity/pull/6818))
|
||||
- Change keypath derivation logic ([#6815](https://github.com/paritytech/parity/pull/6815))
|
||||
- Refactors journaldb as a separate crate ([#6801](https://github.com/paritytech/parity/pull/6801))
|
||||
- Trigger UI build. ([#6817](https://github.com/paritytech/parity/pull/6817))
|
||||
- Bumped more crate versions ([#6809](https://github.com/paritytech/parity/pull/6809))
|
||||
- Fix RPC compilation warnings. ([#6808](https://github.com/paritytech/parity/pull/6808))
|
||||
- Remove internal ipc ([#6795](https://github.com/paritytech/parity/pull/6795))
|
||||
- Consistent KeyValueDB errors ([#6792](https://github.com/paritytech/parity/pull/6792))
|
||||
- Squash remaining warnings ([#6789](https://github.com/paritytech/parity/pull/6789))
|
||||
- Forward-port [#6754](https://github.com/paritytech/parity/issues/6754) [#6755](https://github.com/paritytech/parity/issues/6755) ([#6785](https://github.com/paritytech/parity/pull/6785))
|
||||
- Removed duplicated versions of clippy ([#6776](https://github.com/paritytech/parity/pull/6776))
|
||||
- Updated ethabi to version 4.0 ([#6742](https://github.com/paritytech/parity/pull/6742))
|
||||
- Updated rpc_cli and parity to rpassword 1.0 ([#6774](https://github.com/paritytech/parity/pull/6774))
|
||||
- Fix sign data typo ([#6750](https://github.com/paritytech/parity/pull/6750))
|
||||
- Refactoring/cache 6693 ([#6772](https://github.com/paritytech/parity/pull/6772))
|
||||
- Fix CHANGLOG for 1.8.0 ([#6751](https://github.com/paritytech/parity/pull/6751))
|
||||
- Removes redundant `mut` in service.rs.in ([#6775](https://github.com/paritytech/parity/pull/6775))
|
||||
- Remove redundant `mut` ([#6773](https://github.com/paritytech/parity/pull/6773))
|
||||
- Fixed kovan chain validation ([#6758](https://github.com/paritytech/parity/pull/6758))
|
||||
- Removed redundant evm deps ([#6757](https://github.com/paritytech/parity/pull/6757))
|
||||
- Fixed modexp gas calculation overflow ([#6741](https://github.com/paritytech/parity/pull/6741))
|
||||
- Use cc 1.0 instead of gcc ([#6733](https://github.com/paritytech/parity/pull/6733))
|
||||
- Version bump to 1.9.0 ([#6727](https://github.com/paritytech/parity/pull/6727))
|
||||
- Fix badges not showing up ([#6730](https://github.com/paritytech/parity/pull/6730))
|
||||
- Fix configuration tests.
|
||||
- Rename to warp barrier.
|
||||
- Allow unsafe js eval on Parity Wallet. ([#8204](https://github.com/paritytech/parity/pull/8204))
|
||||
- Update musicoin spec in line with gmc v2.6.2 ([#8242](https://github.com/paritytech/parity/pull/8242))
|
||||
- Supress TemporaryInvalid verification failures. ([#8256](https://github.com/paritytech/parity/pull/8256))
|
||||
- Include suicided accounts in state diff ([#8297](https://github.com/paritytech/parity/pull/8297))
|
||||
- Include suicided accounts in state diff
|
||||
- Shorten form match -> if let
|
||||
- Test suicide trace diff in State
|
||||
- Replace_home for password_files, reserved_peers and log_file ([#8324](https://github.com/paritytech/parity/pull/8324))
|
||||
- Replace_home for password_files, reserved_peers and log_file
|
||||
- Typo: arg_log_file is Option
|
||||
- Enable UI by default, but only display info page.
|
||||
- Fix test.
|
||||
- Fix naming and remove old todo.
|
||||
- Change "wallet" with "browser UI"
|
||||
- Change name Wallet -> UI ([#8164](https://github.com/paritytech/parity/pull/8164)) ([#8205](https://github.com/paritytech/parity/pull/8205))
|
||||
- Change name Wallet -> UI
|
||||
- Make warning bold
|
||||
- Backport [#8099](https://github.com/paritytech/parity/pull/8099) ([#8132](https://github.com/paritytech/parity/pull/8132))
|
||||
- WASM libs ([#8220](https://github.com/paritytech/parity/pull/8220))
|
||||
- Bump wasm libs ([#8171](https://github.com/paritytech/parity/pull/8171))
|
||||
- Bump wasmi version ([#8209](https://github.com/paritytech/parity/pull/8209))
|
||||
- Update hyper to 0.11.24 ([#8203](https://github.com/paritytech/parity/pull/8203))
|
||||
- Updated jsonrpc to include latest backports (beta) ([#8181](https://github.com/paritytech/parity/pull/8181))
|
||||
- Updated jsonrpc to include latest backports
|
||||
- Update dependencies.
|
||||
|
||||
### Previous releases
|
||||
## Parity [v1.10.0](https://github.com/paritytech/parity/releases/tag/v1.10.0) (2018-03-22)
|
||||
|
||||
- [CHANGELOG-1.8](docs/CHANGELOG-1.8.md) (_stable_)
|
||||
This is the Parity 1.10.0-beta release! Cool!
|
||||
|
||||
### Disabling the Parity Wallet
|
||||
|
||||
The **Parity Wallet (a.k.a. "UI") is now disabled by default**. We are preparing to split the wallet from the core client.
|
||||
|
||||
To reactivate the parity wallet, you have to run Parity either with `parity --force-ui` (not recommended) or `parity ui` (deprecated) from the command line. Or, if you feel super fancy and want to test our pre-releases of the stand-alone electron wallet, head over to the [Parity-JS repositories and check the releases](https://github.com/Parity-JS/shell/releases).
|
||||
|
||||
Further reading:
|
||||
|
||||
- [Docs: Parity Wallet](https://wiki.parity.io/Parity-Wallet)
|
||||
- [Docs: How to customize Parity UI?](https://wiki.parity.io/FAQ-Customize-Parity-UI.html)
|
||||
- [Github: Parity-JS](https://github.com/parity-js)
|
||||
|
||||
### Introducing the Wasm VM
|
||||
|
||||
We are excited to announce support for **Wasm Smart Contracts on Kovan network**. The hard-fork to activate the Wasm-VM will take place on block `6_600_000`.
|
||||
|
||||
To enable Wasm contracts on your custom network, just schedule a `wasmActivationTransition` at your favorite block number (e.g., `42`, `666`, or `0xbada55`). To hack your first Wasm smart contracts in Rust, have a look at the [Parity Wasm Tutorials](https://github.com/paritytech/pwasm-tutorial).
|
||||
|
||||
Further reading:
|
||||
|
||||
- [Docs: WebAssembly (wasm)](https://wiki.parity.io/WebAssembly-Home)
|
||||
- [Docs: Wasm VM Design](https://wiki.parity.io/WebAssembly-Design)
|
||||
- [Docs: Wasm tutorials and examples](https://wiki.parity.io/WebAssembly-Links)
|
||||
|
||||
### Empty step messages in PoA
|
||||
|
||||
To **reduce blockchain bloat, proof-of-authority networks can now enable _empty step messages_ which replace empty blocks**. Each step message will be signed and broadcasted by the issuing authorities, and included and rewarded in the next non-empty block.
|
||||
|
||||
To enable empty step messages, set the `emptyStepsTransition` to your favorite block number. You can also specify a maximum number of empty steps with `maximumEmptySteps` in your chain spec.
|
||||
|
||||
### Other noteworthy changes
|
||||
|
||||
We removed the old database migrations from 2016. In case you upgrade Parity from a really, really old version, you will have to reset your database manually first with `parity <options> db kill`.
|
||||
|
||||
We fixed DELEGATECALL `from` and `to` fields, see [#7166](https://github.com/paritytech/parity/issues/7166).
|
||||
|
||||
We reduced the default USD per transaction value to 0.0001. Thanks, @MysticRyuujin!
|
||||
|
||||
The Musicoin chain is now enabled with Byzantium features starting at block `2_222_222`.
|
||||
|
||||
### Overview of all changes included
|
||||
|
||||
The full list of included changes:
|
||||
|
||||
- Re-enable signer, even with no UI. ([#8167](https://github.com/paritytech/parity/pull/8167)) ([#8168](https://github.com/paritytech/parity/pull/8168))
|
||||
- Re-enable signer, even with no UI.
|
||||
- Fix message.
|
||||
- Beta Backports ([#8136](https://github.com/paritytech/parity/pull/8136))
|
||||
- Support parity protocol. ([#8035](https://github.com/paritytech/parity/pull/8035))
|
||||
- updater: apply exponential backoff after download failure ([#8059](https://github.com/paritytech/parity/pull/8059))
|
||||
- updater: apply exponential backoff after download failure
|
||||
- updater: reset backoff on new release
|
||||
- Max code size on Kovan ([#8067](https://github.com/paritytech/parity/pull/8067))
|
||||
- Enable code size limit on kovan
|
||||
- Fix formatting.
|
||||
- Limit incoming connections. ([#8060](https://github.com/paritytech/parity/pull/8060))
|
||||
- Limit ingress connections
|
||||
- Optimized handshakes logging
|
||||
- WASM libraries bump ([#7970](https://github.com/paritytech/parity/pull/7970))
|
||||
- update wasmi, parity-wasm, wasm-utils to latest version
|
||||
- Update to new wasmi & error handling
|
||||
- also utilize new stack limiter
|
||||
- fix typo
|
||||
- replace dependency url
|
||||
- Cargo.lock update
|
||||
- add some dos protection ([#8084](https://github.com/paritytech/parity/pull/8084))
|
||||
- revert removing blooms ([#8066](https://github.com/paritytech/parity/pull/8066))
|
||||
- Revert "fix traces, removed bloomchain crate, closes [#7228](https://github.com/paritytech/parity/issues/7228), closes [#7167](https://github.com/paritytech/parity/issues/7167)"
|
||||
- Revert "fixed broken logs ([#7934](https://github.com/paritytech/parity/pull/7934))"
|
||||
- fixed broken logs
|
||||
- bring back old lock order
|
||||
- remove migration v13
|
||||
- revert CURRENT_VERSION to 12 in migration.rs
|
||||
- more dos protection ([#8104](https://github.com/paritytech/parity/pull/8104))
|
||||
- Const time comparison ([#8113](https://github.com/paritytech/parity/pull/8113))
|
||||
- Use `subtle::slices_equal` for constant time comparison.
|
||||
- Also update the existing version of subtle in `ethcrypto` from 0.1 to 0.5
|
||||
- Test specifically for InvalidPassword error.
|
||||
- fix trace filter returning returning unrelated reward calls, closes #8070 ([#8098](https://github.com/paritytech/parity/pull/8098))
|
||||
- network: init discovery using healthy nodes ([#8061](https://github.com/paritytech/parity/pull/8061))
|
||||
- network: init discovery using healthy nodes
|
||||
- network: fix style grumble
|
||||
- network: fix typo
|
||||
- Postpone Kovan hard fork ([#8137](https://github.com/paritytech/parity/pull/8137))
|
||||
- ethcore: postpone Kovan hard fork
|
||||
- util: update version fork metadata
|
||||
- Disable UI by default. ([#8105](https://github.com/paritytech/parity/pull/8105))
|
||||
- dapps: update parity-ui dependencies ([#8160](https://github.com/paritytech/parity/pull/8160))
|
||||
- Probe changes one step deeper ([#8134](https://github.com/paritytech/parity/pull/8134)) ([#8135](https://github.com/paritytech/parity/pull/8135))
|
||||
- Beta backports ([#8053](https://github.com/paritytech/parity/pull/8053))
|
||||
- CI: Fix cargo cache ([#7968](https://github.com/paritytech/parity/pull/7968))
|
||||
- Fix cache
|
||||
- Only clean locked cargo cache on windows
|
||||
- fixed ethstore sign ([#8026](https://github.com/paritytech/parity/pull/8026))
|
||||
- fixed parsing ethash seals and verify_block_undordered ([#8031](https://github.com/paritytech/parity/pull/8031))
|
||||
- fix for verify_block_basic crashing on invalid transaction rlp ([#8032](https://github.com/paritytech/parity/pull/8032))
|
||||
- fix cache & snapcraft CI build ([#8052](https://github.com/paritytech/parity/pull/8052))
|
||||
- Add MCIP-6 Byzyantium transition to Musicoin spec ([#7841](https://github.com/paritytech/parity/pull/7841))
|
||||
- Add test chain spec for musicoin byzantium testnet
|
||||
- Add MCIP-6 Byzyantium transition to Musicoin spec
|
||||
- Update mcip6_byz.json
|
||||
- ethcore: update musicoin byzantium block number
|
||||
- ethcore: update musicoin bootnodes
|
||||
- Update musicoin.json
|
||||
- More bootnodes.
|
||||
- Make 1.10 beta ([#8022](https://github.com/paritytech/parity/pull/8022))
|
||||
- Make 1.10 beta
|
||||
- Fix gitlab builds
|
||||
- SecretStore: secretstore_generateDocumentKey RPC ([#7864](https://github.com/paritytech/parity/pull/7864))
|
||||
- SecretStore: ECDSA session for cases when 2*t < N ([#7739](https://github.com/paritytech/parity/pull/7739))
|
||||
- bump tiny-keccak ([#8019](https://github.com/paritytech/parity/pull/8019))
|
||||
- Remove un-necessary comment ([#8014](https://github.com/paritytech/parity/pull/8014))
|
||||
- clean up account fmt::Debug ([#7983](https://github.com/paritytech/parity/pull/7983))
|
||||
- improve quality of vote_collector module ([#7984](https://github.com/paritytech/parity/pull/7984))
|
||||
- ExecutedBlock cleanup ([#7991](https://github.com/paritytech/parity/pull/7991))
|
||||
- Hardware-wallet/usb-subscribe-refactor ([#7860](https://github.com/paritytech/parity/pull/7860))
|
||||
- remove wildcard imports from views, make tests more idiomatic ([#7986](https://github.com/paritytech/parity/pull/7986))
|
||||
- moved PerfTimer to a separate crate - "trace-time" ([#7985](https://github.com/paritytech/parity/pull/7985))
|
||||
- clean up ethcore::spec module imports ([#7990](https://github.com/paritytech/parity/pull/7990))
|
||||
- rpc: don't include current block in new_block_filter ([#7982](https://github.com/paritytech/parity/pull/7982))
|
||||
- fix traces, removed bloomchain crate ([#7979](https://github.com/paritytech/parity/pull/7979))
|
||||
- simplify compression and move it out of rlp crate ([#7957](https://github.com/paritytech/parity/pull/7957))
|
||||
- removed old migrations ([#7974](https://github.com/paritytech/parity/pull/7974))
|
||||
- Reject too large packets in snapshot sync. ([#7977](https://github.com/paritytech/parity/pull/7977))
|
||||
- fixed broken logs ([#7934](https://github.com/paritytech/parity/pull/7934))
|
||||
- Increase max download limit to 128MB ([#7965](https://github.com/paritytech/parity/pull/7965))
|
||||
- Calculate proper keccak256/sha3 using parity. ([#7953](https://github.com/paritytech/parity/pull/7953))
|
||||
- Add changelog for 1.8.10 stable and 1.9.3 beta ([#7947](https://github.com/paritytech/parity/pull/7947))
|
||||
- kvdb-rocksdb: remove buffered operations when committing transaction ([#7950](https://github.com/paritytech/parity/pull/7950))
|
||||
- Bump WebSockets ([#7952](https://github.com/paritytech/parity/pull/7952))
|
||||
- removed redundant Bloom conversions ([#7932](https://github.com/paritytech/parity/pull/7932))
|
||||
- simplify RefInfo fmt ([#7929](https://github.com/paritytech/parity/pull/7929))
|
||||
- Kovan WASM fork code ([#7849](https://github.com/paritytech/parity/pull/7849))
|
||||
- bring back trie and triehash benches ([#7926](https://github.com/paritytech/parity/pull/7926))
|
||||
- removed redundant PodAccount::new method ([#7928](https://github.com/paritytech/parity/pull/7928))
|
||||
- removed dummy wrapper structure - LogGroupPosition ([#7922](https://github.com/paritytech/parity/pull/7922))
|
||||
- spec: Validate required divisor fields are not 0 ([#7933](https://github.com/paritytech/parity/pull/7933))
|
||||
- simplify Client::filter_traces method ([#7936](https://github.com/paritytech/parity/pull/7936))
|
||||
- gitlab cache ([#7921](https://github.com/paritytech/parity/pull/7921))
|
||||
- Fix a division by zero in light client RPC handler ([#7917](https://github.com/paritytech/parity/pull/7917))
|
||||
- triehash optimisations ([#7920](https://github.com/paritytech/parity/pull/7920))
|
||||
- removed redundant Blockchain::db method ([#7919](https://github.com/paritytech/parity/pull/7919))
|
||||
- removed redundant Blockchain::rewind method ([#7918](https://github.com/paritytech/parity/pull/7918))
|
||||
- Pending transactions subscription ([#7906](https://github.com/paritytech/parity/pull/7906))
|
||||
- removed redundant otry! macro from ethcore ([#7916](https://github.com/paritytech/parity/pull/7916))
|
||||
- Make block generator easier to use ([#7888](https://github.com/paritytech/parity/pull/7888))
|
||||
- ECIP 1041 - Remove Difficulty Bomb ([#7905](https://github.com/paritytech/parity/pull/7905))
|
||||
- Fix CSP for dapps that require eval. ([#7867](https://github.com/paritytech/parity/pull/7867))
|
||||
- Fix gitlab ([#7901](https://github.com/paritytech/parity/pull/7901))
|
||||
- Gitlb snap master patch ([#7900](https://github.com/paritytech/parity/pull/7900))
|
||||
- fix snap build master ([#7896](https://github.com/paritytech/parity/pull/7896))
|
||||
- Fix wallet import ([#7873](https://github.com/paritytech/parity/pull/7873))
|
||||
- Fix snapcraft nightly ([#7884](https://github.com/paritytech/parity/pull/7884))
|
||||
- Add a timeout for light client sync requests ([#7848](https://github.com/paritytech/parity/pull/7848))
|
||||
- SecretStore: fixed test ([#7878](https://github.com/paritytech/parity/pull/7878))
|
||||
- Fix checksums and auto-update push ([#7846](https://github.com/paritytech/parity/pull/7846))
|
||||
- Forward-port snap fixes ([#7831](https://github.com/paritytech/parity/pull/7831))
|
||||
- Update gitlab-test.sh ([#7883](https://github.com/paritytech/parity/pull/7883))
|
||||
- Fix installer binary names for macos and windows ([#7881](https://github.com/paritytech/parity/pull/7881))
|
||||
- Fix string typo: "develoopment" -> "development" ([#7874](https://github.com/paritytech/parity/pull/7874))
|
||||
- Update the instructions to install the stable snap ([#7876](https://github.com/paritytech/parity/pull/7876))
|
||||
- SecretStore: 'broadcast' decryption session ([#7843](https://github.com/paritytech/parity/pull/7843))
|
||||
- Flush keyfiles. Resolves #7632 ([#7868](https://github.com/paritytech/parity/pull/7868))
|
||||
- Read registry_address from given block ([#7866](https://github.com/paritytech/parity/pull/7866))
|
||||
- Clean up docs formatting for Wasm runtime ([#7869](https://github.com/paritytech/parity/pull/7869))
|
||||
- WASM: Disable internal memory ([#7842](https://github.com/paritytech/parity/pull/7842))
|
||||
- Update gitlab-build.sh ([#7855](https://github.com/paritytech/parity/pull/7855))
|
||||
- ethabi version 5 ([#7723](https://github.com/paritytech/parity/pull/7723))
|
||||
- Light client: randomize the peer we dispatch requests to ([#7844](https://github.com/paritytech/parity/pull/7844))
|
||||
- Store updater metadata in a single place ([#7832](https://github.com/paritytech/parity/pull/7832))
|
||||
- Add new EF ropstens nodes. ([#7824](https://github.com/paritytech/parity/pull/7824))
|
||||
- refactor stratum to remove retain cycle ([#7827](https://github.com/paritytech/parity/pull/7827))
|
||||
- Bump jsonrpc. ([#7828](https://github.com/paritytech/parity/pull/7828))
|
||||
- Add binary identifiers and sha256sum to builds ([#7830](https://github.com/paritytech/parity/pull/7830))
|
||||
- Update references to UI shell & wallet ([#7808](https://github.com/paritytech/parity/pull/7808))
|
||||
- Adjust storage update evm-style ([#7812](https://github.com/paritytech/parity/pull/7812))
|
||||
- Updated WASM Runtime & new interpreter (wasmi) ([#7796](https://github.com/paritytech/parity/pull/7796))
|
||||
- SecretStore: ignore removed authorities when running auto-migration ([#7674](https://github.com/paritytech/parity/pull/7674))
|
||||
- Fix build ([#7807](https://github.com/paritytech/parity/pull/7807))
|
||||
- Move js & js-old code to github.com/parity-js ([#7685](https://github.com/paritytech/parity/pull/7685))
|
||||
- More changelogs :) ([#7782](https://github.com/paritytech/parity/pull/7782))
|
||||
- Actualized API set in help ([#7790](https://github.com/paritytech/parity/pull/7790))
|
||||
- Removed obsolete file ([#7788](https://github.com/paritytech/parity/pull/7788))
|
||||
- Update ropsten bootnodes ([#7776](https://github.com/paritytech/parity/pull/7776))
|
||||
- CHANGELOG for 1.9.1 and 1.8.8 ([#7775](https://github.com/paritytech/parity/pull/7775))
|
||||
- Enable byzantium features on non-ethash chains ([#7753](https://github.com/paritytech/parity/pull/7753))
|
||||
- Fix client not being dropped on shutdown ([#7695](https://github.com/paritytech/parity/pull/7695))
|
||||
- Filter-out nodes.json ([#7716](https://github.com/paritytech/parity/pull/7716))
|
||||
- Removes redundant parentheses ([#7721](https://github.com/paritytech/parity/pull/7721))
|
||||
- Transaction-pool fixes ([#7741](https://github.com/paritytech/parity/pull/7741))
|
||||
- More visible download link in README.md ([#7707](https://github.com/paritytech/parity/pull/7707))
|
||||
- Changelog for 1.9.0 ([#7664](https://github.com/paritytech/parity/pull/7664))
|
||||
- Add scroll when too many accounts ([#7677](https://github.com/paritytech/parity/pull/7677))
|
||||
- SecretStore: return HTTP 403 (access denied) if consensus is unreachable ([#7656](https://github.com/paritytech/parity/pull/7656))
|
||||
- Moved StopGaurd to it's own crate ([#7635](https://github.com/paritytech/parity/pull/7635))
|
||||
|
||||
## Previous releases
|
||||
|
||||
- [CHANGELOG-1.9](docs/CHANGELOG-1.9.md) (_stable_)
|
||||
- [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)
|
||||
|
||||
1907
Cargo.lock
generated
1907
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
37
Cargo.toml
37
Cargo.toml
@@ -2,7 +2,7 @@
|
||||
description = "Parity Ethereum client"
|
||||
name = "parity"
|
||||
# NOTE Make sure to update util/version/Cargo.toml as well
|
||||
version = "1.10.7"
|
||||
version = "1.11.11"
|
||||
license = "GPL-3.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
@@ -14,15 +14,14 @@ docopt = "0.8"
|
||||
clap = "2"
|
||||
term_size = "0.3"
|
||||
textwrap = "0.9"
|
||||
time = "0.1"
|
||||
num_cpus = "1.2"
|
||||
number_prefix = "0.2"
|
||||
rpassword = "1.0"
|
||||
semver = "0.6"
|
||||
semver = "0.9"
|
||||
ansi_term = "0.10"
|
||||
parking_lot = "0.5"
|
||||
regex = "0.2"
|
||||
isatty = "0.1"
|
||||
atty = "0.2.8"
|
||||
toml = "0.4"
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
@@ -30,21 +29,21 @@ serde_derive = "1.0"
|
||||
futures = "0.1"
|
||||
futures-cpupool = "0.1"
|
||||
fdlimit = "0.1"
|
||||
ws2_32-sys = "0.2"
|
||||
ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" }
|
||||
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.10" }
|
||||
ethsync = { path = "sync" }
|
||||
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" }
|
||||
ethcore = { path = "ethcore" }
|
||||
ethcore-bytes = { path = "util/bytes" }
|
||||
ethcore-io = { path = "util/io" }
|
||||
ethcore-light = { path = "ethcore/light" }
|
||||
ethcore-logger = { path = "logger" }
|
||||
ethcore-migrations = { path = "ethcore/migrations" }
|
||||
ethcore-miner = { path = "miner" }
|
||||
ethcore-network = { path = "util/network" }
|
||||
ethcore-stratum = { path = "stratum" }
|
||||
ethcore-private-tx = { path = "ethcore/private-tx" }
|
||||
ethcore-service = { path = "ethcore/service" }
|
||||
ethcore-stratum = { path = "ethcore/stratum" }
|
||||
ethcore-sync = { path = "ethcore/sync" }
|
||||
ethcore-transaction = { path = "ethcore/transaction" }
|
||||
ethereum-types = "0.2"
|
||||
ethereum-types = "0.3"
|
||||
node-filter = { path = "ethcore/node_filter" }
|
||||
ethkey = { path = "ethkey" }
|
||||
node-health = { path = "dapps/node-health" }
|
||||
@@ -63,14 +62,17 @@ path = { path = "util/path" }
|
||||
dir = { path = "util/dir" }
|
||||
panic_hook = { path = "util/panic_hook" }
|
||||
keccak-hash = { path = "util/hash" }
|
||||
migration = { path = "util/migration" }
|
||||
migration-rocksdb = { path = "util/migration-rocksdb" }
|
||||
kvdb = { path = "util/kvdb" }
|
||||
kvdb-rocksdb = { path = "util/kvdb-rocksdb" }
|
||||
journaldb = { path = "util/journaldb" }
|
||||
mem = { path = "util/mem" }
|
||||
|
||||
parity-dapps = { path = "dapps", optional = true }
|
||||
ethcore-secretstore = { path = "secret_store", optional = true }
|
||||
|
||||
registrar = { path = "registrar" }
|
||||
|
||||
[build-dependencies]
|
||||
rustc_version = "0.2"
|
||||
|
||||
@@ -78,12 +80,13 @@ rustc_version = "0.2"
|
||||
pretty_assertions = "0.1"
|
||||
ipnetwork = "0.12.6"
|
||||
tempdir = "0.3"
|
||||
fake-fetch = { path = "util/fake-fetch" }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = "0.2"
|
||||
winapi = { version = "0.3.4", features = ["winsock2", "winuser", "shellapi"] }
|
||||
|
||||
[target.'cfg(not(windows))'.dependencies]
|
||||
daemonize = "0.2"
|
||||
daemonize = { git = "https://github.com/paritytech/daemonize" }
|
||||
|
||||
[features]
|
||||
default = ["ui-precompiled"]
|
||||
@@ -97,7 +100,7 @@ ui-precompiled = [
|
||||
]
|
||||
ui-enabled = ["dapps"]
|
||||
dapps = ["parity-dapps"]
|
||||
jit = ["ethcore/jit"]
|
||||
miner-debug = ["ethcore/miner-debug"]
|
||||
json-tests = ["ethcore/json-tests"]
|
||||
test-heavy = ["ethcore/test-heavy"]
|
||||
evm-debug = ["ethcore/evm-debug"]
|
||||
@@ -121,7 +124,6 @@ panic = "abort"
|
||||
[workspace]
|
||||
members = [
|
||||
"chainspec",
|
||||
"dapps/js-glue",
|
||||
"ethcore/wasm/run",
|
||||
"ethcore/types",
|
||||
"ethkey/cli",
|
||||
@@ -130,5 +132,8 @@ members = [
|
||||
"miner",
|
||||
"transaction-pool",
|
||||
"whisper",
|
||||
"util/rlp_compress"
|
||||
"whisper/cli",
|
||||
]
|
||||
|
||||
[patch.crates-io]
|
||||
ring = { git = "https://github.com/paritytech/ring" }
|
||||
|
||||
12
README.md
12
README.md
@@ -21,7 +21,7 @@ Or join our community on Matrix:
|
||||
|
||||
Official website: https://parity.io
|
||||
|
||||
Be sure to check out [our wiki](https://paritytech.github.io/wiki/) and the [internal documentation](https://paritytech.github.io/parity/ethcore/index.html) for more information.
|
||||
Be sure to check out [our wiki](https://wiki.parity.io) for more information.
|
||||
|
||||
----
|
||||
|
||||
@@ -29,13 +29,15 @@ Be sure to check out [our wiki](https://paritytech.github.io/wiki/) and the [int
|
||||
|
||||
Parity's goal is to be the fastest, lightest, and most secure Ethereum client. We are developing Parity using the sophisticated and cutting-edge Rust programming language. Parity is licensed under the GPLv3, and can be used for all your Ethereum needs.
|
||||
|
||||
Parity comes with a built-in wallet. To access [Parity Wallet](http://web3.site/) simply go to http://web3.site/ (if you don't have access to the internet, but still want to use the service, you can also use http://127.0.0.1:8180/). It includes various functionality allowing you to:
|
||||
Parity comes with a built-in wallet, to install it please follow [these instructions](https://wiki.parity.io/Parity-Wallet). It includes various functionality allowing you to:
|
||||
|
||||
- create and manage your Ethereum accounts;
|
||||
- manage your Ether and any Ethereum tokens;
|
||||
- create and register your own tokens;
|
||||
- and much more.
|
||||
|
||||
From Parity Ethereum client version >=1.10, the User Interface (UI) is accessible in a separate application called Parity UI. To keep using the UI in the browser (deprecated), [follow these steps](https://wiki.parity.io/FAQ-Basic-Operations,-Configuration,-and-Synchronization.md#the-parity-ui-application-isnt-working-the-way-i-want).
|
||||
|
||||
By default, Parity will also run a JSONRPC server on `127.0.0.1:8545` and a websockets server on `127.0.0.1:8546`. This is fully configurable and supports a number of APIs.
|
||||
|
||||
If you run into an issue while using Parity, feel free to file one in this repository or hop on our [Gitter](https://gitter.im/paritytech/parity) or [Riot](https://riot.im/app/#/group/+parity:matrix.parity.io) chat room to ask a question. We are glad to help!
|
||||
@@ -73,7 +75,11 @@ We recommend installing Rust through [rustup](https://www.rustup.rs/). If you do
|
||||
$ rustup default stable-x86_64-pc-windows-msvc
|
||||
```
|
||||
|
||||
Once you have rustup, install Parity or download and build from source
|
||||
Once you have rustup installed, then you need to install:
|
||||
* [Perl](https://www.perl.org)
|
||||
* [Yasm](http://yasm.tortall.net)
|
||||
|
||||
Make sure that these binaries are in your `PATH`. After that you should be able to build parity from source.
|
||||
|
||||
----
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
description = "Parity Dapps crate"
|
||||
name = "parity-dapps"
|
||||
version = "1.9.0"
|
||||
version = "1.11.0"
|
||||
license = "GPL-3.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
@@ -22,14 +22,14 @@ serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0"
|
||||
unicase = "1.4"
|
||||
zip = { version = "0.1", default-features = false }
|
||||
zip = { version = "0.3", default-features = false, features = ["deflate"] }
|
||||
itertools = "0.5"
|
||||
|
||||
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.10" }
|
||||
jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.10" }
|
||||
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" }
|
||||
jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" }
|
||||
|
||||
ethcore-bytes = { path = "../util/bytes" }
|
||||
ethereum-types = "0.2"
|
||||
ethereum-types = "0.3"
|
||||
fetch = { path = "../util/fetch" }
|
||||
node-health = { path = "./node-health" }
|
||||
parity-hash-fetch = { path = "../hash-fetch" }
|
||||
@@ -38,6 +38,7 @@ parity-ui = { path = "./ui" }
|
||||
parity-ui-deprecation = { path = "./ui-deprecation" }
|
||||
keccak-hash = { path = "../util/hash" }
|
||||
parity-version = { path = "../util/version" }
|
||||
registrar = { path = "../registrar" }
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.4"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
//! Reporting node's health.
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::time;
|
||||
use std::time::Duration;
|
||||
use futures::Future;
|
||||
use futures::sync::oneshot;
|
||||
use types::{HealthInfo, HealthStatus, Health};
|
||||
@@ -26,7 +26,7 @@ use parity_reactor::Remote;
|
||||
use parking_lot::Mutex;
|
||||
use {SyncStatus};
|
||||
|
||||
const TIMEOUT_SECS: u64 = 5;
|
||||
const TIMEOUT: Duration = Duration::from_secs(5);
|
||||
const PROOF: &str = "Only one closure is invoked.";
|
||||
|
||||
/// A struct enabling you to query for node's health.
|
||||
@@ -53,11 +53,11 @@ impl NodeHealth {
|
||||
let tx = Arc::new(Mutex::new(Some(tx)));
|
||||
let tx2 = tx.clone();
|
||||
self.remote.spawn_with_timeout(
|
||||
move || time.then(move |result| {
|
||||
move |_| time.then(move |result| {
|
||||
let _ = tx.lock().take().expect(PROOF).send(Ok(result));
|
||||
Ok(())
|
||||
}),
|
||||
time::Duration::from_secs(TIMEOUT_SECS),
|
||||
TIMEOUT,
|
||||
move || {
|
||||
let _ = tx2.lock().take().expect(PROOF).send(Err(()));
|
||||
},
|
||||
|
||||
@@ -21,7 +21,7 @@ use std::path::PathBuf;
|
||||
use ethereum_types::H256;
|
||||
use fetch;
|
||||
use futures_cpupool::CpuPool;
|
||||
use hash::keccak_buffer;
|
||||
use hash::keccak_pipe;
|
||||
use mime_guess::Mime;
|
||||
|
||||
use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest, serialize_manifest, Manifest};
|
||||
@@ -55,15 +55,15 @@ fn write_response_and_check_hash(
|
||||
// Now write the response
|
||||
let mut file = io::BufWriter::new(fs::File::create(&content_path)?);
|
||||
let mut reader = io::BufReader::new(fetch::BodyReader::new(response));
|
||||
io::copy(&mut reader, &mut file)?;
|
||||
let hash = keccak_pipe(&mut reader, &mut file)?;
|
||||
let mut file = file.into_inner()?;
|
||||
file.flush()?;
|
||||
|
||||
// Validate hash
|
||||
// TODO [ToDr] calculate keccak in-flight while reading the response
|
||||
let mut file = io::BufReader::new(fs::File::open(&content_path)?);
|
||||
let hash = keccak_buffer(&mut file)?;
|
||||
if id == hash {
|
||||
Ok((file.into_inner(), content_path))
|
||||
// The writing above changed the file Read position, which we need later. So we just create a new file handle
|
||||
// here.
|
||||
Ok((fs::File::open(&content_path)?, content_path))
|
||||
} else {
|
||||
Err(ValidationError::HashMismatch {
|
||||
expected: id,
|
||||
@@ -266,3 +266,9 @@ impl From<zip::result::ZipError> for ValidationError {
|
||||
ValidationError::Zip(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::IntoInnerError<io::BufWriter<fs::File>>> for ValidationError {
|
||||
fn from(err: io::IntoInnerError<io::BufWriter<fs::File>>) -> Self {
|
||||
ValidationError::Io(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ use fetch::{self, Fetch};
|
||||
use futures::sync::oneshot;
|
||||
use futures::{self, Future};
|
||||
use futures_cpupool::CpuPool;
|
||||
use hyper::{self, Method, StatusCode};
|
||||
use hyper::{self, StatusCode};
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use endpoint::{self, EndpointPath};
|
||||
@@ -32,7 +32,7 @@ use handlers::{ContentHandler, StreamingHandler};
|
||||
use page::local;
|
||||
use {Embeddable};
|
||||
|
||||
const FETCH_TIMEOUT: u64 = 300;
|
||||
const FETCH_TIMEOUT: Duration = Duration::from_secs(300);
|
||||
|
||||
pub enum ValidatorResponse {
|
||||
Local(local::Dapp),
|
||||
@@ -57,7 +57,7 @@ impl Default for FetchControl {
|
||||
FetchControl {
|
||||
abort: Arc::new(AtomicBool::new(false)),
|
||||
listeners: Arc::new(Mutex::new(Vec::new())),
|
||||
deadline: Instant::now() + Duration::from_secs(FETCH_TIMEOUT),
|
||||
deadline: Instant::now() + FETCH_TIMEOUT,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -193,7 +193,7 @@ impl Errors {
|
||||
ContentHandler::error(
|
||||
StatusCode::GatewayTimeout,
|
||||
"Download Timeout",
|
||||
&format!("Could not fetch content within {} seconds.", FETCH_TIMEOUT),
|
||||
&format!("Could not fetch content within {} seconds.", FETCH_TIMEOUT.as_secs()),
|
||||
None,
|
||||
self.embeddable_on.clone(),
|
||||
)
|
||||
@@ -261,7 +261,7 @@ impl ContentFetcherHandler {
|
||||
// Validation of method
|
||||
let status = match *method {
|
||||
// Start fetching content
|
||||
Method::Get => {
|
||||
hyper::Method::Get => {
|
||||
trace!(target: "dapps", "Fetching content from: {:?}", url);
|
||||
FetchState::InProgress(Self::fetch_content(
|
||||
pool,
|
||||
@@ -295,7 +295,7 @@ impl ContentFetcherHandler {
|
||||
) -> Box<Future<Item=FetchState, Error=()> + Send> {
|
||||
// Start fetching the content
|
||||
let pool2 = pool.clone();
|
||||
let future = fetch.fetch(url, abort.into()).then(move |result| {
|
||||
let future = fetch.get(url, abort.into()).then(move |result| {
|
||||
trace!(target: "dapps", "Fetching content finished. Starting validation: {:?}", result);
|
||||
Ok(match result {
|
||||
Ok(response) => match installer.validate_and_install(response) {
|
||||
|
||||
@@ -42,6 +42,7 @@ extern crate parity_ui;
|
||||
extern crate parity_ui_deprecation;
|
||||
extern crate keccak_hash as hash;
|
||||
extern crate parity_version;
|
||||
extern crate registrar;
|
||||
|
||||
#[macro_use]
|
||||
extern crate futures;
|
||||
@@ -81,7 +82,7 @@ use parking_lot::RwLock;
|
||||
use fetch::Fetch;
|
||||
use node_health::NodeHealth;
|
||||
|
||||
pub use hash_fetch::urlhint::ContractClient;
|
||||
pub use registrar::{RegistrarClient, Asynchronous};
|
||||
pub use node_health::SyncStatus;
|
||||
|
||||
|
||||
@@ -156,7 +157,7 @@ impl Middleware {
|
||||
pool: CpuPool,
|
||||
health: NodeHealth,
|
||||
dapps_domain: &str,
|
||||
registrar: Arc<ContractClient>,
|
||||
registrar: Arc<RegistrarClient<Call=Asynchronous>>,
|
||||
sync_status: Arc<SyncStatus>,
|
||||
fetch: F,
|
||||
info_page_only: bool,
|
||||
@@ -217,7 +218,7 @@ impl Middleware {
|
||||
dapps_path: PathBuf,
|
||||
extra_dapps: Vec<PathBuf>,
|
||||
dapps_domain: &str,
|
||||
registrar: Arc<ContractClient>,
|
||||
registrar: Arc<RegistrarClient<Call=Asynchronous>>,
|
||||
sync_status: Arc<SyncStatus>,
|
||||
web_proxy_tokens: Arc<WebProxyTokens>,
|
||||
fetch: F,
|
||||
|
||||
@@ -19,8 +19,8 @@ use std::sync::{atomic, mpsc, Arc};
|
||||
use parking_lot::Mutex;
|
||||
use hyper;
|
||||
|
||||
use futures::{self, Future};
|
||||
use fetch::{self, Fetch, Url};
|
||||
use futures::{self, future, Future};
|
||||
use fetch::{self, Fetch, Url, Request, Abort};
|
||||
|
||||
pub struct FetchControl {
|
||||
sender: mpsc::Sender<()>,
|
||||
@@ -34,8 +34,8 @@ impl FetchControl {
|
||||
}
|
||||
|
||||
pub fn wait_for_requests(&self, len: usize) {
|
||||
const MAX_TIMEOUT_MS: u64 = 5000;
|
||||
const ATTEMPTS: u64 = 10;
|
||||
const MAX_TIMEOUT: time::Duration = time::Duration::from_millis(5000);
|
||||
const ATTEMPTS: u32 = 10;
|
||||
let mut attempts_left = ATTEMPTS;
|
||||
loop {
|
||||
let current = self.fetch.requested.lock().len();
|
||||
@@ -50,7 +50,7 @@ impl FetchControl {
|
||||
} else {
|
||||
attempts_left -= 1;
|
||||
// Should we handle spurious timeouts better?
|
||||
thread::park_timeout(time::Duration::from_millis(MAX_TIMEOUT_MS / ATTEMPTS));
|
||||
thread::park_timeout(MAX_TIMEOUT / ATTEMPTS);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,9 +97,9 @@ impl FakeFetch {
|
||||
impl Fetch for FakeFetch {
|
||||
type Result = Box<Future<Item = fetch::Response, Error = fetch::Error> + Send>;
|
||||
|
||||
fn fetch(&self, url: &str, abort: fetch::Abort) -> Self::Result {
|
||||
let u = Url::parse(url).unwrap();
|
||||
self.requested.lock().push(url.into());
|
||||
fn fetch(&self, request: Request, abort: fetch::Abort) -> Self::Result {
|
||||
let u = request.url().clone();
|
||||
self.requested.lock().push(u.as_str().into());
|
||||
let manual = self.manual.clone();
|
||||
let response = self.response.clone();
|
||||
|
||||
@@ -115,4 +115,20 @@ impl Fetch for FakeFetch {
|
||||
|
||||
Box::new(rx.map_err(|_| fetch::Error::Aborted))
|
||||
}
|
||||
|
||||
fn get(&self, url: &str, abort: Abort) -> Self::Result {
|
||||
let url: Url = match url.parse() {
|
||||
Ok(u) => u,
|
||||
Err(e) => return Box::new(future::err(e.into()))
|
||||
};
|
||||
self.fetch(Request::get(url), abort)
|
||||
}
|
||||
|
||||
fn post(&self, url: &str, abort: Abort) -> Self::Result {
|
||||
let url: Url = match url.parse() {
|
||||
Ok(u) => u,
|
||||
Err(e) => return Box::new(future::err(e.into()))
|
||||
};
|
||||
self.fetch(Request::post(url), abort)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ use jsonrpc_http_server::{self as http, Host, DomainsValidation};
|
||||
use parity_reactor::Remote;
|
||||
|
||||
use devtools::http_client;
|
||||
use hash_fetch::urlhint::ContractClient;
|
||||
use registrar::{RegistrarClient, Asynchronous};
|
||||
use fetch::{Fetch, Client as FetchClient};
|
||||
use node_health::{NodeHealth, TimeChecker, CpuPool};
|
||||
|
||||
@@ -144,7 +144,7 @@ pub fn assert_security_headers_for_embed(headers: &[String]) {
|
||||
/// Webapps HTTP+RPC server build.
|
||||
pub struct ServerBuilder<T: Fetch = FetchClient> {
|
||||
dapps_path: PathBuf,
|
||||
registrar: Arc<ContractClient>,
|
||||
registrar: Arc<RegistrarClient<Call=Asynchronous>>,
|
||||
sync_status: Arc<SyncStatus>,
|
||||
web_proxy_tokens: Arc<WebProxyTokens>,
|
||||
signer_address: Option<(String, u16)>,
|
||||
@@ -155,7 +155,7 @@ pub struct ServerBuilder<T: Fetch = FetchClient> {
|
||||
|
||||
impl ServerBuilder {
|
||||
/// Construct new dapps server
|
||||
pub fn new<P: AsRef<Path>>(fetch: FetchClient, dapps_path: P, registrar: Arc<ContractClient>) -> Self {
|
||||
pub fn new<P: AsRef<Path>>(fetch: FetchClient, dapps_path: P, registrar: Arc<RegistrarClient<Call=Asynchronous>>) -> Self {
|
||||
ServerBuilder {
|
||||
dapps_path: dapps_path.as_ref().to_owned(),
|
||||
registrar: registrar,
|
||||
@@ -219,7 +219,7 @@ impl Server {
|
||||
signer_address: Option<(String, u16)>,
|
||||
dapps_path: PathBuf,
|
||||
extra_dapps: Vec<PathBuf>,
|
||||
registrar: Arc<ContractClient>,
|
||||
registrar: Arc<RegistrarClient<Call=Asynchronous>>,
|
||||
sync_status: Arc<SyncStatus>,
|
||||
web_proxy_tokens: Arc<WebProxyTokens>,
|
||||
remote: Remote,
|
||||
|
||||
@@ -18,10 +18,9 @@ use std::str;
|
||||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use futures::Future;
|
||||
use ethereum_types::{H256, Address};
|
||||
use bytes::{Bytes, ToPretty};
|
||||
use hash_fetch::urlhint::ContractClient;
|
||||
use registrar::{RegistrarClient, Asynchronous};
|
||||
use parking_lot::Mutex;
|
||||
use rustc_hex::FromHex;
|
||||
|
||||
@@ -56,18 +55,20 @@ impl FakeRegistrar {
|
||||
|
||||
pub fn set_result(&self, hash: H256, result: Result<Bytes, String>) {
|
||||
self.responses.lock().insert(
|
||||
(URLHINT.into(), format!("{}{:?}", URLHINT_RESOLVE, hash)),
|
||||
(URLHINT.into(), format!("{}{:x}", URLHINT_RESOLVE, hash)),
|
||||
result
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl ContractClient for FakeRegistrar {
|
||||
fn registrar(&self) -> Result<Address, String> {
|
||||
impl RegistrarClient for FakeRegistrar {
|
||||
type Call = Asynchronous;
|
||||
|
||||
fn registrar_address(&self) -> Result<Address, String> {
|
||||
Ok(REGISTRAR.parse().unwrap())
|
||||
}
|
||||
|
||||
fn call(&self, address: Address, data: Bytes) -> Box<Future<Item = Bytes, Error = String> + Send> {
|
||||
fn call_contract(&self, address: Address, data: Bytes) -> Self::Call {
|
||||
let call = (address.to_hex(), data.to_hex());
|
||||
self.calls.lock().push(call.clone());
|
||||
let res = self.responses.lock().get(&call).cloned().expect(&format!("No response for call: {:?}", call));
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>Parity</title>
|
||||
<style>
|
||||
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
/* Copyright 2015-2018 Parity Technologies (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
@@ -107,8 +107,8 @@
|
||||
<div class="parity-navbar">
|
||||
</div>
|
||||
<div class="parity-box">
|
||||
<h1>Parity browser UI is deprecated.</h1>
|
||||
<h3>Get a standalone Parity UI from <a href="https://github.com/Parity-JS/shell/releases">here</a></h3>
|
||||
<h1>The Parity UI has been split off into a standalone project.</h1>
|
||||
<h3>Get the standalone Parity UI from <a href="https://github.com/Parity-JS/shell/releases">here</a></h3>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
|
||||
@@ -3,7 +3,7 @@ description = "Ethcore Parity UI"
|
||||
homepage = "http://parity.io"
|
||||
license = "GPL-3.0"
|
||||
name = "parity-ui"
|
||||
version = "1.9.0"
|
||||
version = "1.11.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[build-dependencies]
|
||||
|
||||
@@ -3,5 +3,5 @@ description = "Ethcore development/test/build tools"
|
||||
homepage = "http://parity.io"
|
||||
license = "GPL-3.0"
|
||||
name = "ethcore-devtools"
|
||||
version = "1.9.0"
|
||||
version = "1.11.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
29
docker/alpine/Dockerfile
Normal file
29
docker/alpine/Dockerfile
Normal file
@@ -0,0 +1,29 @@
|
||||
FROM alpine:edge
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# install tools and dependencies
|
||||
RUN apk add --no-cache gcc musl-dev pkgconfig g++ make curl \
|
||||
eudev-dev rust cargo git file binutils \
|
||||
libusb-dev linux-headers perl cmake
|
||||
|
||||
# show backtraces
|
||||
ENV RUST_BACKTRACE 1
|
||||
|
||||
# show tools
|
||||
RUN rustc -vV && \
|
||||
cargo -V && \
|
||||
gcc -v &&\
|
||||
g++ -v
|
||||
|
||||
# build parity
|
||||
ADD . /build/parity
|
||||
RUN cd parity && \
|
||||
cargo build --release --verbose && \
|
||||
ls /build/parity/target/release/parity && \
|
||||
strip /build/parity/target/release/parity
|
||||
|
||||
RUN file /build/parity/target/release/parity
|
||||
|
||||
EXPOSE 8080 8545 8180
|
||||
ENTRYPOINT ["/build/parity/target/release/parity"]
|
||||
77
docker/android/Dockerfile
Normal file
77
docker/android/Dockerfile
Normal file
@@ -0,0 +1,77 @@
|
||||
FROM ubuntu:xenial
|
||||
LABEL maintainer="Parity Technologies <devops@parity.io>"
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -yq sudo curl file build-essential wget git g++ cmake pkg-config bison flex \
|
||||
unzip lib32stdc++6 lib32z1 python autotools-dev automake autoconf libtool \
|
||||
gperf xsltproc docbook-xsl
|
||||
|
||||
# Rust & Cargo
|
||||
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
|
||||
ENV PATH /root/.cargo/bin:$PATH
|
||||
RUN rustup toolchain install stable
|
||||
RUN rustup target add --toolchain stable arm-linux-androideabi
|
||||
RUN rustup target add --toolchain stable armv7-linux-androideabi
|
||||
|
||||
# Android NDK and toolchain
|
||||
RUN cd /usr/local && \
|
||||
wget -q https://dl.google.com/android/repository/android-ndk-r16b-linux-x86_64.zip && \
|
||||
unzip -q android-ndk-r16b-linux-x86_64.zip && \
|
||||
rm android-ndk-r16b-linux-x86_64.zip
|
||||
ENV NDK_HOME /usr/local/android-ndk-r16b
|
||||
RUN /usr/local/android-ndk-r16b/build/tools/make-standalone-toolchain.sh \
|
||||
--arch=arm --install-dir=/opt/ndk-standalone --stl=libc++ --platform=android-26
|
||||
ENV PATH $PATH:/opt/ndk-standalone/bin
|
||||
|
||||
# Compiling OpenSSL for Android
|
||||
RUN cd /root && \
|
||||
git clone git://git.openssl.org/openssl.git && \
|
||||
cd openssl && \
|
||||
git checkout OpenSSL_1_1_0-stable
|
||||
ENV CROSS_SYSROOT /opt/ndk-standalone/sysroot
|
||||
RUN cd /root/openssl && \
|
||||
./Configure android-armeabi --cross-compile-prefix=arm-linux-androideabi- \
|
||||
-static no-stdio no-ui \
|
||||
-I/usr/local/android-ndk-r16b/sysroot/usr/include \
|
||||
-I/usr/local/android-ndk-r16b/sysroot/usr/include/arm-linux-androideabi \
|
||||
-L/usr/local/android-ndk-r16b/sysroot/usr/lib \
|
||||
--prefix=/opt/ndk-standalone/sysroot/usr
|
||||
RUN cd /root/openssl && \
|
||||
make build_libs && \
|
||||
make install_dev
|
||||
RUN rm -rf /root/openssl
|
||||
|
||||
# Compiling libudev for Android
|
||||
# This is the most hacky part of the process, as we need to apply a patch and pass specific
|
||||
# options that the compiler environment doesn't define.
|
||||
RUN cd /root && \
|
||||
git clone https://github.com/gentoo/eudev.git
|
||||
ADD libudev.patch /root
|
||||
RUN cd /root/eudev && \
|
||||
git checkout 83d918449f22720d84a341a05e24b6d109e6d3ae && \
|
||||
./autogen.sh && \
|
||||
./configure --disable-introspection --disable-programs --disable-hwdb \
|
||||
--host=arm-linux-androideabi --prefix=/opt/ndk-standalone/sysroot/usr/ \
|
||||
--enable-shared=false CC=arm-linux-androideabi-clang \
|
||||
CFLAGS="-D LINE_MAX=2048 -D RLIMIT_NLIMITS=15 -D IPTOS_LOWCOST=2 -std=gnu99" \
|
||||
CXX=arm-linux-androideabi-clang++ && \
|
||||
git apply - < /root/libudev.patch && \
|
||||
make && \
|
||||
make install
|
||||
RUN rm -rf /root/eudev
|
||||
RUN rm /root/libudev.patch
|
||||
|
||||
# Rust-related configuration
|
||||
ADD cargo-config.toml /root/.cargo/config
|
||||
ENV ARM_LINUX_ANDROIDEABI_OPENSSL_DIR /opt/ndk-standalone/sysroot/usr
|
||||
ENV ARMV7_LINUX_ANDROIDEABI_OPENSSL_DIR /opt/ndk-standalone/sysroot/usr
|
||||
ENV CC_arm_linux_androideabi arm-linux-androideabi-clang
|
||||
ENV CC_armv7_linux_androideabi arm-linux-androideabi-clang
|
||||
ENV CXX_arm_linux_androideabi arm-linux-androideabi-clang++
|
||||
ENV CXX_armv7_linux_androideabi arm-linux-androideabi-clang++
|
||||
ENV AR_arm_linux_androideabi arm-linux-androideabi-ar
|
||||
ENV AR_armv7_linux_androideabi arm-linux-androideabi-ar
|
||||
ENV CFLAGS_arm_linux_androideabi -std=gnu11 -fPIC -D OS_ANDROID
|
||||
ENV CFLAGS_armv7_linux_androideabi -std=gnu11 -fPIC -D OS_ANDROID
|
||||
ENV CXXFLAGS_arm_linux_androideabi -std=gnu++11 -fPIC -fexceptions -frtti -static-libstdc++ -D OS_ANDROID
|
||||
ENV CXXFLAGS_armv7_linux_androideabi -std=gnu++11 -fPIC -fexceptions -frtti -static-libstdc++ -D OS_ANDROID
|
||||
9
docker/android/cargo-config.toml
Normal file
9
docker/android/cargo-config.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
[target.armv7-linux-androideabi]
|
||||
linker = "arm-linux-androideabi-clang"
|
||||
ar = "arm-linux-androideabi-ar"
|
||||
rustflags = ["-C", "link-arg=-lc++_static", "-C", "link-arg=-lc++abi", "-C", "link-arg=-landroid_support"]
|
||||
|
||||
[target.arm-linux-androideabi]
|
||||
linker = "arm-linux-androideabi-clang"
|
||||
ar = "arm-linux-androideabi-ar"
|
||||
rustflags = ["-C", "link-arg=-lc++_static", "-C", "link-arg=-lc++abi", "-C", "link-arg=-landroid_support"]
|
||||
216
docker/android/libudev.patch
Normal file
216
docker/android/libudev.patch
Normal file
@@ -0,0 +1,216 @@
|
||||
diff --git a/src/collect/collect.c b/src/collect/collect.c
|
||||
index 2cf1f00..b24f26b 100644
|
||||
--- a/src/collect/collect.c
|
||||
+++ b/src/collect/collect.c
|
||||
@@ -84,7 +84,7 @@ static void usage(void)
|
||||
" invoked for each ID in <idlist>) collect returns 0, the\n"
|
||||
" number of missing IDs otherwise.\n"
|
||||
" On error a negative number is returned.\n\n"
|
||||
- , program_invocation_short_name);
|
||||
+ , "parity");
|
||||
}
|
||||
|
||||
/*
|
||||
diff --git a/src/scsi_id/scsi_id.c b/src/scsi_id/scsi_id.c
|
||||
index 8b76d87..7bf3948 100644
|
||||
--- a/src/scsi_id/scsi_id.c
|
||||
+++ b/src/scsi_id/scsi_id.c
|
||||
@@ -321,7 +321,7 @@ static void help(void) {
|
||||
" -u --replace-whitespace Replace all whitespace by underscores\n"
|
||||
" -v --verbose Verbose logging\n"
|
||||
" -x --export Print values as environment keys\n"
|
||||
- , program_invocation_short_name);
|
||||
+ , "parity");
|
||||
|
||||
}
|
||||
|
||||
diff --git a/src/shared/hashmap.h b/src/shared/hashmap.h
|
||||
index a03ee58..a7c2005 100644
|
||||
--- a/src/shared/hashmap.h
|
||||
+++ b/src/shared/hashmap.h
|
||||
@@ -98,10 +98,7 @@ extern const struct hash_ops uint64_hash_ops;
|
||||
#if SIZEOF_DEV_T != 8
|
||||
unsigned long devt_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_;
|
||||
int devt_compare_func(const void *a, const void *b) _pure_;
|
||||
-extern const struct hash_ops devt_hash_ops = {
|
||||
- .hash = devt_hash_func,
|
||||
- .compare = devt_compare_func
|
||||
-};
|
||||
+extern const struct hash_ops devt_hash_ops;
|
||||
#else
|
||||
#define devt_hash_func uint64_hash_func
|
||||
#define devt_compare_func uint64_compare_func
|
||||
diff --git a/src/shared/log.c b/src/shared/log.c
|
||||
index 4a40996..1496984 100644
|
||||
--- a/src/shared/log.c
|
||||
+++ b/src/shared/log.c
|
||||
@@ -335,7 +335,7 @@ static int write_to_syslog(
|
||||
|
||||
IOVEC_SET_STRING(iovec[0], header_priority);
|
||||
IOVEC_SET_STRING(iovec[1], header_time);
|
||||
- IOVEC_SET_STRING(iovec[2], program_invocation_short_name);
|
||||
+ IOVEC_SET_STRING(iovec[2], "parity");
|
||||
IOVEC_SET_STRING(iovec[3], header_pid);
|
||||
IOVEC_SET_STRING(iovec[4], buffer);
|
||||
|
||||
@@ -383,7 +383,7 @@ static int write_to_kmsg(
|
||||
char_array_0(header_pid);
|
||||
|
||||
IOVEC_SET_STRING(iovec[0], header_priority);
|
||||
- IOVEC_SET_STRING(iovec[1], program_invocation_short_name);
|
||||
+ IOVEC_SET_STRING(iovec[1], "parity");
|
||||
IOVEC_SET_STRING(iovec[2], header_pid);
|
||||
IOVEC_SET_STRING(iovec[3], buffer);
|
||||
IOVEC_SET_STRING(iovec[4], "\n");
|
||||
diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c
|
||||
index 6af7163..3271e56 100644
|
||||
--- a/src/udev/udevadm-control.c
|
||||
+++ b/src/udev/udevadm-control.c
|
||||
@@ -41,7 +41,7 @@ static void print_help(void) {
|
||||
" -p --property=KEY=VALUE Set a global property for all events\n"
|
||||
" -m --children-max=N Maximum number of children\n"
|
||||
" --timeout=SECONDS Maximum time to block for a reply\n"
|
||||
- , program_invocation_short_name);
|
||||
+ , "parity");
|
||||
}
|
||||
|
||||
static int adm_control(struct udev *udev, int argc, char *argv[]) {
|
||||
diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c
|
||||
index 0aec976..a31ac02 100644
|
||||
--- a/src/udev/udevadm-info.c
|
||||
+++ b/src/udev/udevadm-info.c
|
||||
@@ -279,7 +279,7 @@ static void help(void) {
|
||||
" -P --export-prefix Export the key name with a prefix\n"
|
||||
" -e --export-db Export the content of the udev database\n"
|
||||
" -c --cleanup-db Clean up the udev database\n"
|
||||
- , program_invocation_short_name);
|
||||
+ , "parity");
|
||||
}
|
||||
|
||||
static int uinfo(struct udev *udev, int argc, char *argv[]) {
|
||||
diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c
|
||||
index 15ded09..b58dd08 100644
|
||||
--- a/src/udev/udevadm-monitor.c
|
||||
+++ b/src/udev/udevadm-monitor.c
|
||||
@@ -73,7 +73,7 @@ static void help(void) {
|
||||
" -u --udev Print udev events\n"
|
||||
" -s --subsystem-match=SUBSYSTEM[/DEVTYPE] Filter events by subsystem\n"
|
||||
" -t --tag-match=TAG Filter events by tag\n"
|
||||
- , program_invocation_short_name);
|
||||
+ , "parity");
|
||||
}
|
||||
|
||||
static int adm_monitor(struct udev *udev, int argc, char *argv[]) {
|
||||
diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c
|
||||
index 33597bc..b36a504 100644
|
||||
--- a/src/udev/udevadm-settle.c
|
||||
+++ b/src/udev/udevadm-settle.c
|
||||
@@ -43,7 +43,7 @@ static void help(void) {
|
||||
" --version Show package version\n"
|
||||
" -t --timeout=SECONDS Maximum time to wait for events\n"
|
||||
" -E --exit-if-exists=FILE Stop waiting if file exists\n"
|
||||
- , program_invocation_short_name);
|
||||
+ , "parity");
|
||||
}
|
||||
|
||||
static int adm_settle(struct udev *udev, int argc, char *argv[]) {
|
||||
diff --git a/src/udev/udevadm-test-builtin.c b/src/udev/udevadm-test-builtin.c
|
||||
index baaeca9..50ed812 100644
|
||||
--- a/src/udev/udevadm-test-builtin.c
|
||||
+++ b/src/udev/udevadm-test-builtin.c
|
||||
@@ -39,7 +39,7 @@ static void help(struct udev *udev) {
|
||||
" -h --help Print this message\n"
|
||||
" --version Print version of the program\n\n"
|
||||
"Commands:\n"
|
||||
- , program_invocation_short_name);
|
||||
+ , "parity");
|
||||
|
||||
udev_builtin_list(udev);
|
||||
}
|
||||
diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c
|
||||
index 47fd924..a855412 100644
|
||||
--- a/src/udev/udevadm-test.c
|
||||
+++ b/src/udev/udevadm-test.c
|
||||
@@ -39,7 +39,7 @@ static void help(void) {
|
||||
" --version Show package version\n"
|
||||
" -a --action=ACTION Set action string\n"
|
||||
" -N --resolve-names=early|late|never When to resolve names\n"
|
||||
- , program_invocation_short_name);
|
||||
+ , "parity");
|
||||
}
|
||||
|
||||
static int adm_test(struct udev *udev, int argc, char *argv[]) {
|
||||
diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c
|
||||
index 4dc756a..67787d3 100644
|
||||
--- a/src/udev/udevadm-trigger.c
|
||||
+++ b/src/udev/udevadm-trigger.c
|
||||
@@ -92,7 +92,7 @@ static void help(void) {
|
||||
" -y --sysname-match=NAME Trigger devices with this /sys path\n"
|
||||
" --name-match=NAME Trigger devices with this /dev name\n"
|
||||
" -b --parent-match=NAME Trigger devices with that parent device\n"
|
||||
- , program_invocation_short_name);
|
||||
+ , "parity");
|
||||
}
|
||||
|
||||
static int adm_trigger(struct udev *udev, int argc, char *argv[]) {
|
||||
diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c
|
||||
index 3e57cf6..b03dfaa 100644
|
||||
--- a/src/udev/udevadm.c
|
||||
+++ b/src/udev/udevadm.c
|
||||
@@ -62,7 +62,7 @@ static int adm_help(struct udev *udev, int argc, char *argv[]) {
|
||||
printf("%s [--help] [--version] [--debug] COMMAND [COMMAND OPTIONS]\n\n"
|
||||
"Send control commands or test the device manager.\n\n"
|
||||
"Commands:\n"
|
||||
- , program_invocation_short_name);
|
||||
+ , "parity");
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(udevadm_cmds); i++)
|
||||
if (udevadm_cmds[i]->help != NULL)
|
||||
@@ -128,7 +128,7 @@ int main(int argc, char *argv[]) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
- fprintf(stderr, "%s: missing or unknown command\n", program_invocation_short_name);
|
||||
+ fprintf(stderr, "%s: missing or unknown command\n", "parity");
|
||||
rc = 2;
|
||||
out:
|
||||
mac_selinux_finish();
|
||||
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
|
||||
index cf826c6..4eec0af 100644
|
||||
--- a/src/udev/udevd.c
|
||||
+++ b/src/udev/udevd.c
|
||||
@@ -1041,7 +1041,7 @@ static void help(void) {
|
||||
" -t --event-timeout=SECONDS Seconds to wait before terminating an event\n"
|
||||
" -N --resolve-names=early|late|never\n"
|
||||
" When to resolve users and groups\n"
|
||||
- , program_invocation_short_name);
|
||||
+ , "parity");
|
||||
}
|
||||
|
||||
static int parse_argv(int argc, char *argv[]) {
|
||||
diff --git a/src/v4l_id/v4l_id.c b/src/v4l_id/v4l_id.c
|
||||
index 1dce0d5..f65badf 100644
|
||||
--- a/src/v4l_id/v4l_id.c
|
||||
+++ b/src/v4l_id/v4l_id.c
|
||||
@@ -49,7 +49,7 @@ int main(int argc, char *argv[]) {
|
||||
printf("%s [-h,--help] <device file>\n\n"
|
||||
"Video4Linux device identification.\n\n"
|
||||
" -h Print this message\n"
|
||||
- , program_invocation_short_name);
|
||||
+ , "parity");
|
||||
return 0;
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
diff --git a/src/shared/path-util.c b/src/shared/path-util.c
|
||||
index 0744563..7151356 100644
|
||||
--- a/src/shared/path-util.c
|
||||
+++ b/src/shared/path-util.c
|
||||
@@ -109,7 +109,7 @@ char *path_make_absolute_cwd(const char *p) {
|
||||
if (path_is_absolute(p))
|
||||
return strdup(p);
|
||||
|
||||
- cwd = get_current_dir_name();
|
||||
+ cwd = getcwd(malloc(128), 128);
|
||||
if (!cwd)
|
||||
return NULL;
|
||||
|
||||
@@ -3,7 +3,7 @@ WORKDIR /build
|
||||
|
||||
# install tools and dependencies
|
||||
RUN yum -y update&& \
|
||||
yum install -y git make gcc-c++ gcc file binutils
|
||||
yum install -y git make gcc-c++ gcc file binutils cmake
|
||||
|
||||
# install rustup
|
||||
RUN curl -sSf https://static.rust-lang.org/rustup.sh -o rustup.sh &&\
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM ubuntu:14.04
|
||||
FROM ubuntu:xenial
|
||||
MAINTAINER Parity Technologies <devops@parity.io>
|
||||
WORKDIR /build
|
||||
#ENV for build TAG
|
||||
@@ -13,6 +13,7 @@ RUN apt-get update && \
|
||||
# add-apt-repository
|
||||
software-properties-common \
|
||||
make \
|
||||
cmake \
|
||||
curl \
|
||||
wget \
|
||||
git \
|
||||
@@ -27,20 +28,7 @@ RUN apt-get update && \
|
||||
libudev-dev \
|
||||
pkg-config \
|
||||
dpkg-dev \
|
||||
# evmjit dependencies
|
||||
zlib1g-dev \
|
||||
libedit-dev \
|
||||
libudev-dev &&\
|
||||
# cmake and llvm ppa's. then update ppa's
|
||||
add-apt-repository -y "ppa:george-edison55/cmake-3.x" && \
|
||||
add-apt-repository "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main" && \
|
||||
apt-get update && \
|
||||
apt-get install -y --force-yes cmake llvm-3.7-dev && \
|
||||
# install evmjit
|
||||
git clone https://github.com/debris/evmjit && \
|
||||
cd evmjit && \
|
||||
mkdir build && cd build && \
|
||||
cmake .. && make && make install && cd && \
|
||||
# install rustup
|
||||
curl https://sh.rustup.rs -sSf | sh -s -- -y && \
|
||||
# rustup directory
|
||||
@@ -48,14 +36,13 @@ RUN apt-get update && \
|
||||
# show backtraces
|
||||
RUST_BACKTRACE=1 && \
|
||||
# build parity
|
||||
cd /build&&git clone https://github.com/paritytech/parity && \
|
||||
cd parity && \
|
||||
cd /build&&git clone https://github.com/paritytech/parity-ethereum && \
|
||||
cd parity-ethereum && \
|
||||
git pull&& \
|
||||
git checkout $BUILD_TAG && \
|
||||
cargo build --verbose --release --features final && \
|
||||
#ls /build/parity/target/release/parity && \
|
||||
strip /build/parity/target/release/parity && \
|
||||
file /build/parity/target/release/parity&&mkdir -p /parity&& cp /build/parity/target/release/parity /parity&&\
|
||||
strip /build/parity-ethereum/target/release/parity && \
|
||||
file /build/parity-ethereum/target/release/parity&&mkdir -p /parity&& cp /build/parity-ethereum/target/release/parity /parity&&\
|
||||
#cleanup Docker image
|
||||
rm -rf /root/.cargo&&rm -rf /root/.multirust&&rm -rf /root/.rustup&&rm -rf /build&&\
|
||||
apt-get purge -y \
|
||||
@@ -64,6 +51,7 @@ cd /build&&git clone https://github.com/paritytech/parity && \
|
||||
# add-apt-repository
|
||||
software-properties-common \
|
||||
make \
|
||||
cmake \
|
||||
curl \
|
||||
wget \
|
||||
git \
|
||||
@@ -72,11 +60,7 @@ cd /build&&git clone https://github.com/paritytech/parity && \
|
||||
binutils \
|
||||
file \
|
||||
pkg-config \
|
||||
dpkg-dev \
|
||||
# evmjit dependencies
|
||||
zlib1g-dev \
|
||||
libedit-dev \
|
||||
cmake llvm-3.7-dev&&\
|
||||
dpkg-dev &&\
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
# setup ENTRYPOINT
|
||||
EXPOSE 8080 8545 8180
|
||||
|
||||
@@ -6,7 +6,7 @@ RUN apt-get -y update && \
|
||||
apt-get install -y --force-yes --no-install-recommends \
|
||||
curl git make g++ gcc-aarch64-linux-gnu g++-aarch64-linux-gnu \
|
||||
libc6-arm64-cross libc6-dev-arm64-cross wget file ca-certificates \
|
||||
binutils-aarch64-linux-gnu \
|
||||
binutils-aarch64-linux-gnu cmake \
|
||||
&& \
|
||||
apt-get clean
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ RUN apt-get -y update && \
|
||||
apt-get install -y --force-yes --no-install-recommends \
|
||||
curl git make g++ gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf \
|
||||
libc6-dev-armhf-cross wget file ca-certificates \
|
||||
binutils-arm-linux-gnueabihf \
|
||||
binutils-arm-linux-gnueabihf cmake \
|
||||
&& \
|
||||
apt-get clean
|
||||
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
FROM ubuntu:14.04
|
||||
WORKDIR /build
|
||||
|
||||
# install tools and dependencies
|
||||
RUN apt-get update && \
|
||||
apt-get install -y \
|
||||
# make
|
||||
build-essential \
|
||||
# add-apt-repository
|
||||
software-properties-common \
|
||||
curl \
|
||||
wget \
|
||||
git \
|
||||
g++ \
|
||||
binutils \
|
||||
file \
|
||||
# evmjit dependencies
|
||||
zlib1g-dev \
|
||||
libedit-dev
|
||||
|
||||
# cmake and llvm ppas. then update ppas
|
||||
RUN add-apt-repository -y "ppa:george-edison55/cmake-3.x" && \
|
||||
add-apt-repository "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main" && \
|
||||
apt-get update && \
|
||||
apt-get install -y --force-yes cmake llvm-3.7-dev
|
||||
|
||||
# install evmjit
|
||||
RUN git clone https://github.com/debris/evmjit && \
|
||||
cd evmjit && \
|
||||
mkdir build && cd build && \
|
||||
cmake .. && make && make install && cd
|
||||
|
||||
# install rustup
|
||||
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
|
||||
|
||||
# rustup directory
|
||||
ENV PATH /root/.cargo/bin:$PATH
|
||||
|
||||
# show backtraces
|
||||
ENV RUST_BACKTRACE 1
|
||||
|
||||
# show tools
|
||||
RUN rustc -vV && \
|
||||
cargo -V && \
|
||||
gcc -v &&\
|
||||
g++ -v
|
||||
|
||||
# build parity
|
||||
ADD . /build/parity
|
||||
RUN cd parity && \
|
||||
cargo build --release --features ethcore/jit --verbose && \
|
||||
ls /build/parity/target/release/parity && \
|
||||
strip /build/parity/target/release/parity
|
||||
|
||||
RUN file /build/parity/target/release/parity
|
||||
|
||||
EXPOSE 8080 8545 8180
|
||||
ENTRYPOINT ["/build/parity/target/release/parity"]
|
||||
@@ -6,6 +6,7 @@ RUN apt-get update && \
|
||||
apt-get install -y \
|
||||
g++ \
|
||||
build-essential \
|
||||
cmake \
|
||||
curl \
|
||||
git \
|
||||
file \
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
Note: Parity 1.8 reached End-of-Life on 2018-03-22 (EOL).
|
||||
|
||||
## Parity [v1.8.11](https://github.com/paritytech/parity/releases/tag/v1.8.11) (2018-03-01)
|
||||
|
||||
Parity 1.8.11 is a bug-fix release to improve performance and stability.
|
||||
|
||||
The full list of included changes:
|
||||
|
||||
- Bump stable to 1.8.11 ([#8010](https://github.com/paritytech/parity/pull/8010))
|
||||
- Stable Backports ([#8008](https://github.com/paritytech/parity/pull/8008))
|
||||
- Reject too large packets in snapshot sync. ([#7977](https://github.com/paritytech/parity/pull/7977))
|
||||
- Increase max download limit to 128MB ([#7965](https://github.com/paritytech/parity/pull/7965))
|
||||
- Calculate proper keccak256/sha3 using parity. ([#7953](https://github.com/paritytech/parity/pull/7953))
|
||||
- Bump WebSockets ([#7952](https://github.com/paritytech/parity/pull/7952))
|
||||
|
||||
## Parity [v1.8.10](https://github.com/paritytech/parity/releases/tag/v1.8.10) (2018-02-20)
|
||||
|
||||
Parity 1.8.10 is a bug-fix release to improve performance and stability.
|
||||
|
||||
531
docs/CHANGELOG-1.9.md
Normal file
531
docs/CHANGELOG-1.9.md
Normal file
@@ -0,0 +1,531 @@
|
||||
## Parity [v1.9.7](https://github.com/paritytech/parity/releases/tag/v1.9.7) (2018-04-23)
|
||||
|
||||
Parity 1.9.7 is a bug-fix release to improve performance and stability.
|
||||
|
||||
The full list of included changes:
|
||||
|
||||
- Update Parity stable to 1.9.7 + Backports ([#8456](https://github.com/paritytech/parity/pull/8456))
|
||||
- Update Parity stable to 1.9.7
|
||||
- Allow 32-bit pipelines to fail ([#8454](https://github.com/paritytech/parity/pull/8454))
|
||||
- Disable 32-bit targets for Gitlab
|
||||
- Rename Linux pipelines
|
||||
- Update wasmi ([#8452](https://github.com/paritytech/parity/pull/8452))
|
||||
- Revert Cargo lock update from master
|
||||
- Fix Cargo.lock
|
||||
- Backports ([#8449](https://github.com/paritytech/parity/pull/8449))
|
||||
- Use forked app_dirs crate for reverted Windows dir behavior ([#8438](https://github.com/paritytech/parity/pull/8438))
|
||||
- Remove unused app_dirs dependency in CLI
|
||||
- Use forked app_dirs crate for reverted Windows dir behavior
|
||||
- Remove Tendermint extra_info due to seal inconsistencies ([#8367](https://github.com/paritytech/parity/pull/8367))
|
||||
- Improve VM executor stack size estimation rules ([#8439](https://github.com/paritytech/parity/pull/8439))
|
||||
- Improve VM executor stack size estimation rules
|
||||
- Typo: docs add "(Debug build)" comment
|
||||
- Fix an off by one typo and set minimal stack size
|
||||
- Use saturating_sub to avoid potential overflow
|
||||
- Upgrade crossbeam to 0.3
|
||||
|
||||
## Parity [v1.9.6](https://github.com/paritytech/parity/releases/tag/v1.9.6) (2018-04-16)
|
||||
|
||||
Parity 1.9.6 is a bug-fix release to improve performance and stability.
|
||||
|
||||
The full list of included changes:
|
||||
|
||||
- Bump app_dirs, fixes [#8315](https://github.com/paritytech/parity/issues/8315) ([#8355](https://github.com/paritytech/parity/pull/8355))
|
||||
- Fix Cargo lock
|
||||
- Backports ([#8352](https://github.com/paritytech/parity/pull/8352))
|
||||
- Update musicoin spec in line with gmc v2.6.2 ([#8242](https://github.com/paritytech/parity/pull/8242))
|
||||
- Supress TemporaryInvalid verification failures. ([#8256](https://github.com/paritytech/parity/pull/8256))
|
||||
- Include suicided accounts in state diff ([#8297](https://github.com/paritytech/parity/pull/8297))
|
||||
- Include suicided accounts in state diff
|
||||
- Shorten form match -> if let
|
||||
- Test suicide trace diff in State
|
||||
- Replace_home for password_files, reserved_peers and log_file ([#8324](https://github.com/paritytech/parity/pull/8324))
|
||||
- Replace_home for password_files, reserved_peers and log_file
|
||||
- Typo: arg_log_file is Option
|
||||
- Bump version in util/version
|
||||
- Bump stable to 1.9.6 ([#8348](https://github.com/paritytech/parity/pull/8348))
|
||||
- WASM libraries bump ([#8219](https://github.com/paritytech/parity/pull/8219))
|
||||
- Bump wasm libs ([#8171](https://github.com/paritytech/parity/pull/8171))
|
||||
- Bump wasmi version ([#8209](https://github.com/paritytech/parity/pull/8209))
|
||||
- Updated jsonrpc to include latest backports (1.9) ([#8182](https://github.com/paritytech/parity/pull/8182))
|
||||
- Updated jsonrpc to include latest backports (1.9)
|
||||
- Update dependencies.
|
||||
|
||||
## Parity [v1.9.5](https://github.com/paritytech/parity/releases/tag/v1.9.5) (2018-03-21)
|
||||
|
||||
Parity 1.9.5 is a bug-fix release to improve performance and stability. This release marks the 1.9 track _stable_.
|
||||
|
||||
We are excited to announce support for **Wasm Smart Contracts on Kovan network**. The hard-fork to activate the Wasm-VM will take place on block `6600000`.
|
||||
|
||||
The full list of included changes:
|
||||
|
||||
- Do a meaningful commit that does not contain the words "ci" or "skip"
|
||||
- Triggering build for stable.
|
||||
- Postpone Kovan hard fork ([#8137](https://github.com/paritytech/parity/pull/8137)) ([#8152](https://github.com/paritytech/parity/pull/8152))
|
||||
- Postpone Kovan hard fork ([#8137](https://github.com/paritytech/parity/pull/8137))
|
||||
- ethcore: postpone Kovan hard fork
|
||||
- util: update version fork metadata
|
||||
- WASM libraries bump ([#7970](https://github.com/paritytech/parity/pull/7970))
|
||||
- update wasmi, parity-wasm, wasm-utils to latest version
|
||||
- Update to new wasmi & error handling
|
||||
- also utilize new stack limiter
|
||||
- fix typo
|
||||
- replace dependency url
|
||||
- Cargo.lock update
|
||||
- Fix scripts. Force JS rebuild. ([#8144](https://github.com/paritytech/parity/pull/8144))
|
||||
- Stable Backports ([#8133](https://github.com/paritytech/parity/pull/8133))
|
||||
- updater: apply exponential backoff after download failure ([#8059](https://github.com/paritytech/parity/pull/8059))
|
||||
- updater: apply exponential backoff after download failure
|
||||
- updater: reset backoff on new release
|
||||
- Limit incoming connections. ([#8060](https://github.com/paritytech/parity/pull/8060))
|
||||
- Limit ingress connections
|
||||
- Optimized handshakes logging
|
||||
- Max code size on Kovan ([#8067](https://github.com/paritytech/parity/pull/8067))
|
||||
- Enable code size limit on kovan
|
||||
- Fix formatting.
|
||||
- add some dos protection ([#8084](https://github.com/paritytech/parity/pull/8084))
|
||||
- more dos protection ([#8104](https://github.com/paritytech/parity/pull/8104))
|
||||
- Const time comparison ([#8113](https://github.com/paritytech/parity/pull/8113))
|
||||
- Use `subtle::slices_equal` for constant time comparison.
|
||||
- Also update the existing version of subtle in `ethcrypto` from
|
||||
- 0.1 to 0.5
|
||||
- Test specifically for InvalidPassword error.
|
||||
- revert removing blooms ([#8066](https://github.com/paritytech/parity/pull/8066))
|
||||
- Revert "fix traces, removed bloomchain crate, closes [#7228](https://github.com/paritytech/parity/pull/7228), closes [#7167](https://github.com/paritytech/parity/pull/7167)"
|
||||
- Revert "fixed broken logs ([#7934](https://github.com/paritytech/parity/pull/7934))"
|
||||
- fixed broken logs
|
||||
- bring back old lock order
|
||||
- remove migration v13
|
||||
- revert CURRENT_VERSION to 12 in migration.rs
|
||||
- Fix compilation.
|
||||
- Check one step deeper if we're on release track branches
|
||||
- add missing pr
|
||||
- Fix blooms?
|
||||
- Fix tests compiilation.
|
||||
- Fix size.
|
||||
- Check one step deeper if we're on release track branches ([#8134](https://github.com/paritytech/parity/pull/8134)) ([#8140](https://github.com/paritytech/parity/pull/8140))
|
||||
- Trigger js build. ([#8121](https://github.com/paritytech/parity/pull/8121))
|
||||
- Stable backports ([#8055](https://github.com/paritytech/parity/pull/8055))
|
||||
- CI: Fix cargo cache ([#7968](https://github.com/paritytech/parity/pull/7968))
|
||||
- Fix cache
|
||||
Blocking waiting for file lock on the registry index
|
||||
- Only clean locked cargo cache on windows
|
||||
- fixed ethstore sign ([#8026](https://github.com/paritytech/parity/pull/8026))
|
||||
- fix cache & snapcraft CI build ([#8052](https://github.com/paritytech/parity/pull/8052))
|
||||
- Add MCIP-6 Byzyantium transition to Musicoin spec ([#7841](https://github.com/paritytech/parity/pull/7841))
|
||||
- Add test chain spec for musicoin byzantium testnet
|
||||
- Add MCIP-6 Byzyantium transition to Musicoin spec
|
||||
- Update mcip6_byz.json
|
||||
- ethcore: update musicoin byzantium block number
|
||||
- ethcore: update musicoin bootnodes
|
||||
- Update musicoin.json
|
||||
- More bootnodes.
|
||||
- Optimize JS build ([#8093](https://github.com/paritytech/parity/pull/8093))
|
||||
- Extract common chunks plugin.
|
||||
- Fix common CSS.
|
||||
- Fix js push for stable.
|
||||
- Remove arguments to getPlugins.
|
||||
- Stable Backports ([#8058](https://github.com/paritytech/parity/pull/8058))
|
||||
- fixed parsing ethash seals and verify_block_undordered ([#8031](https://github.com/paritytech/parity/pull/8031))
|
||||
- fix for verify_block_basic crashing on invalid transaction rlp ([#8032](https://github.com/paritytech/parity/pull/8032))
|
||||
- Make 1.9 stable ([#8023](https://github.com/paritytech/parity/pull/8023))
|
||||
- Make 1.9 stable
|
||||
- Bump stable to 1.9.5
|
||||
- Fix gitlab builds
|
||||
|
||||
## Parity [v1.9.4](https://github.com/paritytech/parity/releases/tag/v1.9.4) (2018-03-01)
|
||||
|
||||
Parity 1.9.4 is a bug-fix release to improve performance and stability.
|
||||
|
||||
The full list of included changes:
|
||||
|
||||
- Bump beta to 1.9.4 ([#8016](https://github.com/paritytech/parity/pull/8016))
|
||||
- Beta Backports ([#8011](https://github.com/paritytech/parity/pull/8011))
|
||||
- Fix traces, removed bloomchain crate ([#7979](https://github.com/paritytech/parity/pull/7979))
|
||||
- Reject too large packets in snapshot sync. ([#7977](https://github.com/paritytech/parity/pull/7977))
|
||||
- Fixed broken logs ([#7934](https://github.com/paritytech/parity/pull/7934))
|
||||
- Increase max download limit to 128MB ([#7965](https://github.com/paritytech/parity/pull/7965))
|
||||
- Calculate proper keccak256/sha3 using parity. ([#7953](https://github.com/paritytech/parity/pull/7953))
|
||||
- Bump WebSockets ([#7952](https://github.com/paritytech/parity/pull/7952))
|
||||
- Hardware-wallet/usb-subscribe-refactor ([#7860](https://github.com/paritytech/parity/pull/7860))
|
||||
- Make block generator easier to use ([#7888](https://github.com/paritytech/parity/pull/7888))
|
||||
|
||||
## Parity [v1.9.3](https://github.com/paritytech/parity/releases/tag/v1.9.3) (2018-02-20)
|
||||
|
||||
Parity 1.9.3 is a bug-fix release to improve performance and stability.
|
||||
|
||||
The full list of included changes:
|
||||
|
||||
- Backports ([#7945](https://github.com/paritytech/parity/pull/7945))
|
||||
- ECIP 1041 - Remove Difficulty Bomb ([#7905](https://github.com/paritytech/parity/pull/7905))
|
||||
- spec: Validate required divisor fields are not 0 ([#7933](https://github.com/paritytech/parity/pull/7933))
|
||||
- Kovan WASM fork code ([#7849](https://github.com/paritytech/parity/pull/7849))
|
||||
- Gitlab Cargo Cache ([#7944](https://github.com/paritytech/parity/pull/7944))
|
||||
- Bump react-qr-reader ([#7943](https://github.com/paritytech/parity/pull/7943))
|
||||
- Update react-qr-reader
|
||||
- Explicit webrtc-adapter dependency (package-lock workaround)
|
||||
- Iframe with allow (QR, new Chrome policy)
|
||||
- Backport of [#7844](https://github.com/paritytech/parity/pull/7844) and [#7917](https://github.com/paritytech/parity/pull/7917) to beta ([#7940](https://github.com/paritytech/parity/pull/7940))
|
||||
- Randomize the peer we dispatch to
|
||||
- Fix a division by zero in light client RPC handler
|
||||
- Wallet allowJsEval: true ([#7913](https://github.com/paritytech/parity/pull/7913))
|
||||
- Wallet allowJsEval: true
|
||||
- Fix unsafe wallet.
|
||||
- Enable unsafe-eval for all dapps.
|
||||
- Fix CSP for dapps that require eval. ([#7867](https://github.com/paritytech/parity/pull/7867)) ([#7903](https://github.com/paritytech/parity/pull/7903))
|
||||
- Add allowJsEval to manifest.
|
||||
- Enable 'unsafe-eval' if requested in manifest.
|
||||
- Fix snap build beta ([#7895](https://github.com/paritytech/parity/pull/7895))
|
||||
- Fix snapcraft grade to stable ([#7894](https://github.com/paritytech/parity/pull/7894))
|
||||
- Backport Master CI PRs to Beta ([#7890](https://github.com/paritytech/parity/pull/7890))
|
||||
- Add binary identifiers and sha256sum to builds ([#7830](https://github.com/paritytech/parity/pull/7830))
|
||||
- Fix checksums and auto-update push ([#7846](https://github.com/paritytech/parity/pull/7846))
|
||||
- Update gitlab-build.sh ([#7855](https://github.com/paritytech/parity/pull/7855))
|
||||
- Fix installer binary names for macos and windows ([#7881](https://github.com/paritytech/parity/pull/7881))
|
||||
- Update gitlab-test.sh ([#7883](https://github.com/paritytech/parity/pull/7883))
|
||||
- Fix snapcraft nightly ([#7884](https://github.com/paritytech/parity/pull/7884))
|
||||
- Backport Core PRs to beta ([#7891](https://github.com/paritytech/parity/pull/7891))
|
||||
- Update back-references more aggressively after answering from cache ([#7578](https://github.com/paritytech/parity/pull/7578))
|
||||
- Updated WASM Runtime & new interpreter (wasmi) ([#7796](https://github.com/paritytech/parity/pull/7796))
|
||||
- Adjust storage update evm-style ([#7812](https://github.com/paritytech/parity/pull/7812))
|
||||
- Add new EF ropstens nodes ([#7824](https://github.com/paritytech/parity/pull/7824))
|
||||
- Store updater metadata in a single place ([#7832](https://github.com/paritytech/parity/pull/7832))
|
||||
- WASM: Disable internal memory ([#7842](https://github.com/paritytech/parity/pull/7842))
|
||||
- Add a timeout for light client sync requests ([#7848](https://github.com/paritytech/parity/pull/7848))
|
||||
- Flush keyfiles. Resolves [#7632](https://github.com/paritytech/parity/issues/7632) ([#7868](https://github.com/paritytech/parity/pull/7868))
|
||||
- Fix wallet import ([#7873](https://github.com/paritytech/parity/pull/7873))
|
||||
|
||||
## Parity [v1.9.2](https://github.com/paritytech/parity/releases/tag/v1.9.2) (2018-02-02)
|
||||
|
||||
Parity 1.9.2 is a bug-fix release to improve performance and stability. It adds additional bootnodes for the Ropsten test network.
|
||||
|
||||
The full list of included changes:
|
||||
|
||||
- Backports beta ([#7780](https://github.com/paritytech/parity/pull/7780))
|
||||
- Bump beta to 1.9.2
|
||||
- Update ropsten.json ([#7776](https://github.com/paritytech/parity/pull/7776))
|
||||
- Snapcraft push beta
|
||||
|
||||
## Parity [v1.9.1](https://github.com/paritytech/parity/releases/tag/v1.9.1) (2018-02-01)
|
||||
|
||||
Parity 1.9.1 is a bug-fix release to improve performance and stability. It restores ERC-20 token balances, improves networking, fixes database corruptions on client shutdown, and fixes issues with the `--password` command-line flag. Happy syncing, fellow Ethereans!
|
||||
|
||||
In addition, this stabilizes Kovan and other Proof-of-Authority networks. If you run a network with AuRa engine, updating is highly encouraged!
|
||||
|
||||
The full list of included changes:
|
||||
|
||||
- Beta Backports ([#7756](https://github.com/paritytech/parity/pull/7756))
|
||||
- Filter-out nodes.json ([#7716](https://github.com/paritytech/parity/pull/7716))
|
||||
- Filter-out nodes.json
|
||||
- network: sort node table nodes by failure ratio
|
||||
- network: fix node table tests
|
||||
- network: fit node failure percentage into buckets of 5%
|
||||
- network: consider number of attempts in sorting of node table
|
||||
- network: fix node table grumbles
|
||||
- Fix client not being dropped on shutdown ([#7695](https://github.com/paritytech/parity/pull/7695))
|
||||
- parity: wait for client to drop on shutdown
|
||||
- parity: fix grumbles in shutdown wait
|
||||
- parity: increase shutdown timeouts
|
||||
- Wrap --help output to 120 characters ([#7626](https://github.com/paritytech/parity/pull/7626))
|
||||
- Update Clap dependency and remove workarounds
|
||||
- WIP
|
||||
- Remove line breaks in help messages for now
|
||||
- Multiple values can only be separated by commas (closes [#7428](https://github.com/paritytech/parity/issues/7428))
|
||||
- Grumbles; refactor repeating code; add constant
|
||||
- Use a single Wrapper rather than allocate a new one for each call
|
||||
- Wrap --help to 120 characters rather than 100 characte
|
||||
- Token filter balances (throttle) ([#7742](https://github.com/paritytech/parity/pull/7742))
|
||||
- Token filter balances (throttle)
|
||||
- Cleanups
|
||||
- Remove unused uniq
|
||||
- Update @parity/shared to 2.2.23
|
||||
- Remove unused code paths
|
||||
- Bump beta to 1.9.1 ([#7751](https://github.com/paritytech/parity/pull/7751))
|
||||
- Explicitly add branch name ([#7754](https://github.com/paritytech/parity/pull/7754))
|
||||
- Explicitly add branch name
|
||||
- Fix cargo update branch to beta
|
||||
- Revert revert revert ([#7715](https://github.com/paritytech/parity/pull/7715))
|
||||
- This reverts commit 568dc33.
|
||||
|
||||
## Parity [v1.9.0](https://github.com/paritytech/parity/releases/tag/v1.9.0) "Velocity" (2018-01-25)
|
||||
|
||||
We are happy to announce our newest Parity 1.9 release. Among others, it enables the following features:
|
||||
|
||||
- It integrates the fully reworked Parity Wallet and DApps browser (a.k.a. "UI 2.0", [#6819](https://github.com/paritytech/parity/pull/6819)).
|
||||
- It enables devp2p snappy compression ([#6683](https://github.com/paritytech/parity/pull/6683)).
|
||||
- AuRa Proof-of-Authority chains now disable uncles by default ([#7006](https://github.com/paritytech/parity/pull/7006)). Existing PoA chains can go through a "maximum uncle count transition" to achieve more stability ([#7196](https://github.com/paritytech/parity/pull/7196)).
|
||||
- Added Expanse's Byzantium hard-fork ([#7463](https://github.com/paritytech/parity/pull/7463)).
|
||||
- Added support for Ellaism chain ([#7222](https://github.com/paritytech/parity/pull/7222)).
|
||||
|
||||
Further, users upgrading from 1.8 should acknowledge the following changes:
|
||||
|
||||
- Fixed DELEGATECALL's from/to field ([#7568](https://github.com/paritytech/parity/pull/7568)).
|
||||
- Set zero nonce and gas price for calls by default ([#6954](https://github.com/paritytech/parity/pull/6954)).
|
||||
- Create pending blocks with all transactions from the queue ([#6942](https://github.com/paritytech/parity/pull/6942)).
|
||||
- Remove RPC parameter leniency now that Mist formats correctly ([#6651](https://github.com/paritytech/parity/pull/6651)). Parity stops accepting decimal-formatted block numbers and stops parsing the empty string as empty bytes.
|
||||
- Public nodes do not support the user interface anymore. If you are running a public node, please stay on the 1.8 branch of the stable releases.
|
||||
|
||||
Additional noteworthy changes:
|
||||
|
||||
- `ethstore` and `ethkey` have been significantly improved ([#6961](https://github.com/paritytech/parity/pull/6961)):
|
||||
- `ethstore` now supports brute forcing pre-sale wallets given a password list for recovery.
|
||||
- `ethkey` now supports multi-threaded generation of prefix-matching addresses.
|
||||
- `ethkey` now supports prefix-matching brain wallets.
|
||||
- `ethkey` now supports brain-wallets recovery-phrases lookup. This helps to find a correct phrase if you know the address you want to get yet you made a typo backing the phrase up, or forgot a word.
|
||||
|
||||
Read more about Parity 1.9 in our [blog post](http://paritytech.io/velocity-the-fastest-parity-released/).
|
||||
|
||||
The full list of included changes:
|
||||
|
||||
- Add scroll when when too many accounts ([#7677](https://github.com/paritytech/parity/pull/7677)) ([#7679](https://github.com/paritytech/parity/pull/7679))
|
||||
- Update installer.nsi
|
||||
- Fix conditions in gitlab-test ([#7676](https://github.com/paritytech/parity/pull/7676))
|
||||
- Fix conditions in gitlab-test
|
||||
- Update gitlab-test.sh
|
||||
- Remove cargo cache
|
||||
- Backports to beta ([#7660](https://github.com/paritytech/parity/pull/7660))
|
||||
- Improve handling of RocksDB corruption ([#7630](https://github.com/paritytech/parity/pull/7630))
|
||||
- Kvdb-rocksdb: update rust-rocksdb version
|
||||
- Kvdb-rocksdb: mark corruptions and attempt repair on db open
|
||||
- Kvdb-rocksdb: better corruption detection on open
|
||||
- Kvdb-rocksdb: add corruption_file_name const
|
||||
- Kvdb-rocksdb: rename mark_corruption to check_for_corruption
|
||||
- Hardening of CSP ([#7621](https://github.com/paritytech/parity/pull/7621))
|
||||
- Fixed delegatecall's from/to ([#7568](https://github.com/paritytech/parity/pull/7568))
|
||||
- Fixed delegatecall's from/to, closes [#7166](https://github.com/paritytech/parity/issues/7166)
|
||||
- Added tests for delegatecall traces, [#7167](https://github.com/paritytech/parity/issues/7167)
|
||||
- Light client RPCs ([#7603](https://github.com/paritytech/parity/pull/7603))
|
||||
- Implement registrar.
|
||||
- Implement eth_getCode
|
||||
- Don't wait for providers.
|
||||
- Don't wait for providers.
|
||||
- Fix linting and wasm tests.
|
||||
- Problem: AttachedProtocols don't get registered ([#7610](https://github.com/paritytech/parity/pull/7610))
|
||||
- Fix Temporarily Invalid blocks handling ([#7613](https://github.com/paritytech/parity/pull/7613))
|
||||
- Handle temporarily invalid blocks in sync.
|
||||
- Fix tests.
|
||||
- Add docker build for beta ([#7671](https://github.com/paritytech/parity/pull/7671))
|
||||
- Add docker build for beta
|
||||
- Add cargo cache
|
||||
- Fix snapcraft build for beta ([#7670](https://github.com/paritytech/parity/pull/7670))
|
||||
- Update Parity.pkgproj
|
||||
- update gitlab build from master
|
||||
- Update references to dapp sources ([#7634](https://github.com/paritytech/parity/pull/7634)) ([#7636](https://github.com/paritytech/parity/pull/7636))
|
||||
- Update tokenreg ([#7618](https://github.com/paritytech/parity/pull/7618)) ([#7619](https://github.com/paritytech/parity/pull/7619))
|
||||
- Fix cache:key ([#7598](https://github.com/paritytech/parity/pull/7598))
|
||||
- Make 1.9 beta ([#7533](https://github.com/paritytech/parity/pull/7533))
|
||||
- Trigger js-precompiled ([#7535](https://github.com/paritytech/parity/pull/7535))
|
||||
- RocksDB fix ([#7512](https://github.com/paritytech/parity/pull/7512))
|
||||
- Update js-api ([#7510](https://github.com/paritytech/parity/pull/7510))
|
||||
- Expose default gas price percentile configuration in CLI ([#7497](https://github.com/paritytech/parity/pull/7497))
|
||||
- Use https connection ([#7503](https://github.com/paritytech/parity/pull/7503))
|
||||
- More thorough changes detection ([#7472](https://github.com/paritytech/parity/pull/7472))
|
||||
- Fix small layout issues ([#7500](https://github.com/paritytech/parity/pull/7500))
|
||||
- Show all accounts on Topbar ([#7498](https://github.com/paritytech/parity/pull/7498))
|
||||
- Update Parity Mainnet Bootnodes ([#7476](https://github.com/paritytech/parity/pull/7476))
|
||||
- Fixed panic when io is not available for export block ([#7495](https://github.com/paritytech/parity/pull/7495))
|
||||
- Advance AuRa step as far as we can and prevent invalid blocks. ([#7451](https://github.com/paritytech/parity/pull/7451))
|
||||
- Update package-lock in js-old ([#7494](https://github.com/paritytech/parity/pull/7494))
|
||||
- Update issue template and readme ([#7450](https://github.com/paritytech/parity/pull/7450))
|
||||
- Update package-lock.json pinned versions ([#7492](https://github.com/paritytech/parity/pull/7492))
|
||||
- Explicit pre-precompiled push checkout ([#7474](https://github.com/paritytech/parity/pull/7474))
|
||||
- Trigger js-precompiled ([#7473](https://github.com/paritytech/parity/pull/7473))
|
||||
- Expanse Byzantium update w/ correct metropolis difficulty increment divisor ([#7463](https://github.com/paritytech/parity/pull/7463))
|
||||
- Updated icons ([#7469](https://github.com/paritytech/parity/pull/7469))
|
||||
- Cleanup certifications ([#7454](https://github.com/paritytech/parity/pull/7454))
|
||||
- Fix css lint (updated stylelint) ([#7471](https://github.com/paritytech/parity/pull/7471))
|
||||
- Upgrade markdown-loader & marked ([#7467](https://github.com/paritytech/parity/pull/7467))
|
||||
- Remove JS test for removed code ([#7461](https://github.com/paritytech/parity/pull/7461))
|
||||
- Pull in dapp-status ([#7457](https://github.com/paritytech/parity/pull/7457))
|
||||
- Bump openssl crate ([#7455](https://github.com/paritytech/parity/pull/7455))
|
||||
- Signer updates from global Redux state ([#7452](https://github.com/paritytech/parity/pull/7452))
|
||||
- Remove expanse chain ([#7437](https://github.com/paritytech/parity/pull/7437))
|
||||
- Store tokens with repeatable id ([#7435](https://github.com/paritytech/parity/pull/7435))
|
||||
- Strict config parsing ([#7433](https://github.com/paritytech/parity/pull/7433))
|
||||
- Upgrade to RocksDB 5.8.8 and tune settings to reduce space amplification ([#7348](https://github.com/paritytech/parity/pull/7348))
|
||||
- Fix status layout ([#7432](https://github.com/paritytech/parity/pull/7432))
|
||||
- Fix tracing failed calls. ([#7412](https://github.com/paritytech/parity/pull/7412))
|
||||
- Problem: sending any Whisper message fails ([#7421](https://github.com/paritytech/parity/pull/7421))
|
||||
- Wait for future blocks in AuRa ([#7368](https://github.com/paritytech/parity/pull/7368))
|
||||
- Fix final feature. ([#7426](https://github.com/paritytech/parity/pull/7426))
|
||||
- Use RwLock for state DB ([#7425](https://github.com/paritytech/parity/pull/7425))
|
||||
- Update branding on UI ([#7370](https://github.com/paritytech/parity/pull/7370))
|
||||
- Changelog for 1.8.5 and 1.7.11 ([#7401](https://github.com/paritytech/parity/pull/7401))
|
||||
- Added checking tx-type using transactions permission contract for miners ([#7359](https://github.com/paritytech/parity/pull/7359))
|
||||
- Standalone dir crate, replaces [#7383](https://github.com/paritytech/parity/issues/7383) ([#7409](https://github.com/paritytech/parity/pull/7409))
|
||||
- SecretStore: secretstore_signRawHash method ([#7336](https://github.com/paritytech/parity/pull/7336))
|
||||
- SecretStore: return error 404 when there's no key shares for given key on all nodes ([#7331](https://github.com/paritytech/parity/pull/7331))
|
||||
- SecretStore: PoA integration initial version ([#7101](https://github.com/paritytech/parity/pull/7101))
|
||||
- Update bootnodes ([#7363](https://github.com/paritytech/parity/pull/7363))
|
||||
- Fix default CORS settings. ([#7387](https://github.com/paritytech/parity/pull/7387))
|
||||
- Fix version ([#7390](https://github.com/paritytech/parity/pull/7390))
|
||||
- Wasm runtime update ([#7356](https://github.com/paritytech/parity/pull/7356))
|
||||
- Parity-version pr reopen ([#7136](https://github.com/paritytech/parity/pull/7136))
|
||||
- Get rid of clippy remainings. ([#7355](https://github.com/paritytech/parity/pull/7355))
|
||||
- Avoid using ok_or with allocated argument ([#7357](https://github.com/paritytech/parity/pull/7357))
|
||||
- Make accounts refresh time configurable. ([#7345](https://github.com/paritytech/parity/pull/7345))
|
||||
- Enable traces for DEV chain ([#7327](https://github.com/paritytech/parity/pull/7327))
|
||||
- Problem: AuRa's unsafeties around step duration ([#7282](https://github.com/paritytech/parity/pull/7282))
|
||||
- Problem: Cargo.toml file contains [project] key ([#7346](https://github.com/paritytech/parity/pull/7346))
|
||||
- Fix broken flex modal layouts ([#7343](https://github.com/paritytech/parity/pull/7343))
|
||||
- Fix dappIcon & Fix Signer Pending ([#7338](https://github.com/paritytech/parity/pull/7338))
|
||||
- Fix wallet token/badge icons not showing up ([#7333](https://github.com/paritytech/parity/pull/7333))
|
||||
- Add Ellaism coin in chain config ([#7222](https://github.com/paritytech/parity/pull/7222))
|
||||
- Update bootnodes ([#7296](https://github.com/paritytech/parity/pull/7296))
|
||||
- Adds `personal_signTransaction` RPC method ([#6991](https://github.com/paritytech/parity/pull/6991))
|
||||
- Fix double initialization of embeded providers. ([#7326](https://github.com/paritytech/parity/pull/7326))
|
||||
- Transaction Pool re-implementation ([#6994](https://github.com/paritytech/parity/pull/6994))
|
||||
- UI package bump ([#7318](https://github.com/paritytech/parity/pull/7318))
|
||||
- Test framework and basic test for whisper ([#7011](https://github.com/paritytech/parity/pull/7011))
|
||||
- CI js-precompiled trigger ([#7316](https://github.com/paritytech/parity/pull/7316))
|
||||
- Fix inject.js & Signer store duplication ([#7299](https://github.com/paritytech/parity/pull/7299))
|
||||
- Detect different node, same-key signing in aura ([#7245](https://github.com/paritytech/parity/pull/7245))
|
||||
- New warp enodes ([#7287](https://github.com/paritytech/parity/pull/7287))
|
||||
- CSS fixes for v1 ([#7285](https://github.com/paritytech/parity/pull/7285))
|
||||
- Wallet subscriptions & refresh ([#7283](https://github.com/paritytech/parity/pull/7283))
|
||||
- Update inject web3 dependencies ([#7286](https://github.com/paritytech/parity/pull/7286))
|
||||
- Some padding around dapp image ([#7276](https://github.com/paritytech/parity/pull/7276))
|
||||
- Expand available middleware methods ([#7275](https://github.com/paritytech/parity/pull/7275))
|
||||
- Inject parity script to all dapps // Expand dapps to any ZIP file ([#7260](https://github.com/paritytech/parity/pull/7260))
|
||||
- New Homepage ([#7266](https://github.com/paritytech/parity/pull/7266))
|
||||
- Update kovan HF block number. ([#7259](https://github.com/paritytech/parity/pull/7259))
|
||||
- CHANGELOG for 1.7.10 and 1.8.4 ([#7265](https://github.com/paritytech/parity/pull/7265))
|
||||
- Remove extraneous id hashing ([#7269](https://github.com/paritytech/parity/pull/7269))
|
||||
- Simplify status + content display overlaps/page fixing ([#7264](https://github.com/paritytech/parity/pull/7264))
|
||||
- UI redirect to 127.0.0.1 when localhost requested ([#7236](https://github.com/paritytech/parity/pull/7236))
|
||||
- Usability improvements to security token Dialog [#7112](https://github.com/paritytech/parity/issues/7112) ([#7134](https://github.com/paritytech/parity/pull/7134))
|
||||
- Don't display unneeded notifications ([#7237](https://github.com/paritytech/parity/pull/7237))
|
||||
- Reduce max block timestamp drift to 15 seconds ([#7240](https://github.com/paritytech/parity/pull/7240))
|
||||
- Increase allowed time drift to 10s. ([#7238](https://github.com/paritytech/parity/pull/7238))
|
||||
- Improve building from source ([#7239](https://github.com/paritytech/parity/pull/7239))
|
||||
- Fix/Update method permissions ([#7233](https://github.com/paritytech/parity/pull/7233))
|
||||
- Fix aura difficulty race ([#7198](https://github.com/paritytech/parity/pull/7198))
|
||||
- Dependency updates ([#7226](https://github.com/paritytech/parity/pull/7226))
|
||||
- Display all dapps (shell) & wallet tabs (v1) by default ([#7213](https://github.com/paritytech/parity/pull/7213))
|
||||
- Rework dapps list ([#7206](https://github.com/paritytech/parity/pull/7206))
|
||||
- Add contributing guidelines and code of conduct. ([#7157](https://github.com/paritytech/parity/pull/7157))
|
||||
- Make Signing Requests more visible ([#7204](https://github.com/paritytech/parity/pull/7204))
|
||||
- Send each log as a separate notification ([#7175](https://github.com/paritytech/parity/pull/7175))
|
||||
- Deleting a mistake comment in calc difficulty ([#7154](https://github.com/paritytech/parity/pull/7154))
|
||||
- Maximum uncle count transition ([#7196](https://github.com/paritytech/parity/pull/7196))
|
||||
- Update FirstRun for UI-2 ([#7195](https://github.com/paritytech/parity/pull/7195))
|
||||
- Update mocha import stubs ([#7191](https://github.com/paritytech/parity/pull/7191))
|
||||
- Escape inifinite loop in estimte_gas ([#7075](https://github.com/paritytech/parity/pull/7075))
|
||||
- New account selector UI in top bar ([#7179](https://github.com/paritytech/parity/pull/7179))
|
||||
- Removed ethcore-util dependency from ethcore-network ([#7180](https://github.com/paritytech/parity/pull/7180))
|
||||
- WASM test runner utility upgrade ([#7147](https://github.com/paritytech/parity/pull/7147))
|
||||
- React 16 ([#7174](https://github.com/paritytech/parity/pull/7174))
|
||||
- Assorted improvements for ethstore and ethkey ([#6961](https://github.com/paritytech/parity/pull/6961))
|
||||
- Delete unused package.json (dist bundles) ([#7173](https://github.com/paritytech/parity/pull/7173))
|
||||
- Remove *.css.map & *.js.map ([#7168](https://github.com/paritytech/parity/pull/7168))
|
||||
- Use git flag to remove old js artifacts ([#7165](https://github.com/paritytech/parity/pull/7165))
|
||||
- Cleanup JS build artifacts ([#7164](https://github.com/paritytech/parity/pull/7164))
|
||||
- Fixes typo in user config path ([#7159](https://github.com/paritytech/parity/pull/7159))
|
||||
- Pull in new dapp-{methods,visible} dapps ([#7150](https://github.com/paritytech/parity/pull/7150))
|
||||
- WASM test runner utility ([#7142](https://github.com/paritytech/parity/pull/7142))
|
||||
- WASM Remove blockhash error ([#7121](https://github.com/paritytech/parity/pull/7121))
|
||||
- ECIP-1039: Monetary policy rounding specification ([#7067](https://github.com/paritytech/parity/pull/7067))
|
||||
- Fixed `RotatingLogger` after migrating to new arrayvec ([#7129](https://github.com/paritytech/parity/pull/7129))
|
||||
- Push to correct shell branch ([#7135](https://github.com/paritytech/parity/pull/7135))
|
||||
- Update js-precompiled ref, trigger JS build ([#7132](https://github.com/paritytech/parity/pull/7132))
|
||||
- Fixed build && test ([#7128](https://github.com/paritytech/parity/pull/7128))
|
||||
- Update packages, pull in compiled-only repos ([#7125](https://github.com/paritytech/parity/pull/7125))
|
||||
- Cleanup top bar, add Home icon for navigation ([#7118](https://github.com/paritytech/parity/pull/7118))
|
||||
- WASM storage_read and storage_write don't return anything ([#7110](https://github.com/paritytech/parity/pull/7110))
|
||||
- Local dapp development URL ([#7100](https://github.com/paritytech/parity/pull/7100))
|
||||
- Remove unused and duplicated files in js-old ([#7082](https://github.com/paritytech/parity/pull/7082))
|
||||
- Optimize & group dapp requests ([#7083](https://github.com/paritytech/parity/pull/7083))
|
||||
- WASM parse payload from panics ([#7097](https://github.com/paritytech/parity/pull/7097))
|
||||
- Fix no-default-features. ([#7096](https://github.com/paritytech/parity/pull/7096))
|
||||
- Updated eth-secp256k1 ([#7090](https://github.com/paritytech/parity/pull/7090))
|
||||
- Improve Github Issue Template ([#7099](https://github.com/paritytech/parity/pull/7099))
|
||||
- Changes necessary to upload crates to crates.io ([#7020](https://github.com/paritytech/parity/pull/7020))
|
||||
- Reopened 6860 - iterate over both buffered and unbuffered database entries ([#7048](https://github.com/paritytech/parity/pull/7048))
|
||||
- SecretStore: servers set change session api ([#6925](https://github.com/paritytech/parity/pull/6925))
|
||||
- Disable uncles by default ([#7006](https://github.com/paritytech/parity/pull/7006))
|
||||
- Squashed ethcore-network changes which introduce error-chain ([#7040](https://github.com/paritytech/parity/pull/7040))
|
||||
- Removed redundant imports ([#7057](https://github.com/paritytech/parity/pull/7057))
|
||||
- CHANGELOG for 1.7.8, 1.7.9, 1.8.2, and 1.8.3 ([#7055](https://github.com/paritytech/parity/pull/7055))
|
||||
- Properly display Signer errors (Snackbar display popup) ([#7053](https://github.com/paritytech/parity/pull/7053))
|
||||
- Add the desktop file for the snap ([#7059](https://github.com/paritytech/parity/pull/7059))
|
||||
- Small performance gain in allocations ([#7054](https://github.com/paritytech/parity/pull/7054))
|
||||
- Bump JSON-RPC version ([#7051](https://github.com/paritytech/parity/pull/7051))
|
||||
- Fix nonce reservation ([#7025](https://github.com/paritytech/parity/pull/7025))
|
||||
- Fixed ethstore-cli output ([#7052](https://github.com/paritytech/parity/pull/7052))
|
||||
- Add mui for embed compilation ([#7049](https://github.com/paritytech/parity/pull/7049))
|
||||
- Update the snap metadata to keep working strictly confined ([#6993](https://github.com/paritytech/parity/pull/6993))
|
||||
- Remove unused js packages (dapp cleanups) ([#7046](https://github.com/paritytech/parity/pull/7046))
|
||||
- Gitlog location update ([#7042](https://github.com/paritytech/parity/pull/7042))
|
||||
- Move git logging to .git-release.log ([#7041](https://github.com/paritytech/parity/pull/7041))
|
||||
- Start from rust root in release update step ([#7039](https://github.com/paritytech/parity/pull/7039))
|
||||
- Complete token merge, remove unused files ([#7037](https://github.com/paritytech/parity/pull/7037))
|
||||
- Add missing cargo-push.sh shell variable ([#7036](https://github.com/paritytech/parity/pull/7036))
|
||||
- Fix npm start script ([#7034](https://github.com/paritytech/parity/pull/7034))
|
||||
- Update executable flags on release scripts ([#7035](https://github.com/paritytech/parity/pull/7035))
|
||||
- Fix v1 precompiled ([#7033](https://github.com/paritytech/parity/pull/7033))
|
||||
- Push precompiled to correct branch (v1) ([#7031](https://github.com/paritytech/parity/pull/7031))
|
||||
- Update v1 Wallet Dapp ([#6935](https://github.com/paritytech/parity/pull/6935))
|
||||
- WASM tests update ([#7018](https://github.com/paritytech/parity/pull/7018))
|
||||
- Events in WASM runtime ([#6967](https://github.com/paritytech/parity/pull/6967))
|
||||
- Adds validate_node_url() and refactors boot node check ([#6907](https://github.com/paritytech/parity/pull/6907)) ([#6970](https://github.com/paritytech/parity/pull/6970))
|
||||
- Fix windows build (with ui rebuild) ([#7016](https://github.com/paritytech/parity/pull/7016))
|
||||
- Make CLI arguments parsing more backwards compatible ([#7004](https://github.com/paritytech/parity/pull/7004))
|
||||
- Fixes for parity-extension ([#6990](https://github.com/paritytech/parity/pull/6990))
|
||||
- Update ethcore-bigint ([#6992](https://github.com/paritytech/parity/pull/6992))
|
||||
- Get local transactions by hash in the light client ([#6874](https://github.com/paritytech/parity/pull/6874))
|
||||
- Warn when blacklisted account present in store ([#6875](https://github.com/paritytech/parity/pull/6875))
|
||||
- Skip nonce check for gas estimation ([#6997](https://github.com/paritytech/parity/pull/6997))
|
||||
- Creating pending block with all transactions from the queue ([#6942](https://github.com/paritytech/parity/pull/6942))
|
||||
- Removes `MAX_TX_TO_IMPORT` from `ChainSync` ([#6976](https://github.com/paritytech/parity/pull/6976))
|
||||
- SecretStore: versioned keys ([#6910](https://github.com/paritytech/parity/pull/6910))
|
||||
- Removes `FUTURE_QUEUE_LIMITS_SHIFT` ([#6962](https://github.com/paritytech/parity/pull/6962))
|
||||
- Set zero nonce and gas price for calls by default ([#6954](https://github.com/paritytech/parity/pull/6954))
|
||||
- Add hint in ActionParams for splitting code/data ([#6957](https://github.com/paritytech/parity/pull/6957))
|
||||
- Return decoded seal fields. ([#6932](https://github.com/paritytech/parity/pull/6932))
|
||||
- Fix serialization of status in transaction receipts. ([#6926](https://github.com/paritytech/parity/pull/6926))
|
||||
- Reserve nonces for signing ([#6834](https://github.com/paritytech/parity/pull/6834))
|
||||
- Windows fixes ([#6921](https://github.com/paritytech/parity/pull/6921))
|
||||
- Don't add {css,js}.map from dapps ([#6931](https://github.com/paritytech/parity/pull/6931))
|
||||
- Fix JSON tracing for sub-calls. ([#6842](https://github.com/paritytech/parity/pull/6842))
|
||||
- Shell updates (bonds, updated Dapps) ([#6897](https://github.com/paritytech/parity/pull/6897))
|
||||
- Fix [#6228](https://github.com/paritytech/parity/issues/6228): do not display eth price in cli for etc ([#6877](https://github.com/paritytech/parity/pull/6877))
|
||||
- Fix mining help ([#6885](https://github.com/paritytech/parity/pull/6885))
|
||||
- Refactor static context check in CREATE. ([#6886](https://github.com/paritytech/parity/pull/6886))
|
||||
- Cleanup some configuration options ([#6878](https://github.com/paritytech/parity/pull/6878))
|
||||
- Fix serialization of non-localized transactions ([#6868](https://github.com/paritytech/parity/pull/6868))
|
||||
- Updated ntp to version 0.3 ([#6854](https://github.com/paritytech/parity/pull/6854))
|
||||
- Align README with 1.8 and prepare CHANGELOG with 1.8.1 ([#6833](https://github.com/paritytech/parity/pull/6833))
|
||||
- Return error on timed unlock ([#6777](https://github.com/paritytech/parity/pull/6777))
|
||||
- Fix dapps tests in master ([#6866](https://github.com/paritytech/parity/pull/6866))
|
||||
- Ethstore optimizations ([#6827](https://github.com/paritytech/parity/pull/6827))
|
||||
- Add ECIP1017 to Morden config ([#6810](https://github.com/paritytech/parity/pull/6810))
|
||||
- Remove all package publishing to npm ([#6838](https://github.com/paritytech/parity/pull/6838))
|
||||
- Util crates use tempdir crate instead of devtools to create temp path ([#6807](https://github.com/paritytech/parity/pull/6807))
|
||||
- Trigger js build ([#6836](https://github.com/paritytech/parity/pull/6836))
|
||||
- Clean-up scripts. ([#6832](https://github.com/paritytech/parity/pull/6832))
|
||||
- Tweaked snapshot sync threshold ([#6829](https://github.com/paritytech/parity/pull/6829))
|
||||
- Integrate UI 2 ([#6819](https://github.com/paritytech/parity/pull/6819))
|
||||
- Refresh cached tokens based on registry info & random balances ([#6818](https://github.com/paritytech/parity/pull/6818))
|
||||
- Change keypath derivation logic ([#6815](https://github.com/paritytech/parity/pull/6815))
|
||||
- Refactors journaldb as a separate crate ([#6801](https://github.com/paritytech/parity/pull/6801))
|
||||
- Trigger UI build. ([#6817](https://github.com/paritytech/parity/pull/6817))
|
||||
- Bumped more crate versions ([#6809](https://github.com/paritytech/parity/pull/6809))
|
||||
- Fix RPC compilation warnings. ([#6808](https://github.com/paritytech/parity/pull/6808))
|
||||
- Remove internal ipc ([#6795](https://github.com/paritytech/parity/pull/6795))
|
||||
- Consistent KeyValueDB errors ([#6792](https://github.com/paritytech/parity/pull/6792))
|
||||
- Squash remaining warnings ([#6789](https://github.com/paritytech/parity/pull/6789))
|
||||
- Forward-port [#6754](https://github.com/paritytech/parity/issues/6754) [#6755](https://github.com/paritytech/parity/issues/6755) ([#6785](https://github.com/paritytech/parity/pull/6785))
|
||||
- Removed duplicated versions of clippy ([#6776](https://github.com/paritytech/parity/pull/6776))
|
||||
- Updated ethabi to version 4.0 ([#6742](https://github.com/paritytech/parity/pull/6742))
|
||||
- Updated rpc_cli and parity to rpassword 1.0 ([#6774](https://github.com/paritytech/parity/pull/6774))
|
||||
- Fix sign data typo ([#6750](https://github.com/paritytech/parity/pull/6750))
|
||||
- Refactoring/cache 6693 ([#6772](https://github.com/paritytech/parity/pull/6772))
|
||||
- Fix CHANGLOG for 1.8.0 ([#6751](https://github.com/paritytech/parity/pull/6751))
|
||||
- Removes redundant `mut` in service.rs.in ([#6775](https://github.com/paritytech/parity/pull/6775))
|
||||
- Remove redundant `mut` ([#6773](https://github.com/paritytech/parity/pull/6773))
|
||||
- Fixed kovan chain validation ([#6758](https://github.com/paritytech/parity/pull/6758))
|
||||
- Removed redundant evm deps ([#6757](https://github.com/paritytech/parity/pull/6757))
|
||||
- Fixed modexp gas calculation overflow ([#6741](https://github.com/paritytech/parity/pull/6741))
|
||||
- Use cc 1.0 instead of gcc ([#6733](https://github.com/paritytech/parity/pull/6733))
|
||||
- Version bump to 1.9.0 ([#6727](https://github.com/paritytech/parity/pull/6727))
|
||||
- Fix badges not showing up ([#6730](https://github.com/paritytech/parity/pull/6730))
|
||||
@@ -1,18 +1,22 @@
|
||||
[package]
|
||||
name = "ethash"
|
||||
version = "1.9.0"
|
||||
version = "1.11.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[lib]
|
||||
|
||||
[dependencies]
|
||||
log = "0.3"
|
||||
keccak-hash = { path = "../util/hash" }
|
||||
primal = "0.2.3"
|
||||
parking_lot = "0.5"
|
||||
crunchy = "0.1.0"
|
||||
memmap = "0.6"
|
||||
either = "1.0.0"
|
||||
ethereum-types = "0.3"
|
||||
keccak-hash = { path = "../util/hash" }
|
||||
log = "0.3"
|
||||
memmap = "0.6"
|
||||
parking_lot = "0.5"
|
||||
primal = "0.2.3"
|
||||
|
||||
[dev-dependencies]
|
||||
tempdir = "0.3"
|
||||
|
||||
[features]
|
||||
benches = []
|
||||
|
||||
@@ -315,6 +315,7 @@ fn calculate_dag_item(node_index: u32, cache: &[Node]) -> Node {
|
||||
mod test {
|
||||
use super::*;
|
||||
use std::fs;
|
||||
use tempdir::TempDir;
|
||||
|
||||
#[test]
|
||||
fn test_get_cache_size() {
|
||||
@@ -386,8 +387,10 @@ mod test {
|
||||
0xe9, 0x7e, 0x53, 0x84,
|
||||
];
|
||||
let nonce = 0xd7b3ac70a301a249;
|
||||
|
||||
let tempdir = TempDir::new("").unwrap();
|
||||
// difficulty = 0x085657254bd9u64;
|
||||
let light = NodeCacheBuilder::new(None).light(&::std::env::temp_dir(), 486382);
|
||||
let light = NodeCacheBuilder::new(None).light(tempdir.path(), 486382);
|
||||
let result = light_compute(&light, &hash, nonce);
|
||||
assert_eq!(result.mix_hash[..], mix_hash[..]);
|
||||
assert_eq!(result.value[..], boundary[..]);
|
||||
@@ -395,18 +398,18 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_drop_old_data() {
|
||||
let path = ::std::env::temp_dir();
|
||||
let tempdir = TempDir::new("").unwrap();
|
||||
let builder = NodeCacheBuilder::new(None);
|
||||
let first = builder.light(&path, 0).to_file().unwrap().to_owned();
|
||||
let first = builder.light(tempdir.path(), 0).to_file().unwrap().to_owned();
|
||||
|
||||
let second = builder.light(&path, ETHASH_EPOCH_LENGTH).to_file().unwrap().to_owned();
|
||||
let second = builder.light(tempdir.path(), ETHASH_EPOCH_LENGTH).to_file().unwrap().to_owned();
|
||||
assert!(fs::metadata(&first).is_ok());
|
||||
|
||||
let _ = builder.light(&path, ETHASH_EPOCH_LENGTH * 2).to_file();
|
||||
let _ = builder.light(tempdir.path(), ETHASH_EPOCH_LENGTH * 2).to_file();
|
||||
assert!(fs::metadata(&first).is_err());
|
||||
assert!(fs::metadata(&second).is_ok());
|
||||
|
||||
let _ = builder.light(&path, ETHASH_EPOCH_LENGTH * 3).to_file();
|
||||
let _ = builder.light(tempdir.path(), ETHASH_EPOCH_LENGTH * 3).to_file();
|
||||
assert!(fs::metadata(&second).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,16 +16,20 @@
|
||||
|
||||
#![cfg_attr(feature = "benches", feature(test))]
|
||||
|
||||
extern crate primal;
|
||||
extern crate parking_lot;
|
||||
extern crate either;
|
||||
extern crate ethereum_types;
|
||||
extern crate memmap;
|
||||
extern crate parking_lot;
|
||||
extern crate primal;
|
||||
|
||||
#[macro_use]
|
||||
extern crate crunchy;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate tempdir;
|
||||
|
||||
mod compute;
|
||||
mod seed_compute;
|
||||
mod cache;
|
||||
@@ -35,6 +39,7 @@ mod shared;
|
||||
pub use cache::{NodeCacheBuilder, OptimizeFor};
|
||||
pub use compute::{ProofOfWork, quick_get_difficulty, slow_hash_block_number};
|
||||
use compute::Light;
|
||||
use ethereum_types::{U256, U512};
|
||||
use keccak::H256;
|
||||
use parking_lot::Mutex;
|
||||
pub use seed_compute::SeedHashCompute;
|
||||
@@ -133,9 +138,35 @@ impl EthashManager {
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert an Ethash boundary to its original difficulty. Basically just `f(x) = 2^256 / x`.
|
||||
pub fn boundary_to_difficulty(boundary: ðereum_types::H256) -> U256 {
|
||||
difficulty_to_boundary_aux(&**boundary)
|
||||
}
|
||||
|
||||
/// Convert an Ethash difficulty to the target boundary. Basically just `f(x) = 2^256 / x`.
|
||||
pub fn difficulty_to_boundary(difficulty: &U256) -> ethereum_types::H256 {
|
||||
difficulty_to_boundary_aux(difficulty).into()
|
||||
}
|
||||
|
||||
fn difficulty_to_boundary_aux<T: Into<U512>>(difficulty: T) -> ethereum_types::U256 {
|
||||
let difficulty = difficulty.into();
|
||||
|
||||
assert!(!difficulty.is_zero());
|
||||
|
||||
if difficulty == U512::one() {
|
||||
U256::max_value()
|
||||
} else {
|
||||
// difficulty > 1, so result should never overflow 256 bits
|
||||
U256::from((U512::one() << 256) / difficulty)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lru() {
|
||||
let ethash = EthashManager::new(&::std::env::temp_dir(), None);
|
||||
use tempdir::TempDir;
|
||||
|
||||
let tempdir = TempDir::new("").unwrap();
|
||||
let ethash = EthashManager::new(tempdir.path(), None);
|
||||
let hash = [0u8; 32];
|
||||
ethash.compute_light(1, &hash, 1);
|
||||
ethash.compute_light(50000, &hash, 1);
|
||||
@@ -149,6 +180,43 @@ fn test_lru() {
|
||||
assert_eq!(ethash.cache.lock().prev_epoch.unwrap(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_difficulty_to_boundary() {
|
||||
use ethereum_types::H256;
|
||||
use std::str::FromStr;
|
||||
|
||||
assert_eq!(difficulty_to_boundary(&U256::from(1)), H256::from(U256::max_value()));
|
||||
assert_eq!(difficulty_to_boundary(&U256::from(2)), H256::from_str("8000000000000000000000000000000000000000000000000000000000000000").unwrap());
|
||||
assert_eq!(difficulty_to_boundary(&U256::from(4)), H256::from_str("4000000000000000000000000000000000000000000000000000000000000000").unwrap());
|
||||
assert_eq!(difficulty_to_boundary(&U256::from(32)), H256::from_str("0800000000000000000000000000000000000000000000000000000000000000").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_difficulty_to_boundary_regression() {
|
||||
use ethereum_types::H256;
|
||||
|
||||
// the last bit was originally being truncated when performing the conversion
|
||||
// https://github.com/paritytech/parity-ethereum/issues/8397
|
||||
for difficulty in 1..9 {
|
||||
assert_eq!(U256::from(difficulty), boundary_to_difficulty(&difficulty_to_boundary(&difficulty.into())));
|
||||
assert_eq!(H256::from(difficulty), difficulty_to_boundary(&boundary_to_difficulty(&difficulty.into())));
|
||||
assert_eq!(U256::from(difficulty), boundary_to_difficulty(&boundary_to_difficulty(&difficulty.into()).into()));
|
||||
assert_eq!(H256::from(difficulty), difficulty_to_boundary(&difficulty_to_boundary(&difficulty.into()).into()));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_difficulty_to_boundary_panics_on_zero() {
|
||||
difficulty_to_boundary(&U256::from(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_boundary_to_difficulty_panics_on_zero() {
|
||||
boundary_to_difficulty(ðereum_types::H256::from(0));
|
||||
}
|
||||
|
||||
#[cfg(feature = "benches")]
|
||||
mod benchmarks {
|
||||
extern crate test;
|
||||
|
||||
@@ -3,28 +3,30 @@ description = "Ethcore library"
|
||||
homepage = "http://parity.io"
|
||||
license = "GPL-3.0"
|
||||
name = "ethcore"
|
||||
version = "1.9.0"
|
||||
version = "1.11.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[dependencies]
|
||||
ansi_term = "0.10"
|
||||
bloomchain = { path = "../util/bloomchain" }
|
||||
bn = { git = "https://github.com/paritytech/bn" }
|
||||
bn = { git = "https://github.com/paritytech/bn", default-features = false }
|
||||
byteorder = "1.0"
|
||||
common-types = { path = "types" }
|
||||
crossbeam = "0.3"
|
||||
ethash = { path = "../ethash" }
|
||||
ethcore-bloom-journal = { path = "../util/bloom" }
|
||||
ethcore-bytes = { path = "../util/bytes" }
|
||||
fetch = { path = "../util/fetch" }
|
||||
hashdb = { path = "../util/hashdb" }
|
||||
memorydb = { path = "../util/memorydb" }
|
||||
patricia-trie = { path = "../util/patricia_trie" }
|
||||
error-chain = { version = "0.11", default-features = false }
|
||||
ethcore-io = { path = "../util/io" }
|
||||
ethcore-logger = { path = "../logger" }
|
||||
ethcore-miner = { path = "../miner" }
|
||||
ethcore-stratum = { path = "../stratum" }
|
||||
ethcore-stratum = { path = "./stratum" }
|
||||
ethcore-transaction = { path = "./transaction" }
|
||||
ethereum-types = "0.2"
|
||||
ethereum-types = "0.3"
|
||||
memory-cache = { path = "../util/memory_cache" }
|
||||
ethabi = "5.1"
|
||||
ethabi-derive = "5.0"
|
||||
@@ -33,55 +35,61 @@ ethjson = { path = "../json" }
|
||||
ethkey = { path = "../ethkey" }
|
||||
ethstore = { path = "../ethstore" }
|
||||
evm = { path = "evm" }
|
||||
futures-cpupool = "0.1"
|
||||
hardware-wallet = { path = "../hw" }
|
||||
heapsize = "0.4"
|
||||
itertools = "0.5"
|
||||
lazy_static = "1.0"
|
||||
log = "0.3"
|
||||
lru-cache = "0.1"
|
||||
num = "0.1"
|
||||
num = { version = "0.1", default-features = false, features = ["bigint"] }
|
||||
num_cpus = "1.2"
|
||||
parity-machine = { path = "../machine" }
|
||||
parking_lot = "0.5"
|
||||
price-info = { path = "../price-info" }
|
||||
rayon = "0.8"
|
||||
rayon = "1.0"
|
||||
rand = "0.4"
|
||||
rlp = { path = "../util/rlp" }
|
||||
rlp_compress = { path = "../util/rlp_compress" }
|
||||
rlp_derive = { path = "../util/rlp_derive" }
|
||||
kvdb = { path = "../util/kvdb" }
|
||||
kvdb-rocksdb = { path = "../util/kvdb-rocksdb" }
|
||||
kvdb-memorydb = { path = "../util/kvdb-memorydb" }
|
||||
util-error = { path = "../util/error" }
|
||||
snappy = { git = "https://github.com/paritytech/rust-snappy" }
|
||||
stop-guard = { path = "../util/stop-guard" }
|
||||
migration = { path = "../util/migration" }
|
||||
macros = { path = "../util/macros" }
|
||||
rust-crypto = "0.2.34"
|
||||
rustc-hex = "1.0"
|
||||
stats = { path = "../util/stats" }
|
||||
time = "0.1"
|
||||
trace-time = { path = "../util/trace-time" }
|
||||
using_queue = { path = "../util/using_queue" }
|
||||
table = { path = "../util/table" }
|
||||
vm = { path = "vm" }
|
||||
wasm = { path = "wasm" }
|
||||
keccak-hash = { path = "../util/hash" }
|
||||
triehash = { path = "../util/triehash" }
|
||||
unexpected = { path = "../util/unexpected" }
|
||||
journaldb = { path = "../util/journaldb" }
|
||||
tempdir = "0.3"
|
||||
|
||||
[dev-dependencies]
|
||||
tempdir = "0.3"
|
||||
trie-standardmap = { path = "../util/trie-standardmap" }
|
||||
kvdb-rocksdb = { path = "../util/kvdb-rocksdb" }
|
||||
|
||||
[features]
|
||||
jit = ["evm/jit"]
|
||||
# Disables seal verification for mined blocks.
|
||||
# This allows you to submit any seal via RPC to test and benchmark
|
||||
# how fast pending block get's created while running on the mainnet.
|
||||
miner-debug = []
|
||||
# Display EVM debug traces.
|
||||
evm-debug = ["slow-blocks"]
|
||||
# Display EVM debug traces when running tests.
|
||||
evm-debug-tests = ["evm-debug", "evm/evm-debug-tests"]
|
||||
slow-blocks = [] # Use SLOW_TX_DURATION="50" (compile time!) to track transactions over 50ms
|
||||
# Measure time of transaction execution.
|
||||
# Whenever the transaction execution time (in millis) exceeds the value of
|
||||
# SLOW_TX_DURATION env variable (provided compile time!)
|
||||
# EVM debug traces are printed.
|
||||
slow-blocks = []
|
||||
# Run JSON consensus tests.
|
||||
json-tests = ["ethcore-transaction/json-tests"]
|
||||
# Run memory/cpu heavy tests.
|
||||
test-heavy = []
|
||||
default = []
|
||||
# Compile benches
|
||||
benches = []
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
@@ -16,18 +16,16 @@
|
||||
|
||||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
extern crate ethcore_util as util;
|
||||
extern crate rand;
|
||||
extern crate bn;
|
||||
extern crate crypto;
|
||||
extern crate ethereum_types;
|
||||
extern crate ethkey;
|
||||
extern crate parity_crypto;
|
||||
extern crate rand;
|
||||
extern crate rustc_hex;
|
||||
extern crate ethcore_bigint;
|
||||
|
||||
use self::test::{Bencher};
|
||||
use rand::{StdRng};
|
||||
extern crate test;
|
||||
|
||||
use self::test::Bencher;
|
||||
use rand::StdRng;
|
||||
|
||||
#[bench]
|
||||
fn bn_128_pairing(b: &mut Bencher) {
|
||||
@@ -61,16 +59,12 @@ fn bn_128_mul(b: &mut Bencher) {
|
||||
|
||||
#[bench]
|
||||
fn sha256(b: &mut Bencher) {
|
||||
use crypto::sha2::Sha256;
|
||||
use crypto::digest::Digest;
|
||||
use parity_crypto::digest::sha256;
|
||||
|
||||
let mut input: [u8; 256] = [0; 256];
|
||||
let mut out = [0; 32];
|
||||
let input = [0_u8; 256];
|
||||
|
||||
b.iter(|| {
|
||||
let mut sha = Sha256::new();
|
||||
sha.input(&input);
|
||||
sha.result(&mut input[0..32]);
|
||||
sha256(&input);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -78,7 +72,7 @@ fn sha256(b: &mut Bencher) {
|
||||
fn ecrecover(b: &mut Bencher) {
|
||||
use rustc_hex::FromHex;
|
||||
use ethkey::{Signature, recover as ec_recover};
|
||||
use ethcore_bigint::hash::H256;
|
||||
use ethereum_types::H256;
|
||||
let input = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap();
|
||||
let hash = H256::from_slice(&input[0..32]);
|
||||
let v = H256::from_slice(&input[32..64]);
|
||||
@@ -95,4 +89,3 @@ fn ecrecover(b: &mut Bencher) {
|
||||
let _ = ec_recover(&s, &hash);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
[package]
|
||||
name = "ethcrypto"
|
||||
name = "ethcore-crypto"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[dependencies]
|
||||
rust-crypto = "0.2.36"
|
||||
tiny-keccak = "1.3"
|
||||
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" }
|
||||
ethkey = { path = "../ethkey" }
|
||||
ethereum-types = "0.2"
|
||||
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1", optional = true }
|
||||
ethkey = { path = "../../ethkey", optional = true }
|
||||
ethereum-types = "0.3"
|
||||
subtle = "0.5"
|
||||
|
||||
[features]
|
||||
default = ["secp256k1"]
|
||||
secp256k1 = ["eth-secp256k1", "ethkey"]
|
||||
5
ethcore/crypto/README.md
Normal file
5
ethcore/crypto/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Ethcrypto
|
||||
|
||||
General cryptographic utilities for Ethereum.
|
||||
|
||||
By default, this library is compiled with the `secp256k1` feature, which provides ECDH and ECIES capability on that curve. It can be compiled without to avoid a dependency on the `libsecp256k1` library.
|
||||
@@ -18,17 +18,22 @@
|
||||
|
||||
extern crate crypto as rcrypto;
|
||||
extern crate ethereum_types;
|
||||
extern crate ethkey;
|
||||
extern crate secp256k1;
|
||||
extern crate subtle;
|
||||
extern crate tiny_keccak;
|
||||
|
||||
#[cfg(feature = "secp256k1")]
|
||||
extern crate secp256k1;
|
||||
#[cfg(feature = "secp256k1")]
|
||||
extern crate ethkey;
|
||||
|
||||
use std::fmt;
|
||||
use tiny_keccak::Keccak;
|
||||
use rcrypto::pbkdf2::pbkdf2;
|
||||
use rcrypto::scrypt::{scrypt, ScryptParams};
|
||||
use rcrypto::sha2::Sha256;
|
||||
use rcrypto::hmac::Hmac;
|
||||
|
||||
#[cfg(feature = "secp256k1")]
|
||||
use secp256k1::Error as SecpError;
|
||||
|
||||
pub const KEY_LENGTH: usize = 32;
|
||||
@@ -59,6 +64,7 @@ impl fmt::Display for ScryptError {
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum Error {
|
||||
#[cfg(feature = "secp256k1")]
|
||||
Secp(SecpError),
|
||||
Scrypt(ScryptError),
|
||||
InvalidMessage,
|
||||
@@ -73,6 +79,7 @@ impl From<ScryptError> for Error {
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
let s = match *self {
|
||||
#[cfg(feature = "secp256k1")]
|
||||
Error::Secp(ref err) => err.to_string(),
|
||||
Error::Scrypt(ref err) => err.to_string(),
|
||||
Error::InvalidMessage => "Invalid message".into(),
|
||||
@@ -88,6 +95,7 @@ impl Into<String> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "secp256k1")]
|
||||
impl From<SecpError> for Error {
|
||||
fn from(e: SecpError) -> Self {
|
||||
Error::Secp(e)
|
||||
@@ -174,6 +182,7 @@ pub mod aes {
|
||||
}
|
||||
|
||||
/// ECDH functions
|
||||
#[cfg(feature = "secp256k1")]
|
||||
pub mod ecdh {
|
||||
use secp256k1::{ecdh, key, Error as SecpError};
|
||||
use ethkey::{Secret, Public, SECP256K1};
|
||||
@@ -198,6 +207,7 @@ pub mod ecdh {
|
||||
}
|
||||
|
||||
/// ECIES function
|
||||
#[cfg(feature = "secp256k1")]
|
||||
pub mod ecies {
|
||||
use rcrypto::digest::Digest;
|
||||
use rcrypto::sha2::Sha256;
|
||||
@@ -205,7 +215,7 @@ pub mod ecies {
|
||||
use rcrypto::mac::Mac;
|
||||
use ethereum_types::H128;
|
||||
use ethkey::{Random, Generator, Public, Secret};
|
||||
use {Error, ecdh, aes, Keccak256};
|
||||
use {Error, ecdh, aes};
|
||||
|
||||
/// Encrypt a message with a public key, writing an HMAC covering both
|
||||
/// the plaintext and authenticated data.
|
||||
@@ -247,33 +257,6 @@ pub mod ecies {
|
||||
Ok(msg)
|
||||
}
|
||||
|
||||
/// Encrypt a message with a public key and no HMAC
|
||||
pub fn encrypt_single_message(public: &Public, plain: &[u8]) -> Result<Vec<u8>, Error> {
|
||||
let r = Random.generate()
|
||||
.expect("context known to have key-generation capabilities");
|
||||
|
||||
let z = ecdh::agree(r.secret(), public)?;
|
||||
let mut key = [0u8; 32];
|
||||
let mut mkey = [0u8; 32];
|
||||
kdf(&z, &[0u8; 0], &mut key);
|
||||
let mut hasher = Sha256::new();
|
||||
let mkey_material = &key[16..32];
|
||||
hasher.input(mkey_material);
|
||||
hasher.result(&mut mkey);
|
||||
let ekey = &key[0..16];
|
||||
|
||||
let mut msgd = vec![0u8; 64 + plain.len()];
|
||||
{
|
||||
r.public().copy_to(&mut msgd[0..64]);
|
||||
let iv = H128::from_slice(&z.keccak256()[0..16]);
|
||||
{
|
||||
let cipher = &mut msgd[64..(64 + plain.len())];
|
||||
aes::encrypt(ekey, &iv, plain, cipher);
|
||||
}
|
||||
}
|
||||
Ok(msgd)
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
@@ -317,33 +300,6 @@ pub mod ecies {
|
||||
Ok(msg)
|
||||
}
|
||||
|
||||
/// Decrypt single message with a secret key and no HMAC.
|
||||
pub fn decrypt_single_message(secret: &Secret, encrypted: &[u8]) -> Result<Vec<u8>, Error> {
|
||||
let meta_len = 64;
|
||||
if encrypted.len() < meta_len {
|
||||
return Err(Error::InvalidMessage); //invalid message: publickey
|
||||
}
|
||||
|
||||
let e = encrypted;
|
||||
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_material = &key[16..32];
|
||||
let mut hasher = Sha256::new();
|
||||
let mut mkey = [0u8; 32];
|
||||
hasher.input(mkey_material);
|
||||
hasher.result(&mut mkey);
|
||||
|
||||
let clen = encrypted.len() - meta_len;
|
||||
let cipher = &e[64..(64+clen)];
|
||||
let mut msg = vec![0u8; clen];
|
||||
let iv = H128::from_slice(&z.keccak256()[0..16]);
|
||||
aes::decrypt(ekey, &iv, cipher, &mut msg[..]);
|
||||
Ok(msg)
|
||||
}
|
||||
|
||||
fn kdf(secret: &Secret, s1: &[u8], dest: &mut [u8]) {
|
||||
let mut hasher = Sha256::new();
|
||||
// SEC/ISO/Shoup specify counter size SHOULD be equivalent
|
||||
@@ -384,15 +340,5 @@ mod tests {
|
||||
let decrypted = ecies::decrypt(kp.secret(), shared, &encrypted).unwrap();
|
||||
assert_eq!(decrypted[..message.len()], message[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ecies_shared_single() {
|
||||
let kp = Random.generate().unwrap();
|
||||
let message = b"So many books, so little time";
|
||||
let encrypted = ecies::encrypt_single_message(kp.public(), message).unwrap();
|
||||
assert!(encrypted[..] != message[..]);
|
||||
let decrypted = ecies::decrypt_single_message(kp.secret(), &encrypted).unwrap();
|
||||
assert_eq!(decrypted[..message.len()], message[..]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[dependencies]
|
||||
bit-set = "0.4"
|
||||
ethereum-types = "0.2"
|
||||
evmjit = { path = "../../evmjit", optional = true }
|
||||
ethereum-types = "0.3"
|
||||
heapsize = "0.4"
|
||||
lazy_static = "1.0"
|
||||
log = "0.3"
|
||||
@@ -19,6 +18,5 @@ memory-cache = { path = "../../util/memory_cache" }
|
||||
rustc-hex = "1.0"
|
||||
|
||||
[features]
|
||||
jit = ["evmjit"]
|
||||
evm-debug = []
|
||||
evm-debug-tests = ["evm-debug"]
|
||||
|
||||
@@ -32,23 +32,6 @@ pub struct Factory {
|
||||
impl Factory {
|
||||
/// Create fresh instance of VM
|
||||
/// Might choose implementation depending on supplied gas.
|
||||
#[cfg(feature = "jit")]
|
||||
pub fn create(&self, gas: &U256) -> Box<Vm> {
|
||||
match self.evm {
|
||||
VMType::Jit => {
|
||||
Box::new(super::jit::JitEvm::default())
|
||||
},
|
||||
VMType::Interpreter => if Self::can_fit_in_usize(gas) {
|
||||
Box::new(super::interpreter::Interpreter::<usize>::new(self.evm_cache.clone()))
|
||||
} else {
|
||||
Box::new(super::interpreter::Interpreter::<U256>::new(self.evm_cache.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create fresh instance of VM
|
||||
/// Might choose implementation depending on supplied gas.
|
||||
#[cfg(not(feature = "jit"))]
|
||||
pub fn create(&self, gas: &U256) -> Box<Vm> {
|
||||
match self.evm {
|
||||
VMType::Interpreter => if Self::can_fit_in_usize(gas) {
|
||||
@@ -74,17 +57,7 @@ impl Factory {
|
||||
}
|
||||
|
||||
impl Default for Factory {
|
||||
/// Returns jitvm factory
|
||||
#[cfg(all(feature = "jit", not(test)))]
|
||||
fn default() -> Factory {
|
||||
Factory {
|
||||
evm: VMType::Jit,
|
||||
evm_cache: Arc::new(SharedCache::default()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns native rust evm factory
|
||||
#[cfg(any(not(feature = "jit"), test))]
|
||||
fn default() -> Factory {
|
||||
Factory {
|
||||
evm: VMType::Interpreter,
|
||||
@@ -101,24 +74,7 @@ fn test_create_vm() {
|
||||
/// Create tests by injecting different VM factories
|
||||
#[macro_export]
|
||||
macro_rules! evm_test(
|
||||
(ignorejit => $name_test: ident: $name_jit: ident, $name_int: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
#[cfg(feature = "jit")]
|
||||
fn $name_jit() {
|
||||
$name_test(Factory::new(VMType::Jit, 1024 * 32));
|
||||
}
|
||||
#[test]
|
||||
fn $name_int() {
|
||||
$name_test(Factory::new(VMType::Interpreter, 1024 * 32));
|
||||
}
|
||||
};
|
||||
($name_test: ident: $name_jit: ident, $name_int: ident) => {
|
||||
#[test]
|
||||
#[cfg(feature = "jit")]
|
||||
fn $name_jit() {
|
||||
$name_test(Factory::new(VMType::Jit, 1024 * 32));
|
||||
}
|
||||
($name_test: ident: $name_int: ident) => {
|
||||
#[test]
|
||||
fn $name_int() {
|
||||
$name_test(Factory::new(VMType::Interpreter, 1024 * 32));
|
||||
@@ -129,14 +85,7 @@ macro_rules! evm_test(
|
||||
/// Create ignored tests by injecting different VM factories
|
||||
#[macro_export]
|
||||
macro_rules! evm_test_ignore(
|
||||
($name_test: ident: $name_jit: ident, $name_int: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
#[cfg(feature = "jit")]
|
||||
#[cfg(feature = "ignored-tests")]
|
||||
fn $name_jit() {
|
||||
$name_test(Factory::new(VMType::Jit, 1024 * 32));
|
||||
}
|
||||
($name_test: ident: $name_int: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
#[cfg(feature = "ignored-tests")]
|
||||
|
||||
@@ -81,7 +81,7 @@ fn test_get_swap_position() {
|
||||
assert_eq!(get_swap_position(SWAP10), 10);
|
||||
}
|
||||
|
||||
/// Returns number of topcis to take from stack
|
||||
/// Returns number of topics to take from stack
|
||||
/// LOG0 -> 0
|
||||
pub fn get_log_topics (i: Instruction) -> usize {
|
||||
assert!(i >= LOG0 && i <= LOG4);
|
||||
|
||||
@@ -1,414 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Just in time compiler execution environment.
|
||||
use bigint::prelude::U256;
|
||||
use bigint::hash::H256;
|
||||
use util::*;
|
||||
use evmjit;
|
||||
use evm::{self, GasLeft};
|
||||
use evm::CallType;
|
||||
use vm::{self, Vm};
|
||||
|
||||
/// Should be used to convert jit types to ethcore
|
||||
trait FromJit<T>: Sized {
|
||||
fn from_jit(input: T) -> Self;
|
||||
}
|
||||
|
||||
/// Should be used to covert ethcore types to jit
|
||||
trait IntoJit<T> {
|
||||
fn into_jit(self) -> T;
|
||||
}
|
||||
|
||||
impl<'a> FromJit<&'a evmjit::I256> for U256 {
|
||||
fn from_jit(input: &'a evmjit::I256) -> Self {
|
||||
unsafe {
|
||||
let mut res: U256 = mem::uninitialized();
|
||||
ptr::copy(input.words.as_ptr(), res.0.as_mut_ptr(), 4);
|
||||
res
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromJit<&'a evmjit::I256> for H256 {
|
||||
fn from_jit(input: &'a evmjit::I256) -> Self {
|
||||
let u = U256::from_jit(input);
|
||||
H256::from(&u)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromJit<&'a evmjit::I256> for Address {
|
||||
fn from_jit(input: &'a evmjit::I256) -> Self {
|
||||
Address::from(H256::from_jit(input))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromJit<&'a evmjit::H256> for H256 {
|
||||
fn from_jit(input: &'a evmjit::H256) -> Self {
|
||||
H256::from_jit(&evmjit::I256::from(input.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromJit<&'a evmjit::H256> for Address {
|
||||
fn from_jit(input: &'a evmjit::H256) -> Self {
|
||||
Address::from(H256::from_jit(input))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoJit<evmjit::I256> for U256 {
|
||||
fn into_jit(self) -> evmjit::I256 {
|
||||
unsafe {
|
||||
let mut res: evmjit::I256 = mem::uninitialized();
|
||||
ptr::copy(self.0.as_ptr(), res.words.as_mut_ptr(), 4);
|
||||
res
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoJit<evmjit::I256> for H256 {
|
||||
fn into_jit(self) -> evmjit::I256 {
|
||||
let mut ret = [0; 4];
|
||||
let len = self.len();
|
||||
for i in 0..len {
|
||||
let rev = len - 1 - i;
|
||||
let pos = rev / 8;
|
||||
ret[pos] += (self[i] as u64) << ((rev % 8) * 8);
|
||||
}
|
||||
evmjit::I256 { words: ret }
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoJit<evmjit::H256> for H256 {
|
||||
fn into_jit(self) -> evmjit::H256 {
|
||||
let i: evmjit::I256 = self.into_jit();
|
||||
From::from(i)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoJit<evmjit::I256> for Address {
|
||||
fn into_jit(self) -> evmjit::I256 {
|
||||
H256::from(self).into_jit()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoJit<evmjit::H256> for Address {
|
||||
fn into_jit(self) -> evmjit::H256 {
|
||||
H256::from(self).into_jit()
|
||||
}
|
||||
}
|
||||
|
||||
/// Externalities adapter. Maps callbacks from evmjit to externalities trait.
|
||||
///
|
||||
/// Evmjit doesn't have to know about children execution failures.
|
||||
/// This adapter 'catches' them and moves upstream.
|
||||
struct ExtAdapter<'a> {
|
||||
ext: &'a mut evm::Ext,
|
||||
address: Address
|
||||
}
|
||||
|
||||
impl<'a> ExtAdapter<'a> {
|
||||
fn new(ext: &'a mut evm::Ext, address: Address) -> Self {
|
||||
ExtAdapter {
|
||||
ext: ext,
|
||||
address: address
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> evmjit::Ext for ExtAdapter<'a> {
|
||||
fn sload(&self, key: *const evmjit::I256, out_value: *mut evmjit::I256) {
|
||||
unsafe {
|
||||
let i = H256::from_jit(&*key);
|
||||
let o = self.ext.storage_at(&i);
|
||||
*out_value = o.into_jit();
|
||||
}
|
||||
}
|
||||
|
||||
fn sstore(&mut self, key: *const evmjit::I256, value: *const evmjit::I256) {
|
||||
let key = unsafe { H256::from_jit(&*key) };
|
||||
let value = unsafe { H256::from_jit(&*value) };
|
||||
let old_value = self.ext.storage_at(&key);
|
||||
// if SSTORE nonzero -> zero, increment refund count
|
||||
if !old_value.is_zero() && value.is_zero() {
|
||||
self.ext.inc_sstore_clears();
|
||||
}
|
||||
self.ext.set_storage(key, value);
|
||||
}
|
||||
|
||||
fn balance(&self, address: *const evmjit::H256, out_value: *mut evmjit::I256) {
|
||||
unsafe {
|
||||
let a = Address::from_jit(&*address);
|
||||
let o = self.ext.balance(&a);
|
||||
*out_value = o.into_jit();
|
||||
}
|
||||
}
|
||||
|
||||
fn blockhash(&self, number: *const evmjit::I256, out_hash: *mut evmjit::H256) {
|
||||
unsafe {
|
||||
let n = U256::from_jit(&*number);
|
||||
let o = self.ext.blockhash(&n);
|
||||
*out_hash = o.into_jit();
|
||||
}
|
||||
}
|
||||
|
||||
fn create(&mut self,
|
||||
io_gas: *mut u64,
|
||||
value: *const evmjit::I256,
|
||||
init_beg: *const u8,
|
||||
init_size: u64,
|
||||
address: *mut evmjit::H256) {
|
||||
|
||||
let gas = unsafe { U256::from(*io_gas) };
|
||||
let value = unsafe { U256::from_jit(&*value) };
|
||||
let code = unsafe { slice::from_raw_parts(init_beg, init_size as usize) };
|
||||
|
||||
// check if balance is sufficient and we are not too deep
|
||||
if self.ext.balance(&self.address) >= value && self.ext.depth() < self.ext.schedule().max_depth {
|
||||
match self.ext.create(&gas, &value, code) {
|
||||
evm::ContractCreateResult::Created(new_address, gas_left) => unsafe {
|
||||
*address = new_address.into_jit();
|
||||
*io_gas = gas_left.low_u64();
|
||||
},
|
||||
evm::ContractCreateResult::Failed => unsafe {
|
||||
*address = Address::new().into_jit();
|
||||
*io_gas = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unsafe { *address = Address::new().into_jit(); }
|
||||
}
|
||||
}
|
||||
|
||||
fn call(&mut self,
|
||||
io_gas: *mut u64,
|
||||
call_gas: u64,
|
||||
sender_address: *const evmjit::H256,
|
||||
receive_address: *const evmjit::H256,
|
||||
code_address: *const evmjit::H256,
|
||||
transfer_value: *const evmjit::I256,
|
||||
// We are ignoring apparent value - it's handled in externalities.
|
||||
_apparent_value: *const evmjit::I256,
|
||||
in_beg: *const u8,
|
||||
in_size: u64,
|
||||
out_beg: *mut u8,
|
||||
out_size: u64) -> bool {
|
||||
|
||||
let mut gas = unsafe { U256::from(*io_gas) };
|
||||
let mut call_gas = U256::from(call_gas);
|
||||
let mut gas_cost = call_gas;
|
||||
let sender_address = unsafe { Address::from_jit(&*sender_address) };
|
||||
let receive_address = unsafe { Address::from_jit(&*receive_address) };
|
||||
let code_address = unsafe { Address::from_jit(&*code_address) };
|
||||
let transfer_value = unsafe { U256::from_jit(&*transfer_value) };
|
||||
|
||||
// receive address and code address are the same in normal calls
|
||||
let is_callcode = receive_address != code_address;
|
||||
let is_delegatecall = is_callcode && sender_address != receive_address;
|
||||
|
||||
let value = if is_delegatecall { None } else { Some(transfer_value) };
|
||||
|
||||
if !is_callcode && !self.ext.exists(&code_address) {
|
||||
gas_cost = gas_cost + U256::from(self.ext.schedule().call_new_account_gas);
|
||||
}
|
||||
|
||||
if transfer_value > U256::zero() {
|
||||
assert!(self.ext.schedule().call_value_transfer_gas > self.ext.schedule().call_stipend, "overflow possible");
|
||||
gas_cost = gas_cost + U256::from(self.ext.schedule().call_value_transfer_gas);
|
||||
call_gas = call_gas + U256::from(self.ext.schedule().call_stipend);
|
||||
}
|
||||
|
||||
if gas_cost > gas {
|
||||
unsafe {
|
||||
*io_gas = -1i64 as u64;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
gas = gas - gas_cost;
|
||||
|
||||
// check if balance is sufficient and we are not too deep
|
||||
if self.ext.balance(&self.address) < transfer_value || self.ext.depth() >= self.ext.schedule().max_depth {
|
||||
unsafe {
|
||||
*io_gas = (gas + call_gas).low_u64();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
let call_type = match (is_callcode, is_delegatecall) {
|
||||
(_, true) => CallType::DelegateCall,
|
||||
(true, false) => CallType::CallCode,
|
||||
(false, false) => CallType::Call,
|
||||
};
|
||||
|
||||
match self.ext.call(
|
||||
&call_gas,
|
||||
&sender_address,
|
||||
&receive_address,
|
||||
value,
|
||||
unsafe { slice::from_raw_parts(in_beg, in_size as usize) },
|
||||
&code_address,
|
||||
unsafe { slice::from_raw_parts_mut(out_beg, out_size as usize) },
|
||||
call_type,
|
||||
) {
|
||||
evm::MessageCallResult::Success(gas_left) => unsafe {
|
||||
*io_gas = (gas + gas_left).low_u64();
|
||||
true
|
||||
},
|
||||
evm::MessageCallResult::Failed => unsafe {
|
||||
*io_gas = gas.low_u64();
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn log(&mut self,
|
||||
beg: *const u8,
|
||||
size: u64,
|
||||
topic1: *const evmjit::H256,
|
||||
topic2: *const evmjit::H256,
|
||||
topic3: *const evmjit::H256,
|
||||
topic4: *const evmjit::H256) {
|
||||
|
||||
unsafe {
|
||||
let mut topics = vec![];
|
||||
if !topic1.is_null() {
|
||||
topics.push(H256::from_jit(&*topic1));
|
||||
}
|
||||
|
||||
if !topic2.is_null() {
|
||||
topics.push(H256::from_jit(&*topic2));
|
||||
}
|
||||
|
||||
if !topic3.is_null() {
|
||||
topics.push(H256::from_jit(&*topic3));
|
||||
}
|
||||
|
||||
if !topic4.is_null() {
|
||||
topics.push(H256::from_jit(&*topic4));
|
||||
}
|
||||
|
||||
let bytes_ref: &[u8] = slice::from_raw_parts(beg, size as usize);
|
||||
self.ext.log(topics, bytes_ref);
|
||||
}
|
||||
}
|
||||
|
||||
fn extcode(&self, address: *const evmjit::H256, size: *mut u64) -> *const u8 {
|
||||
unsafe {
|
||||
let code = self.ext.extcode(&Address::from_jit(&*address));
|
||||
*size = code.len() as u64;
|
||||
let ptr = code.as_ptr();
|
||||
mem::forget(code);
|
||||
ptr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct JitEvm {
|
||||
context: Option<evmjit::ContextHandle>,
|
||||
}
|
||||
|
||||
impl vm::Vm for JitEvm {
|
||||
fn exec(&mut self, params: ActionParams, ext: &mut evm::Ext) -> evm::Result<GasLeft> {
|
||||
// Dirty hack. This is unsafe, but we interact with ffi, so it's justified.
|
||||
let ext_adapter: ExtAdapter<'static> = unsafe { ::std::mem::transmute(ExtAdapter::new(ext, params.address.clone())) };
|
||||
let mut ext_handle = evmjit::ExtHandle::new(ext_adapter);
|
||||
assert!(params.gas <= U256::from(i64::max_value() as u64), "evmjit max gas is 2 ^ 63");
|
||||
assert!(params.gas_price <= U256::from(i64::max_value() as u64), "evmjit max gas is 2 ^ 63");
|
||||
|
||||
let call_data = params.data.unwrap_or_else(Vec::new);
|
||||
let code = params.code.unwrap_or_else(Vec::new);
|
||||
|
||||
let mut data = evmjit::RuntimeDataHandle::new();
|
||||
data.gas = params.gas.low_u64() as i64;
|
||||
data.gas_price = params.gas_price.low_u64() as i64;
|
||||
data.call_data = call_data.as_ptr();
|
||||
data.call_data_size = call_data.len() as u64;
|
||||
mem::forget(call_data);
|
||||
data.code = code.as_ptr();
|
||||
data.code_size = code.len() as u64;
|
||||
data.code_hash = code.sha3().into_jit();
|
||||
mem::forget(code);
|
||||
data.address = params.address.into_jit();
|
||||
data.caller = params.sender.into_jit();
|
||||
data.origin = params.origin.into_jit();
|
||||
data.transfer_value = match params.value {
|
||||
ActionValue::Transfer(val) => val.into_jit(),
|
||||
ActionValue::Apparent(val) => val.into_jit()
|
||||
};
|
||||
data.apparent_value = data.transfer_value;
|
||||
|
||||
let mut schedule = evmjit::ScheduleHandle::new();
|
||||
schedule.have_delegate_call = ext.schedule().have_delegate_call;
|
||||
|
||||
data.author = ext.env_info().author.clone().into_jit();
|
||||
data.difficulty = ext.env_info().difficulty.into_jit();
|
||||
data.gas_limit = ext.env_info().gas_limit.into_jit();
|
||||
data.number = ext.env_info().number;
|
||||
// don't really know why jit timestamp is int..
|
||||
data.timestamp = ext.env_info().timestamp as i64;
|
||||
|
||||
self.context = Some(unsafe { evmjit::ContextHandle::new(data, schedule, &mut ext_handle) });
|
||||
let mut context = self.context.as_mut().expect("context handle set on the prior line; qed");
|
||||
let res = context.exec();
|
||||
|
||||
match res {
|
||||
evmjit::ReturnCode::Stop => Ok(GasLeft::Known(U256::from(context.gas_left()))),
|
||||
evmjit::ReturnCode::Return =>
|
||||
Ok(GasLeft::NeedsReturn(U256::from(context.gas_left()), context.output_data())),
|
||||
evmjit::ReturnCode::Suicide => {
|
||||
ext.suicide(&Address::from_jit(&context.suicide_refund_address()));
|
||||
Ok(GasLeft::Known(U256::from(context.gas_left())))
|
||||
},
|
||||
evmjit::ReturnCode::OutOfGas => Err(vm::Error::OutOfGas),
|
||||
_err => Err(vm::Error::Internal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_and_from_u256() {
|
||||
let u = U256::from_str("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3").unwrap();
|
||||
let j = u.into_jit();
|
||||
let u2 = U256::from_jit(&j);
|
||||
assert_eq!(u, u2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_and_from_h256() {
|
||||
let h = H256::from_str("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3").unwrap();
|
||||
let j: ::evmjit::I256 = h.clone().into_jit();
|
||||
let h2 = H256::from_jit(&j);
|
||||
|
||||
assert_eq!(h, h2);
|
||||
|
||||
let j: ::evmjit::H256 = h.clone().into_jit();
|
||||
let h2 = H256::from_jit(&j);
|
||||
assert_eq!(h, h2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_and_from_address() {
|
||||
let a = Address::from_str("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba").unwrap();
|
||||
let j: ::evmjit::I256 = a.clone().into_jit();
|
||||
let a2 = Address::from_jit(&j);
|
||||
|
||||
assert_eq!(a, a2);
|
||||
|
||||
let j: ::evmjit::H256 = a.clone().into_jit();
|
||||
let a2 = Address::from_jit(&j);
|
||||
assert_eq!(a, a2);
|
||||
}
|
||||
@@ -30,9 +30,6 @@ extern crate lazy_static;
|
||||
#[cfg_attr(feature = "evm-debug", macro_use)]
|
||||
extern crate log;
|
||||
|
||||
#[cfg(feature = "jit")]
|
||||
extern crate evmjit;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate rustc_hex;
|
||||
|
||||
@@ -44,9 +41,6 @@ pub mod factory;
|
||||
mod vmtype;
|
||||
mod instructions;
|
||||
|
||||
#[cfg(feature = "jit" )]
|
||||
mod jit;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
#[cfg(all(feature="benches", test))]
|
||||
|
||||
@@ -26,9 +26,9 @@ use vm::tests::{FakeExt, FakeCall, FakeCallType, test_finalize};
|
||||
use factory::Factory;
|
||||
use vmtype::VMType;
|
||||
|
||||
evm_test!{test_add: test_add_jit, test_add_int}
|
||||
evm_test!{test_add: test_add_int}
|
||||
fn test_add(factory: super::Factory) {
|
||||
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||
let code = "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01600055".from_hex().unwrap();
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
@@ -46,7 +46,7 @@ fn test_add(factory: super::Factory) {
|
||||
assert_store(&ext, 0, "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe");
|
||||
}
|
||||
|
||||
evm_test!{test_sha3: test_sha3_jit, test_sha3_int}
|
||||
evm_test!{test_sha3: test_sha3_int}
|
||||
fn test_sha3(factory: super::Factory) {
|
||||
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||
let code = "6000600020600055".from_hex().unwrap();
|
||||
@@ -66,7 +66,7 @@ fn test_sha3(factory: super::Factory) {
|
||||
assert_store(&ext, 0, "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
|
||||
}
|
||||
|
||||
evm_test!{test_address: test_address_jit, test_address_int}
|
||||
evm_test!{test_address: test_address_int}
|
||||
fn test_address(factory: super::Factory) {
|
||||
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||
let code = "30600055".from_hex().unwrap();
|
||||
@@ -86,7 +86,7 @@ fn test_address(factory: super::Factory) {
|
||||
assert_store(&ext, 0, "0000000000000000000000000f572e5295c57f15886f9b263e2f6d2d6c7b5ec6");
|
||||
}
|
||||
|
||||
evm_test!{test_origin: test_origin_jit, test_origin_int}
|
||||
evm_test!{test_origin: test_origin_int}
|
||||
fn test_origin(factory: super::Factory) {
|
||||
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||
let origin = Address::from_str("cd1722f2947def4cf144679da39c4c32bdc35681").unwrap();
|
||||
@@ -108,7 +108,7 @@ fn test_origin(factory: super::Factory) {
|
||||
assert_store(&ext, 0, "000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681");
|
||||
}
|
||||
|
||||
evm_test!{test_sender: test_sender_jit, test_sender_int}
|
||||
evm_test!{test_sender: test_sender_int}
|
||||
fn test_sender(factory: super::Factory) {
|
||||
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||
let sender = Address::from_str("cd1722f2947def4cf144679da39c4c32bdc35681").unwrap();
|
||||
@@ -130,7 +130,7 @@ fn test_sender(factory: super::Factory) {
|
||||
assert_store(&ext, 0, "000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681");
|
||||
}
|
||||
|
||||
evm_test!{test_extcodecopy: test_extcodecopy_jit, test_extcodecopy_int}
|
||||
evm_test!{test_extcodecopy: test_extcodecopy_int}
|
||||
fn test_extcodecopy(factory: super::Factory) {
|
||||
// 33 - sender
|
||||
// 3b - extcodesize
|
||||
@@ -165,7 +165,7 @@ fn test_extcodecopy(factory: super::Factory) {
|
||||
assert_store(&ext, 0, "6005600055000000000000000000000000000000000000000000000000000000");
|
||||
}
|
||||
|
||||
evm_test!{test_log_empty: test_log_empty_jit, test_log_empty_int}
|
||||
evm_test!{test_log_empty: test_log_empty_int}
|
||||
fn test_log_empty(factory: super::Factory) {
|
||||
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||
let code = "60006000a0".from_hex().unwrap();
|
||||
@@ -187,7 +187,7 @@ fn test_log_empty(factory: super::Factory) {
|
||||
assert!(ext.logs[0].data.is_empty());
|
||||
}
|
||||
|
||||
evm_test!{test_log_sender: test_log_sender_jit, test_log_sender_int}
|
||||
evm_test!{test_log_sender: test_log_sender_int}
|
||||
fn test_log_sender(factory: super::Factory) {
|
||||
// 60 ff - push ff
|
||||
// 60 00 - push 00
|
||||
@@ -220,7 +220,7 @@ fn test_log_sender(factory: super::Factory) {
|
||||
assert_eq!(ext.logs[0].data, "ff00000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap());
|
||||
}
|
||||
|
||||
evm_test!{test_blockhash: test_blockhash_jit, test_blockhash_int}
|
||||
evm_test!{test_blockhash: test_blockhash_int}
|
||||
fn test_blockhash(factory: super::Factory) {
|
||||
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||
let code = "600040600055".from_hex().unwrap();
|
||||
@@ -242,7 +242,7 @@ fn test_blockhash(factory: super::Factory) {
|
||||
assert_eq!(ext.store.get(&H256::new()).unwrap(), &blockhash);
|
||||
}
|
||||
|
||||
evm_test!{test_calldataload: test_calldataload_jit, test_calldataload_int}
|
||||
evm_test!{test_calldataload: test_calldataload_int}
|
||||
fn test_calldataload(factory: super::Factory) {
|
||||
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||
let code = "600135600055".from_hex().unwrap();
|
||||
@@ -265,7 +265,7 @@ fn test_calldataload(factory: super::Factory) {
|
||||
|
||||
}
|
||||
|
||||
evm_test!{test_author: test_author_jit, test_author_int}
|
||||
evm_test!{test_author: test_author_int}
|
||||
fn test_author(factory: super::Factory) {
|
||||
let author = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||
let code = "41600055".from_hex().unwrap();
|
||||
@@ -285,7 +285,7 @@ fn test_author(factory: super::Factory) {
|
||||
assert_store(&ext, 0, "0000000000000000000000000f572e5295c57f15886f9b263e2f6d2d6c7b5ec6");
|
||||
}
|
||||
|
||||
evm_test!{test_timestamp: test_timestamp_jit, test_timestamp_int}
|
||||
evm_test!{test_timestamp: test_timestamp_int}
|
||||
fn test_timestamp(factory: super::Factory) {
|
||||
let timestamp = 0x1234;
|
||||
let code = "42600055".from_hex().unwrap();
|
||||
@@ -305,7 +305,7 @@ fn test_timestamp(factory: super::Factory) {
|
||||
assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000001234");
|
||||
}
|
||||
|
||||
evm_test!{test_number: test_number_jit, test_number_int}
|
||||
evm_test!{test_number: test_number_int}
|
||||
fn test_number(factory: super::Factory) {
|
||||
let number = 0x1234;
|
||||
let code = "43600055".from_hex().unwrap();
|
||||
@@ -325,7 +325,7 @@ fn test_number(factory: super::Factory) {
|
||||
assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000001234");
|
||||
}
|
||||
|
||||
evm_test!{test_difficulty: test_difficulty_jit, test_difficulty_int}
|
||||
evm_test!{test_difficulty: test_difficulty_int}
|
||||
fn test_difficulty(factory: super::Factory) {
|
||||
let difficulty = U256::from(0x1234);
|
||||
let code = "44600055".from_hex().unwrap();
|
||||
@@ -345,7 +345,7 @@ fn test_difficulty(factory: super::Factory) {
|
||||
assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000001234");
|
||||
}
|
||||
|
||||
evm_test!{test_gas_limit: test_gas_limit_jit, test_gas_limit_int}
|
||||
evm_test!{test_gas_limit: test_gas_limit_int}
|
||||
fn test_gas_limit(factory: super::Factory) {
|
||||
let gas_limit = U256::from(0x1234);
|
||||
let code = "45600055".from_hex().unwrap();
|
||||
@@ -365,7 +365,7 @@ fn test_gas_limit(factory: super::Factory) {
|
||||
assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000001234");
|
||||
}
|
||||
|
||||
evm_test!{test_mul: test_mul_jit, test_mul_int}
|
||||
evm_test!{test_mul: test_mul_int}
|
||||
fn test_mul(factory: super::Factory) {
|
||||
let code = "65012365124623626543219002600055".from_hex().unwrap();
|
||||
|
||||
@@ -383,7 +383,7 @@ fn test_mul(factory: super::Factory) {
|
||||
assert_eq!(gas_left, U256::from(79_983));
|
||||
}
|
||||
|
||||
evm_test!{test_sub: test_sub_jit, test_sub_int}
|
||||
evm_test!{test_sub: test_sub_int}
|
||||
fn test_sub(factory: super::Factory) {
|
||||
let code = "65012365124623626543219003600055".from_hex().unwrap();
|
||||
|
||||
@@ -401,7 +401,7 @@ fn test_sub(factory: super::Factory) {
|
||||
assert_eq!(gas_left, U256::from(79_985));
|
||||
}
|
||||
|
||||
evm_test!{test_div: test_div_jit, test_div_int}
|
||||
evm_test!{test_div: test_div_int}
|
||||
fn test_div(factory: super::Factory) {
|
||||
let code = "65012365124623626543219004600055".from_hex().unwrap();
|
||||
|
||||
@@ -419,7 +419,7 @@ fn test_div(factory: super::Factory) {
|
||||
assert_eq!(gas_left, U256::from(79_983));
|
||||
}
|
||||
|
||||
evm_test!{test_div_zero: test_div_zero_jit, test_div_zero_int}
|
||||
evm_test!{test_div_zero: test_div_zero_int}
|
||||
fn test_div_zero(factory: super::Factory) {
|
||||
let code = "6501236512462360009004600055".from_hex().unwrap();
|
||||
|
||||
@@ -437,7 +437,7 @@ fn test_div_zero(factory: super::Factory) {
|
||||
assert_eq!(gas_left, U256::from(94_983));
|
||||
}
|
||||
|
||||
evm_test!{test_mod: test_mod_jit, test_mod_int}
|
||||
evm_test!{test_mod: test_mod_int}
|
||||
fn test_mod(factory: super::Factory) {
|
||||
let code = "650123651246236265432290066000556501236512462360009006600155".from_hex().unwrap();
|
||||
|
||||
@@ -456,7 +456,7 @@ fn test_mod(factory: super::Factory) {
|
||||
assert_eq!(gas_left, U256::from(74_966));
|
||||
}
|
||||
|
||||
evm_test!{test_smod: test_smod_jit, test_smod_int}
|
||||
evm_test!{test_smod: test_smod_int}
|
||||
fn test_smod(factory: super::Factory) {
|
||||
let code = "650123651246236265432290076000556501236512462360009007600155".from_hex().unwrap();
|
||||
|
||||
@@ -475,7 +475,7 @@ fn test_smod(factory: super::Factory) {
|
||||
assert_eq!(gas_left, U256::from(74_966));
|
||||
}
|
||||
|
||||
evm_test!{test_sdiv: test_sdiv_jit, test_sdiv_int}
|
||||
evm_test!{test_sdiv: test_sdiv_int}
|
||||
fn test_sdiv(factory: super::Factory) {
|
||||
let code = "650123651246236265432290056000556501236512462360009005600155".from_hex().unwrap();
|
||||
|
||||
@@ -494,7 +494,7 @@ fn test_sdiv(factory: super::Factory) {
|
||||
assert_eq!(gas_left, U256::from(74_966));
|
||||
}
|
||||
|
||||
evm_test!{test_exp: test_exp_jit, test_exp_int}
|
||||
evm_test!{test_exp: test_exp_int}
|
||||
fn test_exp(factory: super::Factory) {
|
||||
let code = "6016650123651246230a6000556001650123651246230a6001556000650123651246230a600255".from_hex().unwrap();
|
||||
|
||||
@@ -514,7 +514,7 @@ fn test_exp(factory: super::Factory) {
|
||||
assert_eq!(gas_left, U256::from(39_923));
|
||||
}
|
||||
|
||||
evm_test!{test_comparison: test_comparison_jit, test_comparison_int}
|
||||
evm_test!{test_comparison: test_comparison_int}
|
||||
fn test_comparison(factory: super::Factory) {
|
||||
let code = "601665012365124623818181811060005511600155146002556415235412358014600355".from_hex().unwrap();
|
||||
|
||||
@@ -535,7 +535,7 @@ fn test_comparison(factory: super::Factory) {
|
||||
assert_eq!(gas_left, U256::from(49_952));
|
||||
}
|
||||
|
||||
evm_test!{test_signed_comparison: test_signed_comparison_jit, test_signed_comparison_int}
|
||||
evm_test!{test_signed_comparison: test_signed_comparison_int}
|
||||
fn test_signed_comparison(factory: super::Factory) {
|
||||
let code = "60106000036010818112600055136001556010601060000381811260025513600355".from_hex().unwrap();
|
||||
|
||||
@@ -556,7 +556,7 @@ fn test_signed_comparison(factory: super::Factory) {
|
||||
assert_eq!(gas_left, U256::from(49_940));
|
||||
}
|
||||
|
||||
evm_test!{test_bitops: test_bitops_jit, test_bitops_int}
|
||||
evm_test!{test_bitops: test_bitops_int}
|
||||
fn test_bitops(factory: super::Factory) {
|
||||
let code = "60ff610ff08181818116600055176001551860025560008015600355198015600455600555".from_hex().unwrap();
|
||||
|
||||
@@ -579,7 +579,7 @@ fn test_bitops(factory: super::Factory) {
|
||||
assert_eq!(gas_left, U256::from(44_937));
|
||||
}
|
||||
|
||||
evm_test!{test_addmod_mulmod: test_addmod_mulmod_jit, test_addmod_mulmod_int}
|
||||
evm_test!{test_addmod_mulmod: test_addmod_mulmod_int}
|
||||
fn test_addmod_mulmod(factory: super::Factory) {
|
||||
let code = "60ff60f060108282820860005509600155600060f0601082828208196002550919600355".from_hex().unwrap();
|
||||
|
||||
@@ -600,7 +600,7 @@ fn test_addmod_mulmod(factory: super::Factory) {
|
||||
assert_eq!(gas_left, U256::from(19_914));
|
||||
}
|
||||
|
||||
evm_test!{test_byte: test_byte_jit, test_byte_int}
|
||||
evm_test!{test_byte: test_byte_int}
|
||||
fn test_byte(factory: super::Factory) {
|
||||
let code = "60f061ffff1a600055610fff601f1a600155".from_hex().unwrap();
|
||||
|
||||
@@ -619,7 +619,7 @@ fn test_byte(factory: super::Factory) {
|
||||
assert_eq!(gas_left, U256::from(74_976));
|
||||
}
|
||||
|
||||
evm_test!{test_signextend: test_signextend_jit, test_signextend_int}
|
||||
evm_test!{test_signextend: test_signextend_int}
|
||||
fn test_signextend(factory: super::Factory) {
|
||||
let code = "610fff60020b60005560ff60200b600155".from_hex().unwrap();
|
||||
|
||||
@@ -659,7 +659,7 @@ fn test_badinstruction_int() {
|
||||
}
|
||||
}
|
||||
|
||||
evm_test!{test_pop: test_pop_jit, test_pop_int}
|
||||
evm_test!{test_pop: test_pop_int}
|
||||
fn test_pop(factory: super::Factory) {
|
||||
let code = "60f060aa50600055".from_hex().unwrap();
|
||||
|
||||
@@ -677,7 +677,7 @@ fn test_pop(factory: super::Factory) {
|
||||
assert_eq!(gas_left, U256::from(79_989));
|
||||
}
|
||||
|
||||
evm_test!{test_extops: test_extops_jit, test_extops_int}
|
||||
evm_test!{test_extops: test_extops_int}
|
||||
fn test_extops(factory: super::Factory) {
|
||||
let code = "5a6001555836553a600255386003553460045560016001526016590454600555".from_hex().unwrap();
|
||||
|
||||
@@ -702,7 +702,7 @@ fn test_extops(factory: super::Factory) {
|
||||
assert_eq!(gas_left, U256::from(29_898));
|
||||
}
|
||||
|
||||
evm_test!{test_jumps: test_jumps_jit, test_jumps_int}
|
||||
evm_test!{test_jumps: test_jumps_int}
|
||||
fn test_jumps(factory: super::Factory) {
|
||||
let code = "600160015560066000555b60016000540380806000551560245760015402600155600a565b".from_hex().unwrap();
|
||||
|
||||
@@ -722,7 +722,7 @@ fn test_jumps(factory: super::Factory) {
|
||||
assert_eq!(gas_left, U256::from(54_117));
|
||||
}
|
||||
|
||||
evm_test!{test_calls: test_calls_jit, test_calls_int}
|
||||
evm_test!{test_calls: test_calls_int}
|
||||
fn test_calls(factory: super::Factory) {
|
||||
let code = "600054602d57600160005560006000600060006050610998610100f160006000600060006050610998610100f25b".from_hex().unwrap();
|
||||
|
||||
@@ -766,7 +766,7 @@ fn test_calls(factory: super::Factory) {
|
||||
assert_eq!(ext.calls.len(), 2);
|
||||
}
|
||||
|
||||
evm_test!{test_create_in_staticcall: test_create_in_staticcall_jit, test_create_in_staticcall_int}
|
||||
evm_test!{test_create_in_staticcall: test_create_in_staticcall_int}
|
||||
fn test_create_in_staticcall(factory: super::Factory) {
|
||||
let code = "600060006064f000".from_hex().unwrap();
|
||||
|
||||
|
||||
@@ -19,22 +19,11 @@ use std::fmt;
|
||||
/// Type of EVM to use.
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum VMType {
|
||||
/// JIT EVM
|
||||
#[cfg(feature = "jit")]
|
||||
Jit,
|
||||
/// RUST EVM
|
||||
Interpreter
|
||||
}
|
||||
|
||||
impl fmt::Display for VMType {
|
||||
#[cfg(feature="jit")]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", match *self {
|
||||
VMType::Jit => "JIT",
|
||||
VMType::Interpreter => "INT"
|
||||
})
|
||||
}
|
||||
#[cfg(not(feature="jit"))]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", match *self {
|
||||
VMType::Interpreter => "INT"
|
||||
@@ -49,27 +38,8 @@ impl Default for VMType {
|
||||
}
|
||||
|
||||
impl VMType {
|
||||
/// Return all possible VMs (JIT, Interpreter)
|
||||
#[cfg(feature = "jit")]
|
||||
pub fn all() -> Vec<VMType> {
|
||||
vec![VMType::Jit, VMType::Interpreter]
|
||||
}
|
||||
|
||||
/// Return all possible VMs (Interpreter)
|
||||
#[cfg(not(feature = "jit"))]
|
||||
pub fn all() -> Vec<VMType> {
|
||||
vec![VMType::Interpreter]
|
||||
}
|
||||
|
||||
/// Return new jit if it's possible
|
||||
#[cfg(not(feature = "jit"))]
|
||||
pub fn jit() -> Option<Self> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Return new jit if it's possible
|
||||
#[cfg(feature = "jit")]
|
||||
pub fn jit() -> Option<Self> {
|
||||
Some(VMType::Jit)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ description = "Parity Light Client Implementation"
|
||||
homepage = "http://parity.io"
|
||||
license = "GPL-3.0"
|
||||
name = "ethcore-light"
|
||||
version = "1.9.0"
|
||||
version = "1.11.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[dependencies]
|
||||
@@ -11,7 +11,7 @@ log = "0.3"
|
||||
ethcore = { path = ".."}
|
||||
ethcore-bytes = { path = "../../util/bytes" }
|
||||
ethcore-transaction = { path = "../transaction" }
|
||||
ethereum-types = "0.2"
|
||||
ethereum-types = "0.3"
|
||||
memorydb = { path = "../../util/memorydb" }
|
||||
patricia-trie = { path = "../../util/patricia_trie" }
|
||||
ethcore-network = { path = "../../util/network" }
|
||||
@@ -22,7 +22,6 @@ vm = { path = "../vm" }
|
||||
plain_hasher = { path = "../../util/plain_hasher" }
|
||||
rlp = { path = "../../util/rlp" }
|
||||
rlp_derive = { path = "../../util/rlp_derive" }
|
||||
time = "0.1"
|
||||
smallvec = "0.4"
|
||||
futures = "0.1"
|
||||
rand = "0.4"
|
||||
@@ -35,11 +34,11 @@ stats = { path = "../../util/stats" }
|
||||
keccak-hash = { path = "../../util/hash" }
|
||||
triehash = { path = "../../util/triehash" }
|
||||
kvdb = { path = "../../util/kvdb" }
|
||||
kvdb-rocksdb = { path = "../../util/kvdb-rocksdb" }
|
||||
kvdb-memorydb = { path = "../../util/kvdb-memorydb" }
|
||||
memory-cache = { path = "../../util/memory_cache" }
|
||||
error-chain = { version = "0.11", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
kvdb-memorydb = { path = "../../util/kvdb-memorydb" }
|
||||
tempdir = "0.3"
|
||||
|
||||
[features]
|
||||
|
||||
@@ -25,7 +25,7 @@ use ethcore::header::BlockNumber;
|
||||
use ethcore::receipt::Receipt;
|
||||
|
||||
use stats::Corpus;
|
||||
use time::{SteadyTime, Duration};
|
||||
use std::time::{Instant, Duration};
|
||||
use heapsize::HeapSizeOf;
|
||||
use ethereum_types::{H256, U256};
|
||||
use memory_cache::MemoryLruCache;
|
||||
@@ -69,7 +69,7 @@ pub struct Cache {
|
||||
bodies: MemoryLruCache<H256, encoded::Body>,
|
||||
receipts: MemoryLruCache<H256, Vec<Receipt>>,
|
||||
chain_score: MemoryLruCache<H256, U256>,
|
||||
corpus: Option<(Corpus<U256>, SteadyTime)>,
|
||||
corpus: Option<(Corpus<U256>, Instant)>,
|
||||
corpus_expiration: Duration,
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ impl Cache {
|
||||
|
||||
/// Get gas price corpus, if recent enough.
|
||||
pub fn gas_price_corpus(&self) -> Option<Corpus<U256>> {
|
||||
let now = SteadyTime::now();
|
||||
let now = Instant::now();
|
||||
|
||||
self.corpus.as_ref().and_then(|&(ref corpus, ref tm)| {
|
||||
if *tm + self.corpus_expiration >= now {
|
||||
@@ -152,7 +152,7 @@ impl Cache {
|
||||
|
||||
/// Set the cached gas price corpus.
|
||||
pub fn set_gas_price_corpus(&mut self, corpus: Corpus<U256>) {
|
||||
self.corpus = Some((corpus, SteadyTime::now()))
|
||||
self.corpus = Some((corpus, Instant::now()))
|
||||
}
|
||||
|
||||
/// Get the memory used.
|
||||
@@ -175,18 +175,18 @@ impl HeapSizeOf for Cache {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Cache;
|
||||
use time::Duration;
|
||||
use std::time::Duration;
|
||||
|
||||
#[test]
|
||||
fn corpus_inaccessible() {
|
||||
let mut cache = Cache::new(Default::default(), Duration::hours(5));
|
||||
let mut cache = Cache::new(Default::default(), Duration::from_secs(5 * 3600));
|
||||
|
||||
cache.set_gas_price_corpus(vec![].into());
|
||||
assert_eq!(cache.gas_price_corpus(), Some(vec![].into()));
|
||||
|
||||
{
|
||||
let corpus_time = &mut cache.corpus.as_mut().unwrap().1;
|
||||
*corpus_time = *corpus_time - Duration::hours(6);
|
||||
*corpus_time = *corpus_time - Duration::from_secs(6 * 3600);
|
||||
}
|
||||
assert!(cache.gas_price_corpus().is_none());
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ use hashdb::HashDB;
|
||||
use memorydb::MemoryDB;
|
||||
use bytes::Bytes;
|
||||
use trie::{self, TrieMut, TrieDBMut, Trie, TrieDB, Recorder};
|
||||
use rlp::{RlpStream, UntrustedRlp};
|
||||
use rlp::{RlpStream, Rlp};
|
||||
|
||||
// encode a key.
|
||||
macro_rules! key {
|
||||
@@ -150,7 +150,7 @@ pub fn check_proof(proof: &[Bytes], num: u64, root: H256) -> Option<(H256, U256)
|
||||
let res = match TrieDB::new(&db, &root) {
|
||||
Err(_) => return None,
|
||||
Ok(trie) => trie.get_with(&key!(num), |val: &[u8]| {
|
||||
let rlp = UntrustedRlp::new(val);
|
||||
let rlp = Rlp::new(val);
|
||||
rlp.val_at::<H256>(0)
|
||||
.and_then(|h| rlp.val_at::<U256>(1).map(|td| (h, td)))
|
||||
.ok()
|
||||
|
||||
@@ -31,21 +31,21 @@ use std::sync::Arc;
|
||||
use cht;
|
||||
|
||||
use ethcore::block_status::BlockStatus;
|
||||
use ethcore::error::{BlockImportError, BlockError};
|
||||
use ethcore::error::{Error, ErrorKind, BlockImportError, BlockImportErrorKind, BlockError};
|
||||
use ethcore::encoded;
|
||||
use ethcore::header::Header;
|
||||
use ethcore::ids::BlockId;
|
||||
use ethcore::spec::Spec;
|
||||
use ethcore::spec::{Spec, SpecHardcodedSync};
|
||||
use ethcore::engines::epoch::{
|
||||
Transition as EpochTransition,
|
||||
PendingTransition as PendingEpochTransition
|
||||
};
|
||||
|
||||
use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp, UntrustedRlp};
|
||||
use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp};
|
||||
use heapsize::HeapSizeOf;
|
||||
use ethereum_types::{H256, H264, U256};
|
||||
use plain_hasher::H256FastMap;
|
||||
use kvdb::{self, DBTransaction, KeyValueDB};
|
||||
use kvdb::{DBTransaction, KeyValueDB};
|
||||
|
||||
use cache::Cache;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
@@ -74,6 +74,22 @@ pub struct BlockDescriptor {
|
||||
pub total_difficulty: U256,
|
||||
}
|
||||
|
||||
// best block data
|
||||
#[derive(RlpEncodable, RlpDecodable)]
|
||||
struct BestAndLatest {
|
||||
best_num: u64,
|
||||
latest_num: u64
|
||||
}
|
||||
|
||||
impl BestAndLatest {
|
||||
fn new(best_num: u64, latest_num: u64) -> Self {
|
||||
BestAndLatest {
|
||||
best_num,
|
||||
latest_num,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// candidate block description.
|
||||
struct Candidate {
|
||||
hash: H256,
|
||||
@@ -109,7 +125,7 @@ impl Encodable for Entry {
|
||||
}
|
||||
|
||||
impl Decodable for Entry {
|
||||
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
||||
let mut candidates = SmallVec::<[Candidate; 3]>::new();
|
||||
|
||||
for item in rlp.iter() {
|
||||
@@ -170,7 +186,7 @@ fn encode_canonical_transition(header: &Header, proof: &[u8]) -> Vec<u8> {
|
||||
|
||||
// decode last canonical transition entry.
|
||||
fn decode_canonical_transition(t: &[u8]) -> Result<(Header, &[u8]), DecoderError> {
|
||||
let rlp = UntrustedRlp::new(t);
|
||||
let rlp = Rlp::new(t);
|
||||
|
||||
Ok((rlp.val_at(0)?, rlp.at(1)?.data()?))
|
||||
}
|
||||
@@ -180,6 +196,12 @@ pub struct PendingChanges {
|
||||
best_block: Option<BlockDescriptor>, // new best block.
|
||||
}
|
||||
|
||||
/// Whether or not the hardcoded sync feature is allowed.
|
||||
pub enum HardcodedSync {
|
||||
Allow,
|
||||
Deny,
|
||||
}
|
||||
|
||||
/// Header chain. See module docs for more details.
|
||||
pub struct HeaderChain {
|
||||
genesis_header: encoded::Header, // special-case the genesis.
|
||||
@@ -198,25 +220,23 @@ impl HeaderChain {
|
||||
col: Option<u32>,
|
||||
spec: &Spec,
|
||||
cache: Arc<Mutex<Cache>>,
|
||||
) -> Result<Self, kvdb::Error> {
|
||||
allow_hs: HardcodedSync,
|
||||
) -> Result<Self, Error> {
|
||||
let mut live_epoch_proofs = ::std::collections::HashMap::default();
|
||||
|
||||
let genesis = ::rlp::encode(&spec.genesis_header()).into_vec();
|
||||
let decoded_header = spec.genesis_header();
|
||||
|
||||
let chain = if let Some(current) = db.get(col, CURRENT_KEY)? {
|
||||
let (best_number, highest_number) = {
|
||||
let rlp = Rlp::new(¤t);
|
||||
(rlp.val_at(0), rlp.val_at(1))
|
||||
};
|
||||
let curr : BestAndLatest = ::rlp::decode(¤t).expect("decoding db value failed");
|
||||
|
||||
let mut cur_number = highest_number;
|
||||
let mut cur_number = curr.latest_num;
|
||||
let mut candidates = BTreeMap::new();
|
||||
|
||||
// load all era entries, referenced headers within them,
|
||||
// and live epoch proofs.
|
||||
while let Some(entry) = db.get(col, era_key(cur_number).as_bytes())? {
|
||||
let entry: Entry = ::rlp::decode(&entry);
|
||||
let entry: Entry = ::rlp::decode(&entry).expect("decoding db value failed");
|
||||
trace!(target: "chain", "loaded header chain entry for era {} with {} candidates",
|
||||
cur_number, entry.candidates.len());
|
||||
|
||||
@@ -238,15 +258,15 @@ impl HeaderChain {
|
||||
|
||||
// fill best block block descriptor.
|
||||
let best_block = {
|
||||
let era = match candidates.get(&best_number) {
|
||||
let era = match candidates.get(&curr.best_num) {
|
||||
Some(era) => era,
|
||||
None => return Err("Database corrupt: highest block referenced but no data.".into()),
|
||||
None => bail!(ErrorKind::Database("Database corrupt: highest block referenced but no data.".into())),
|
||||
};
|
||||
|
||||
let best = &era.candidates[0];
|
||||
BlockDescriptor {
|
||||
hash: best.hash,
|
||||
number: best_number,
|
||||
number: curr.best_num,
|
||||
total_difficulty: best.total_difficulty,
|
||||
}
|
||||
};
|
||||
@@ -260,8 +280,9 @@ impl HeaderChain {
|
||||
col: col,
|
||||
cache: cache,
|
||||
}
|
||||
|
||||
} else {
|
||||
HeaderChain {
|
||||
let chain = HeaderChain {
|
||||
genesis_header: encoded::Header::new(genesis),
|
||||
best_block: RwLock::new(BlockDescriptor {
|
||||
hash: decoded_header.hash(),
|
||||
@@ -270,10 +291,43 @@ impl HeaderChain {
|
||||
}),
|
||||
candidates: RwLock::new(BTreeMap::new()),
|
||||
live_epoch_proofs: RwLock::new(live_epoch_proofs),
|
||||
db: db,
|
||||
db: db.clone(),
|
||||
col: col,
|
||||
cache: cache,
|
||||
};
|
||||
|
||||
// insert the hardcoded sync into the database.
|
||||
if let (&Some(ref hardcoded_sync), HardcodedSync::Allow) = (&spec.hardcoded_sync, allow_hs) {
|
||||
let mut batch = db.transaction();
|
||||
|
||||
// insert the hardcoded CHT roots into the database.
|
||||
for (cht_num, cht_root) in hardcoded_sync.chts.iter().enumerate() {
|
||||
batch.put(col, cht_key(cht_num as u64).as_bytes(), &::rlp::encode(cht_root));
|
||||
}
|
||||
|
||||
let decoded_header = hardcoded_sync.header.decode()?;
|
||||
let decoded_header_num = decoded_header.number();
|
||||
|
||||
// write the block in the DB.
|
||||
info!(target: "chain", "Inserting hardcoded block #{} in chain",
|
||||
decoded_header_num);
|
||||
let pending = chain.insert_with_td(&mut batch, decoded_header,
|
||||
hardcoded_sync.total_difficulty, None)?;
|
||||
|
||||
// check that we have enough hardcoded CHT roots. avoids panicking later.
|
||||
let cht_num = cht::block_to_cht_number(decoded_header_num - 1)
|
||||
.expect("specs provided a hardcoded block with height 0");
|
||||
if cht_num >= hardcoded_sync.chts.len() as u64 {
|
||||
warn!(target: "chain", "specs didn't provide enough CHT roots for its \
|
||||
hardcoded block ; falling back to non-hardcoded sync \
|
||||
mode");
|
||||
} else {
|
||||
db.write_buffered(batch);
|
||||
chain.apply_pending(pending);
|
||||
}
|
||||
}
|
||||
|
||||
chain
|
||||
};
|
||||
|
||||
// instantiate genesis epoch data if it doesn't exist.
|
||||
@@ -304,6 +358,29 @@ impl HeaderChain {
|
||||
transaction: &mut DBTransaction,
|
||||
header: Header,
|
||||
transition_proof: Option<Vec<u8>>,
|
||||
) -> Result<PendingChanges, BlockImportError> {
|
||||
self.insert_inner(transaction, header, None, transition_proof)
|
||||
}
|
||||
|
||||
/// Insert a pre-verified header, with a known total difficulty. Similary to `insert`.
|
||||
///
|
||||
/// This blindly trusts that the data given to it is sensible.
|
||||
pub fn insert_with_td(
|
||||
&self,
|
||||
transaction: &mut DBTransaction,
|
||||
header: Header,
|
||||
total_difficulty: U256,
|
||||
transition_proof: Option<Vec<u8>>,
|
||||
) -> Result<PendingChanges, BlockImportError> {
|
||||
self.insert_inner(transaction, header, Some(total_difficulty), transition_proof)
|
||||
}
|
||||
|
||||
fn insert_inner(
|
||||
&self,
|
||||
transaction: &mut DBTransaction,
|
||||
header: Header,
|
||||
total_difficulty: Option<U256>,
|
||||
transition_proof: Option<Vec<u8>>,
|
||||
) -> Result<PendingChanges, BlockImportError> {
|
||||
let hash = header.hash();
|
||||
let number = header.number();
|
||||
@@ -321,19 +398,24 @@ impl HeaderChain {
|
||||
// hold candidates the whole time to guard import order.
|
||||
let mut candidates = self.candidates.write();
|
||||
|
||||
// find parent details.
|
||||
let parent_td =
|
||||
if number == 1 {
|
||||
self.genesis_header.difficulty()
|
||||
} else {
|
||||
candidates.get(&(number - 1))
|
||||
.and_then(|entry| entry.candidates.iter().find(|c| c.hash == parent_hash))
|
||||
.map(|c| c.total_difficulty)
|
||||
.ok_or_else(|| BlockError::UnknownParent(parent_hash))
|
||||
.map_err(BlockImportError::Block)?
|
||||
};
|
||||
// find total difficulty.
|
||||
let total_difficulty = match total_difficulty {
|
||||
Some(td) => td,
|
||||
None => {
|
||||
let parent_td =
|
||||
if number == 1 {
|
||||
self.genesis_header.difficulty()
|
||||
} else {
|
||||
candidates.get(&(number - 1))
|
||||
.and_then(|entry| entry.candidates.iter().find(|c| c.hash == parent_hash))
|
||||
.map(|c| c.total_difficulty)
|
||||
.ok_or_else(|| BlockError::UnknownParent(parent_hash))
|
||||
.map_err(BlockImportErrorKind::Block)?
|
||||
};
|
||||
|
||||
let total_difficulty = parent_td + *header.difficulty();
|
||||
parent_td + *header.difficulty()
|
||||
},
|
||||
};
|
||||
|
||||
// insert headers and candidates entries and write era to disk.
|
||||
{
|
||||
@@ -442,7 +524,10 @@ impl HeaderChain {
|
||||
None
|
||||
}
|
||||
Ok(None) => panic!("stored candidates always have corresponding headers; qed"),
|
||||
Ok(Some(header)) => Some((epoch_transition, ::rlp::decode(&header))),
|
||||
Ok(Some(header)) => Some((
|
||||
epoch_transition,
|
||||
::rlp::decode(&header).expect("decoding value from db failed")
|
||||
)),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -472,13 +557,71 @@ impl HeaderChain {
|
||||
// write the best and latest eras to the database.
|
||||
{
|
||||
let latest_num = *candidates.iter().rev().next().expect("at least one era just inserted; qed").0;
|
||||
let mut stream = RlpStream::new_list(2);
|
||||
stream.append(&best_num).append(&latest_num);
|
||||
transaction.put(self.col, CURRENT_KEY, &stream.out())
|
||||
let curr = BestAndLatest::new(best_num, latest_num);
|
||||
transaction.put(self.col, CURRENT_KEY, &::rlp::encode(&curr))
|
||||
}
|
||||
Ok(pending)
|
||||
}
|
||||
|
||||
/// Generates the specifications for hardcoded sync. This is typically only called manually
|
||||
/// from time to time by a Parity developer in order to update the chain specifications.
|
||||
///
|
||||
/// Returns `None` if we are at the genesis block, or if an error happens .
|
||||
pub fn read_hardcoded_sync(&self) -> Result<Option<SpecHardcodedSync>, Error> {
|
||||
let mut chts = Vec::new();
|
||||
let mut cht_num = 0;
|
||||
|
||||
loop {
|
||||
let cht = match self.cht_root(cht_num) {
|
||||
Some(cht) => cht,
|
||||
None if cht_num != 0 => {
|
||||
// end of the iteration
|
||||
let h_num = 1 + cht_num as u64 * cht::SIZE;
|
||||
let header = if let Some(header) = self.block_header(BlockId::Number(h_num)) {
|
||||
header
|
||||
} else {
|
||||
let msg = format!("header of block #{} not found in DB ; database in an \
|
||||
inconsistent state", h_num);
|
||||
bail!(ErrorKind::Database(msg.into()));
|
||||
};
|
||||
|
||||
let decoded = header.decode().expect("decoding db value failed");
|
||||
|
||||
let entry: Entry = {
|
||||
let bytes = self.db.get(self.col, era_key(h_num).as_bytes())?
|
||||
.ok_or_else(|| {
|
||||
let msg = format!("entry for era #{} not found in DB ; database \
|
||||
in an inconsistent state", h_num);
|
||||
ErrorKind::Database(msg.into())
|
||||
})?;
|
||||
::rlp::decode(&bytes).expect("decoding db value failed")
|
||||
};
|
||||
|
||||
let total_difficulty = entry.candidates.iter()
|
||||
.find(|c| c.hash == decoded.hash())
|
||||
.ok_or_else(|| {
|
||||
let msg = "no candidate matching block found in DB ; database in an \
|
||||
inconsistent state";
|
||||
ErrorKind::Database(msg.into())
|
||||
})?
|
||||
.total_difficulty;
|
||||
|
||||
break Ok(Some(SpecHardcodedSync {
|
||||
header,
|
||||
total_difficulty,
|
||||
chts,
|
||||
}));
|
||||
},
|
||||
None => {
|
||||
break Ok(None);
|
||||
},
|
||||
};
|
||||
|
||||
chts.push(cht);
|
||||
cht_num += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply pending changes from a previous `insert` operation.
|
||||
/// Must be done before the next `insert` call.
|
||||
pub fn apply_pending(&self, pending: PendingChanges) {
|
||||
@@ -497,7 +640,7 @@ impl HeaderChain {
|
||||
if self.best_block.read().number < num { return None }
|
||||
self.candidates.read().get(&num).map(|entry| entry.canonical_hash)
|
||||
}
|
||||
BlockId::Latest | BlockId::Pending => {
|
||||
BlockId::Latest => {
|
||||
Some(self.best_block.read().hash)
|
||||
}
|
||||
}
|
||||
@@ -539,7 +682,7 @@ impl HeaderChain {
|
||||
self.candidates.read().get(&num).map(|entry| entry.canonical_hash)
|
||||
.and_then(load_from_db)
|
||||
}
|
||||
BlockId::Latest | BlockId::Pending => {
|
||||
BlockId::Latest => {
|
||||
// hold candidates hear to prevent deletion of the header
|
||||
// as we read it.
|
||||
let _candidates = self.candidates.read();
|
||||
@@ -575,7 +718,7 @@ impl HeaderChain {
|
||||
if self.best_block.read().number < num { return None }
|
||||
candidates.get(&num).map(|era| era.candidates[0].total_difficulty)
|
||||
}
|
||||
BlockId::Latest | BlockId::Pending => Some(self.best_block.read().total_difficulty)
|
||||
BlockId::Latest => Some(self.best_block.read().total_difficulty)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -602,7 +745,7 @@ impl HeaderChain {
|
||||
/// so including it within a CHT would be redundant.
|
||||
pub fn cht_root(&self, n: usize) -> Option<H256> {
|
||||
match self.db.get(self.col, cht_key(n as u64).as_bytes()) {
|
||||
Ok(val) => val.map(|x| ::rlp::decode(&x)),
|
||||
Ok(db_fetch) => db_fetch.map(|bytes| ::rlp::decode(&bytes).expect("decoding value from db failed")),
|
||||
Err(e) => {
|
||||
warn!(target: "chain", "Error reading from database: {}", e);
|
||||
None
|
||||
@@ -653,7 +796,7 @@ impl HeaderChain {
|
||||
pub fn pending_transition(&self, hash: H256) -> Option<PendingEpochTransition> {
|
||||
let key = pending_transition_key(hash);
|
||||
match self.db.get(self.col, &*key) {
|
||||
Ok(val) => val.map(|x| ::rlp::decode(&x)),
|
||||
Ok(db_fetch) => db_fetch.map(|bytes| ::rlp::decode(&bytes).expect("decoding value from db failed")),
|
||||
Err(e) => {
|
||||
warn!(target: "chain", "Error reading from database: {}", e);
|
||||
None
|
||||
@@ -672,7 +815,9 @@ impl HeaderChain {
|
||||
|
||||
for hdr in self.ancestry_iter(BlockId::Hash(parent_hash)) {
|
||||
if let Some(transition) = live_proofs.get(&hdr.hash()).cloned() {
|
||||
return Some((hdr.decode(), transition.proof))
|
||||
return hdr.decode().map(|decoded_hdr| {
|
||||
(decoded_hdr, transition.proof)
|
||||
}).ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -721,7 +866,7 @@ impl<'a> Iterator for AncestryIter<'a> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::HeaderChain;
|
||||
use super::{HeaderChain, HardcodedSync};
|
||||
use std::sync::Arc;
|
||||
|
||||
use ethereum_types::U256;
|
||||
@@ -732,7 +877,7 @@ mod tests {
|
||||
use kvdb::KeyValueDB;
|
||||
use kvdb_memorydb;
|
||||
|
||||
use time::Duration;
|
||||
use std::time::Duration;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
fn make_db() -> Arc<KeyValueDB> {
|
||||
@@ -745,9 +890,9 @@ mod tests {
|
||||
let genesis_header = spec.genesis_header();
|
||||
let db = make_db();
|
||||
|
||||
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
|
||||
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::from_secs(6 * 3600))));
|
||||
|
||||
let chain = HeaderChain::new(db.clone(), None, &spec, cache).unwrap();
|
||||
let chain = HeaderChain::new(db.clone(), None, &spec, cache, HardcodedSync::Allow).unwrap();
|
||||
|
||||
let mut parent_hash = genesis_header.hash();
|
||||
let mut rolling_timestamp = genesis_header.timestamp();
|
||||
@@ -778,9 +923,9 @@ mod tests {
|
||||
let spec = Spec::new_test();
|
||||
let genesis_header = spec.genesis_header();
|
||||
let db = make_db();
|
||||
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
|
||||
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::from_secs(6 * 3600))));
|
||||
|
||||
let chain = HeaderChain::new(db.clone(), None, &spec, cache).unwrap();
|
||||
let chain = HeaderChain::new(db.clone(), None, &spec, cache, HardcodedSync::Allow).unwrap();
|
||||
|
||||
let mut parent_hash = genesis_header.hash();
|
||||
let mut rolling_timestamp = genesis_header.timestamp();
|
||||
@@ -860,13 +1005,12 @@ mod tests {
|
||||
fn earliest_is_latest() {
|
||||
let spec = Spec::new_test();
|
||||
let db = make_db();
|
||||
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
|
||||
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::from_secs(6 * 3600))));
|
||||
|
||||
let chain = HeaderChain::new(db.clone(), None, &spec, cache).unwrap();
|
||||
let chain = HeaderChain::new(db.clone(), None, &spec, cache, HardcodedSync::Allow).unwrap();
|
||||
|
||||
assert!(chain.block_header(BlockId::Earliest).is_some());
|
||||
assert!(chain.block_header(BlockId::Latest).is_some());
|
||||
assert!(chain.block_header(BlockId::Pending).is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -874,10 +1018,11 @@ mod tests {
|
||||
let spec = Spec::new_test();
|
||||
let genesis_header = spec.genesis_header();
|
||||
let db = make_db();
|
||||
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
|
||||
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::from_secs(6 * 3600))));
|
||||
|
||||
{
|
||||
let chain = HeaderChain::new(db.clone(), None, &spec, cache.clone()).unwrap();
|
||||
let chain = HeaderChain::new(db.clone(), None, &spec, cache.clone(),
|
||||
HardcodedSync::Allow).unwrap();
|
||||
let mut parent_hash = genesis_header.hash();
|
||||
let mut rolling_timestamp = genesis_header.timestamp();
|
||||
for i in 1..10000 {
|
||||
@@ -897,7 +1042,8 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
let chain = HeaderChain::new(db.clone(), None, &spec, cache.clone()).unwrap();
|
||||
let chain = HeaderChain::new(db.clone(), None, &spec, cache.clone(),
|
||||
HardcodedSync::Allow).unwrap();
|
||||
assert!(chain.block_header(BlockId::Number(10)).is_none());
|
||||
assert!(chain.block_header(BlockId::Number(9000)).is_some());
|
||||
assert!(chain.cht_root(2).is_some());
|
||||
@@ -910,10 +1056,11 @@ mod tests {
|
||||
let spec = Spec::new_test();
|
||||
let genesis_header = spec.genesis_header();
|
||||
let db = make_db();
|
||||
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
|
||||
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::from_secs(6 * 3600))));
|
||||
|
||||
{
|
||||
let chain = HeaderChain::new(db.clone(), None, &spec, cache.clone()).unwrap();
|
||||
let chain = HeaderChain::new(db.clone(), None, &spec, cache.clone(),
|
||||
HardcodedSync::Allow).unwrap();
|
||||
let mut parent_hash = genesis_header.hash();
|
||||
let mut rolling_timestamp = genesis_header.timestamp();
|
||||
|
||||
@@ -955,7 +1102,8 @@ mod tests {
|
||||
}
|
||||
|
||||
// after restoration, non-canonical eras should still be loaded.
|
||||
let chain = HeaderChain::new(db.clone(), None, &spec, cache.clone()).unwrap();
|
||||
let chain = HeaderChain::new(db.clone(), None, &spec, cache.clone(),
|
||||
HardcodedSync::Allow).unwrap();
|
||||
assert_eq!(chain.block_header(BlockId::Latest).unwrap().number(), 10);
|
||||
assert!(chain.candidates.read().get(&100).is_some())
|
||||
}
|
||||
@@ -965,9 +1113,10 @@ mod tests {
|
||||
let spec = Spec::new_test();
|
||||
let genesis_header = spec.genesis_header();
|
||||
let db = make_db();
|
||||
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
|
||||
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::from_secs(6 * 3600))));
|
||||
|
||||
let chain = HeaderChain::new(db.clone(), None, &spec, cache.clone()).unwrap();
|
||||
let chain = HeaderChain::new(db.clone(), None, &spec, cache.clone(),
|
||||
HardcodedSync::Allow).unwrap();
|
||||
|
||||
assert!(chain.block_header(BlockId::Earliest).is_some());
|
||||
assert!(chain.block_header(BlockId::Number(0)).is_some());
|
||||
@@ -979,9 +1128,9 @@ mod tests {
|
||||
let spec = Spec::new_test();
|
||||
let genesis_header = spec.genesis_header();
|
||||
let db = make_db();
|
||||
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
|
||||
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::from_secs(6 * 3600))));
|
||||
|
||||
let chain = HeaderChain::new(db.clone(), None, &spec, cache).unwrap();
|
||||
let chain = HeaderChain::new(db.clone(), None, &spec, cache, HardcodedSync::Allow).unwrap();
|
||||
|
||||
let mut parent_hash = genesis_header.hash();
|
||||
let mut rolling_timestamp = genesis_header.timestamp();
|
||||
@@ -1039,4 +1188,45 @@ mod tests {
|
||||
assert!(chain.live_epoch_proofs.read().is_empty());
|
||||
assert_eq!(chain.epoch_transition_for(parent_hash).unwrap().1, vec![1, 2, 3, 4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hardcoded_sync_gen() {
|
||||
let spec = Spec::new_test();
|
||||
let genesis_header = spec.genesis_header();
|
||||
let db = make_db();
|
||||
|
||||
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::from_secs(6 * 3600))));
|
||||
|
||||
let chain = HeaderChain::new(db.clone(), None, &spec, cache, HardcodedSync::Allow).expect("failed to instantiate a new HeaderChain");
|
||||
|
||||
let mut parent_hash = genesis_header.hash();
|
||||
let mut rolling_timestamp = genesis_header.timestamp();
|
||||
let mut total_difficulty = *genesis_header.difficulty();
|
||||
let h_num = 3 * ::cht::SIZE + 1;
|
||||
for i in 1..10000 {
|
||||
let mut header = Header::new();
|
||||
header.set_parent_hash(parent_hash);
|
||||
header.set_number(i);
|
||||
header.set_timestamp(rolling_timestamp);
|
||||
let diff = *genesis_header.difficulty() * i as u32;
|
||||
header.set_difficulty(diff);
|
||||
if i <= h_num {
|
||||
total_difficulty = total_difficulty + diff;
|
||||
}
|
||||
parent_hash = header.hash();
|
||||
|
||||
let mut tx = db.transaction();
|
||||
let pending = chain.insert(&mut tx, header, None).expect("failed inserting a transaction");
|
||||
db.write(tx).unwrap();
|
||||
chain.apply_pending(pending);
|
||||
|
||||
rolling_timestamp += 10;
|
||||
}
|
||||
|
||||
let hardcoded_sync = chain.read_hardcoded_sync().expect("failed reading hardcoded sync").expect("failed unwrapping hardcoded sync");
|
||||
assert_eq!(hardcoded_sync.chts.len(), 3);
|
||||
assert_eq!(hardcoded_sync.total_difficulty, total_difficulty);
|
||||
let decoded: Header = hardcoded_sync.header.decode().expect("decoding failed");
|
||||
assert_eq!(decoded.number(), h_num);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,27 +19,25 @@
|
||||
use std::sync::{Weak, Arc};
|
||||
|
||||
use ethcore::block_status::BlockStatus;
|
||||
use ethcore::client::{ClientReport, EnvInfo};
|
||||
use ethcore::client::{ClientReport, EnvInfo, ClientIoMessage};
|
||||
use ethcore::engines::{epoch, EthEngine, EpochChange, EpochTransition, Proof};
|
||||
use ethcore::machine::EthereumMachine;
|
||||
use ethcore::error::BlockImportError;
|
||||
use ethcore::error::{Error, BlockImportError};
|
||||
use ethcore::ids::BlockId;
|
||||
use ethcore::header::{BlockNumber, Header};
|
||||
use ethcore::verification::queue::{self, HeaderQueue};
|
||||
use ethcore::blockchain_info::BlockChainInfo;
|
||||
use ethcore::spec::Spec;
|
||||
use ethcore::service::ClientIoMessage;
|
||||
use ethcore::spec::{Spec, SpecHardcodedSync};
|
||||
use ethcore::encoded;
|
||||
use io::IoChannel;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use ethereum_types::{H256, U256};
|
||||
use futures::{IntoFuture, Future};
|
||||
|
||||
use kvdb::{self, KeyValueDB};
|
||||
use kvdb_rocksdb::CompactionProfile;
|
||||
use kvdb::KeyValueDB;
|
||||
|
||||
use self::fetch::ChainDataFetcher;
|
||||
use self::header_chain::{AncestryIter, HeaderChain};
|
||||
use self::header_chain::{AncestryIter, HeaderChain, HardcodedSync};
|
||||
|
||||
use cache::Cache;
|
||||
|
||||
@@ -57,16 +55,12 @@ pub struct Config {
|
||||
pub queue: queue::Config,
|
||||
/// Chain column in database.
|
||||
pub chain_column: Option<u32>,
|
||||
/// Database cache size. `None` => rocksdb default.
|
||||
pub db_cache_size: Option<usize>,
|
||||
/// State db compaction profile
|
||||
pub db_compaction: CompactionProfile,
|
||||
/// Should db have WAL enabled?
|
||||
pub db_wal: bool,
|
||||
/// Should it do full verification of blocks?
|
||||
pub verify_full: bool,
|
||||
/// Should it check the seal of blocks?
|
||||
pub check_seal: bool,
|
||||
/// Disable hardcoded sync.
|
||||
pub no_hardcoded_sync: bool,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
@@ -74,11 +68,9 @@ impl Default for Config {
|
||||
Config {
|
||||
queue: Default::default(),
|
||||
chain_column: None,
|
||||
db_cache_size: None,
|
||||
db_compaction: CompactionProfile::default(),
|
||||
db_wal: true,
|
||||
verify_full: true,
|
||||
check_seal: true,
|
||||
no_hardcoded_sync: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,11 +178,14 @@ impl<T: ChainDataFetcher> Client<T> {
|
||||
fetcher: T,
|
||||
io_channel: IoChannel<ClientIoMessage>,
|
||||
cache: Arc<Mutex<Cache>>
|
||||
) -> Result<Self, kvdb::Error> {
|
||||
) -> Result<Self, Error> {
|
||||
Ok(Client {
|
||||
queue: HeaderQueue::new(config.queue, spec.engine.clone(), io_channel, config.check_seal),
|
||||
engine: spec.engine.clone(),
|
||||
chain: HeaderChain::new(db.clone(), chain_col, &spec, cache)?,
|
||||
chain: {
|
||||
let hs_cfg = if config.no_hardcoded_sync { HardcodedSync::Deny } else { HardcodedSync::Allow };
|
||||
HeaderChain::new(db.clone(), chain_col, &spec, cache, hs_cfg)?
|
||||
},
|
||||
report: RwLock::new(ClientReport::default()),
|
||||
import_lock: Mutex::new(()),
|
||||
db: db,
|
||||
@@ -200,33 +195,19 @@ impl<T: ChainDataFetcher> Client<T> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Generates the specifications for hardcoded sync. This is typically only called manually
|
||||
/// from time to time by a Parity developer in order to update the chain specifications.
|
||||
///
|
||||
/// Returns `None` if we are at the genesis block.
|
||||
pub fn read_hardcoded_sync(&self) -> Result<Option<SpecHardcodedSync>, Error> {
|
||||
self.chain.read_hardcoded_sync()
|
||||
}
|
||||
|
||||
/// Adds a new `LightChainNotify` listener.
|
||||
pub fn add_listener(&self, listener: Weak<LightChainNotify>) {
|
||||
self.listeners.write().push(listener);
|
||||
}
|
||||
|
||||
/// Create a new `Client` backed purely in-memory.
|
||||
/// This will ignore all database options in the configuration.
|
||||
pub fn in_memory(
|
||||
config: Config,
|
||||
spec: &Spec,
|
||||
fetcher: T,
|
||||
io_channel: IoChannel<ClientIoMessage>,
|
||||
cache: Arc<Mutex<Cache>>
|
||||
) -> Self {
|
||||
let db = ::kvdb_memorydb::create(0);
|
||||
|
||||
Client::new(
|
||||
config,
|
||||
Arc::new(db),
|
||||
None,
|
||||
spec,
|
||||
fetcher,
|
||||
io_channel,
|
||||
cache
|
||||
).expect("New DB creation infallible; qed")
|
||||
}
|
||||
|
||||
/// Import a header to the queue for additional verification.
|
||||
pub fn import_header(&self, header: Header) -> Result<H256, BlockImportError> {
|
||||
self.queue.import(header).map_err(Into::into)
|
||||
@@ -337,7 +318,7 @@ impl<T: ChainDataFetcher> Client<T> {
|
||||
|
||||
let epoch_proof = self.engine.is_epoch_end(
|
||||
&verified_header,
|
||||
&|h| self.chain.block_header(BlockId::Hash(h)).map(|hdr| hdr.decode()),
|
||||
&|h| self.chain.block_header(BlockId::Hash(h)).and_then(|hdr| hdr.decode().ok()),
|
||||
&|h| self.chain.pending_transition(h),
|
||||
);
|
||||
|
||||
@@ -445,7 +426,15 @@ impl<T: ChainDataFetcher> Client<T> {
|
||||
};
|
||||
|
||||
// Verify Block Family
|
||||
let verify_family_result = self.engine.verify_block_family(&verified_header, &parent_header.decode());
|
||||
|
||||
let verify_family_result = {
|
||||
parent_header.decode()
|
||||
.map_err(|dec_err| dec_err.into())
|
||||
.and_then(|decoded| {
|
||||
self.engine.verify_block_family(&verified_header, &decoded)
|
||||
})
|
||||
|
||||
};
|
||||
if let Err(e) = verify_family_result {
|
||||
warn!(target: "client", "Stage 3 block verification failed for #{} ({})\nError: {:?}",
|
||||
verified_header.number(), verified_header.hash(), e);
|
||||
@@ -606,6 +595,12 @@ impl<T: ChainDataFetcher> LightChainClient for Client<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ChainDataFetcher> ::ethcore::client::ChainInfo for Client<T> {
|
||||
fn chain_info(&self) -> BlockChainInfo {
|
||||
Client::chain_info(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ChainDataFetcher> ::ethcore::client::EngineClient for Client<T> {
|
||||
fn update_sealing(&self) { }
|
||||
fn submit_seal(&self, _block_hash: H256, _seal: Vec<Vec<u8>>) { }
|
||||
@@ -619,10 +614,6 @@ impl<T: ChainDataFetcher> ::ethcore::client::EngineClient for Client<T> {
|
||||
})
|
||||
}
|
||||
|
||||
fn chain_info(&self) -> BlockChainInfo {
|
||||
Client::chain_info(self)
|
||||
}
|
||||
|
||||
fn as_full_client(&self) -> Option<&::ethcore::client::BlockChainClient> {
|
||||
None
|
||||
}
|
||||
|
||||
@@ -18,34 +18,40 @@
|
||||
//! Just handles block import messages and passes them to the client.
|
||||
|
||||
use std::fmt;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use ethcore::client::ClientIoMessage;
|
||||
use ethcore::db;
|
||||
use ethcore::service::ClientIoMessage;
|
||||
use ethcore::error::Error as CoreError;
|
||||
use ethcore::spec::Spec;
|
||||
use io::{IoContext, IoError, IoHandler, IoService};
|
||||
use kvdb;
|
||||
use kvdb_rocksdb::{Database, DatabaseConfig};
|
||||
use kvdb::KeyValueDB;
|
||||
|
||||
use cache::Cache;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use super::{ChainDataFetcher, Client, Config as ClientConfig};
|
||||
use super::{ChainDataFetcher, LightChainNotify, Client, Config as ClientConfig};
|
||||
|
||||
/// Errors on service initialization.
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// Database error.
|
||||
Database(kvdb::Error),
|
||||
/// Core error.
|
||||
Core(CoreError),
|
||||
/// I/O service error.
|
||||
Io(IoError),
|
||||
}
|
||||
|
||||
impl From<CoreError> for Error {
|
||||
#[inline]
|
||||
fn from(err: CoreError) -> Error {
|
||||
Error::Core(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Error::Database(ref msg) => write!(f, "Database error: {}", msg),
|
||||
Error::Core(ref msg) => write!(f, "Core error: {}", msg),
|
||||
Error::Io(ref err) => write!(f, "I/O service error: {}", err),
|
||||
}
|
||||
}
|
||||
@@ -59,19 +65,7 @@ pub struct Service<T> {
|
||||
|
||||
impl<T: ChainDataFetcher> Service<T> {
|
||||
/// Start the service: initialize I/O workers and client itself.
|
||||
pub fn start(config: ClientConfig, spec: &Spec, fetcher: T, path: &Path, cache: Arc<Mutex<Cache>>) -> Result<Self, Error> {
|
||||
|
||||
// initialize database.
|
||||
let mut db_config = DatabaseConfig::with_columns(db::NUM_COLUMNS);
|
||||
|
||||
db_config.memory_budget = config.db_cache_size;
|
||||
db_config.compaction = config.db_compaction;
|
||||
db_config.wal = config.db_wal;
|
||||
|
||||
let db = Arc::new(Database::open(
|
||||
&db_config,
|
||||
&path.to_str().expect("DB path could not be converted to string.")
|
||||
).map_err(Error::Database)?);
|
||||
pub fn start(config: ClientConfig, spec: &Spec, fetcher: T, db: Arc<KeyValueDB>, cache: Arc<Mutex<Cache>>) -> Result<Self, Error> {
|
||||
|
||||
let io_service = IoService::<ClientIoMessage>::start().map_err(Error::Io)?;
|
||||
let client = Arc::new(Client::new(config,
|
||||
@@ -81,7 +75,7 @@ impl<T: ChainDataFetcher> Service<T> {
|
||||
fetcher,
|
||||
io_service.channel(),
|
||||
cache,
|
||||
).map_err(Error::Database)?);
|
||||
)?);
|
||||
|
||||
io_service.register_handler(Arc::new(ImportBlocks(client.clone()))).map_err(Error::Io)?;
|
||||
spec.engine.register_client(Arc::downgrade(&client) as _);
|
||||
@@ -92,6 +86,11 @@ impl<T: ChainDataFetcher> Service<T> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Set the actor to be notified on certain chain events
|
||||
pub fn add_notify(&self, notify: Arc<LightChainNotify>) {
|
||||
self.client.add_listener(Arc::downgrade(¬ify));
|
||||
}
|
||||
|
||||
/// Register an I/O handler on the service.
|
||||
pub fn register_handler(&self, handler: Arc<IoHandler<ClientIoMessage> + Send>) -> Result<(), IoError> {
|
||||
self.io_service.register_handler(handler)
|
||||
@@ -121,16 +120,17 @@ mod tests {
|
||||
use std::sync::Arc;
|
||||
use cache::Cache;
|
||||
use client::fetch;
|
||||
use time::Duration;
|
||||
use std::time::Duration;
|
||||
use parking_lot::Mutex;
|
||||
use tempdir::TempDir;
|
||||
use kvdb_memorydb;
|
||||
use ethcore::db::NUM_COLUMNS;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let tempdir = TempDir::new("").unwrap();
|
||||
let db = Arc::new(kvdb_memorydb::create(NUM_COLUMNS.unwrap_or(0)));
|
||||
let spec = Spec::new_test();
|
||||
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
|
||||
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::from_secs(6 * 3600))));
|
||||
|
||||
Service::start(Default::default(), &spec, fetch::unavailable(), tempdir.path(), cache).unwrap();
|
||||
Service::start(Default::default(), &spec, fetch::unavailable(), db, cache).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ pub mod provider;
|
||||
mod types;
|
||||
|
||||
pub use self::cache::Cache;
|
||||
pub use self::provider::Provider;
|
||||
pub use self::provider::{Provider, MAX_HEADERS_PER_REQUEST};
|
||||
pub use self::transaction_queue::TransactionQueue;
|
||||
pub use types::request as request;
|
||||
|
||||
@@ -75,14 +75,15 @@ extern crate rlp_derive;
|
||||
extern crate serde;
|
||||
extern crate smallvec;
|
||||
extern crate stats;
|
||||
extern crate time;
|
||||
extern crate vm;
|
||||
extern crate keccak_hash as hash;
|
||||
extern crate triehash;
|
||||
extern crate kvdb;
|
||||
extern crate kvdb_memorydb;
|
||||
extern crate kvdb_rocksdb;
|
||||
extern crate memory_cache;
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate kvdb_memorydb;
|
||||
#[cfg(test)]
|
||||
extern crate tempdir;
|
||||
|
||||
@@ -47,7 +47,7 @@ pub trait IoContext {
|
||||
}
|
||||
|
||||
|
||||
impl<'a> IoContext for NetworkContext<'a> {
|
||||
impl<T> IoContext for T where T: ?Sized + NetworkContext {
|
||||
fn send(&self, peer: PeerId, packet_id: u8, packet_body: Vec<u8>) {
|
||||
if let Err(e) = self.send(peer, packet_id, packet_body) {
|
||||
debug!(target: "pip", "Error sending packet to peer {}: {}", peer, e);
|
||||
|
||||
@@ -27,11 +27,11 @@
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::fs::File;
|
||||
use std::path::PathBuf;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use request::{CompleteRequest, Kind};
|
||||
|
||||
use bincode;
|
||||
use time;
|
||||
use parking_lot::{RwLock, Mutex};
|
||||
|
||||
/// Number of time periods samples should be kept for.
|
||||
@@ -48,11 +48,11 @@ pub trait SampleStore: Send + Sync {
|
||||
}
|
||||
|
||||
// get a hardcoded, arbitrarily determined (but intended overestimate)
|
||||
// of the time in nanoseconds to serve a request of the given kind.
|
||||
// of the time it takes to serve a request of the given kind.
|
||||
//
|
||||
// TODO: seed this with empirical data.
|
||||
fn hardcoded_serve_time(kind: Kind) -> u64 {
|
||||
match kind {
|
||||
fn hardcoded_serve_time(kind: Kind) -> Duration {
|
||||
Duration::new(0, match kind {
|
||||
Kind::Headers => 500_000,
|
||||
Kind::HeaderProof => 500_000,
|
||||
Kind::TransactionIndex => 500_000,
|
||||
@@ -63,7 +63,7 @@ fn hardcoded_serve_time(kind: Kind) -> u64 {
|
||||
Kind::Code => 1_500_000,
|
||||
Kind::Execution => 250, // per gas.
|
||||
Kind::Signal => 500_000,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// A no-op store.
|
||||
@@ -107,17 +107,17 @@ impl LoadDistribution {
|
||||
};
|
||||
|
||||
LoadTimer {
|
||||
start: time::precise_time_ns(),
|
||||
start: Instant::now(),
|
||||
n: n,
|
||||
dist: self,
|
||||
kind: kind,
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate EMA of load in nanoseconds for a specific request kind.
|
||||
/// Calculate EMA of load for a specific request kind.
|
||||
/// If there is no data for the given request kind, no EMA will be calculated,
|
||||
/// but a hardcoded time will be returned.
|
||||
pub fn expected_time_ns(&self, kind: Kind) -> u64 {
|
||||
pub fn expected_time(&self, kind: Kind) -> Duration {
|
||||
let samples = self.samples.read();
|
||||
samples.get(&kind).and_then(|s| {
|
||||
if s.len() == 0 { return None }
|
||||
@@ -128,7 +128,9 @@ impl LoadDistribution {
|
||||
(alpha * c as f64) + ((1.0 - alpha) * a)
|
||||
});
|
||||
|
||||
Some(ema as u64)
|
||||
// TODO: use `Duration::from_nanos` once stable (https://github.com/rust-lang/rust/issues/46507)
|
||||
let ema = ema as u64;
|
||||
Some(Duration::new(ema / 1_000_000_000, (ema % 1_000_000_000) as u32))
|
||||
}).unwrap_or_else(move || hardcoded_serve_time(kind))
|
||||
}
|
||||
|
||||
@@ -151,10 +153,10 @@ impl LoadDistribution {
|
||||
store.store(&*samples);
|
||||
}
|
||||
|
||||
fn update(&self, kind: Kind, elapsed: u64, n: u64) {
|
||||
fn update(&self, kind: Kind, elapsed: Duration, n: u64) {
|
||||
macro_rules! update_counters {
|
||||
($counters: expr) => {
|
||||
$counters.0 = $counters.0.saturating_add(elapsed);
|
||||
$counters.0 = $counters.0.saturating_add({ elapsed.as_secs() * 1_000_000_000 + elapsed.subsec_nanos() as u64 });
|
||||
$counters.1 = $counters.1.saturating_add(n);
|
||||
}
|
||||
};
|
||||
@@ -180,7 +182,7 @@ impl LoadDistribution {
|
||||
/// A timer for a single request.
|
||||
/// On drop, this will update the distribution.
|
||||
pub struct LoadTimer<'a> {
|
||||
start: u64,
|
||||
start: Instant,
|
||||
n: u64,
|
||||
dist: &'a LoadDistribution,
|
||||
kind: Kind,
|
||||
@@ -188,7 +190,7 @@ pub struct LoadTimer<'a> {
|
||||
|
||||
impl<'a> Drop for LoadTimer<'a> {
|
||||
fn drop(&mut self) {
|
||||
let elapsed = time::precise_time_ns() - self.start;
|
||||
let elapsed = self.start.elapsed();
|
||||
self.dist.update(self.kind, elapsed, self.n);
|
||||
}
|
||||
}
|
||||
@@ -223,12 +225,12 @@ mod tests {
|
||||
#[test]
|
||||
fn hardcoded_before_data() {
|
||||
let dist = LoadDistribution::load(&NullStore);
|
||||
assert_eq!(dist.expected_time_ns(Kind::Headers), hardcoded_serve_time(Kind::Headers));
|
||||
assert_eq!(dist.expected_time(Kind::Headers), hardcoded_serve_time(Kind::Headers));
|
||||
|
||||
dist.update(Kind::Headers, 100_000, 100);
|
||||
dist.update(Kind::Headers, Duration::new(0, 100_000), 100);
|
||||
dist.end_period(&NullStore);
|
||||
|
||||
assert_eq!(dist.expected_time_ns(Kind::Headers), 1000);
|
||||
assert_eq!(dist.expected_time(Kind::Headers), Duration::new(0, 1000));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -238,26 +240,26 @@ mod tests {
|
||||
let mut sum = 0;
|
||||
|
||||
for (i, x) in (0..10).map(|x| x * 10_000).enumerate() {
|
||||
dist.update(Kind::Headers, x, 1);
|
||||
dist.update(Kind::Headers, Duration::new(0, x), 1);
|
||||
dist.end_period(&NullStore);
|
||||
|
||||
sum += x;
|
||||
if i == 0 { continue }
|
||||
|
||||
let moving_average = dist.expected_time_ns(Kind::Headers);
|
||||
let moving_average = dist.expected_time(Kind::Headers);
|
||||
|
||||
// should be weighted below the maximum entry.
|
||||
let arith_average = (sum as f64 / (i + 1) as f64) as u64;
|
||||
assert!(moving_average < x);
|
||||
let arith_average = (sum as f64 / (i + 1) as f64) as u32;
|
||||
assert!(moving_average < Duration::new(0, x));
|
||||
|
||||
// when there are only 2 entries, they should be equal due to choice of
|
||||
// ALPHA = 1/N.
|
||||
// otherwise, the weight should be below the arithmetic mean because the much
|
||||
// smaller previous values are discounted less.
|
||||
if i == 1 {
|
||||
assert_eq!(moving_average, arith_average);
|
||||
assert_eq!(moving_average, Duration::new(0, arith_average));
|
||||
} else {
|
||||
assert!(moving_average < arith_average)
|
||||
assert!(moving_average < Duration::new(0, arith_average))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,11 +22,11 @@ use transaction::UnverifiedTransaction;
|
||||
|
||||
use io::TimerToken;
|
||||
use network::{HostInfo, NetworkProtocolHandler, NetworkContext, PeerId};
|
||||
use rlp::{RlpStream, UntrustedRlp};
|
||||
use rlp::{RlpStream, Rlp};
|
||||
use ethereum_types::{H256, U256};
|
||||
use kvdb::DBValue;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use time::{Duration, SteadyTime};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt;
|
||||
@@ -61,28 +61,31 @@ pub use self::load_timer::{SampleStore, FileStore};
|
||||
pub use self::status::{Status, Capabilities, Announcement};
|
||||
|
||||
const TIMEOUT: TimerToken = 0;
|
||||
const TIMEOUT_INTERVAL_MS: u64 = 1000;
|
||||
const TIMEOUT_INTERVAL: Duration = Duration::from_secs(1);
|
||||
|
||||
const TICK_TIMEOUT: TimerToken = 1;
|
||||
const TICK_TIMEOUT_INTERVAL_MS: u64 = 5000;
|
||||
const TICK_TIMEOUT_INTERVAL: Duration = Duration::from_secs(5);
|
||||
|
||||
const PROPAGATE_TIMEOUT: TimerToken = 2;
|
||||
const PROPAGATE_TIMEOUT_INTERVAL_MS: u64 = 5000;
|
||||
const PROPAGATE_TIMEOUT_INTERVAL: Duration = Duration::from_secs(5);
|
||||
|
||||
const RECALCULATE_COSTS_TIMEOUT: TimerToken = 3;
|
||||
const RECALCULATE_COSTS_INTERVAL_MS: u64 = 60 * 60 * 1000;
|
||||
const RECALCULATE_COSTS_INTERVAL: Duration = Duration::from_secs(60 * 60);
|
||||
|
||||
// minimum interval between updates.
|
||||
const UPDATE_INTERVAL_MS: i64 = 5000;
|
||||
const UPDATE_INTERVAL: Duration = Duration::from_millis(5000);
|
||||
|
||||
/// Packet count for PIP.
|
||||
const PACKET_COUNT_V1: u8 = 9;
|
||||
|
||||
/// Supported protocol versions.
|
||||
pub const PROTOCOL_VERSIONS: &'static [u8] = &[1];
|
||||
pub const PROTOCOL_VERSIONS: &'static [(u8, u8)] = &[
|
||||
(1, PACKET_COUNT_V1),
|
||||
];
|
||||
|
||||
/// Max protocol version.
|
||||
pub const MAX_PROTOCOL_VERSION: u8 = 1;
|
||||
|
||||
/// Packet count for PIP.
|
||||
pub const PACKET_COUNT: u8 = 9;
|
||||
|
||||
// packet ID definitions.
|
||||
mod packet {
|
||||
@@ -109,20 +112,22 @@ mod packet {
|
||||
|
||||
// timeouts for different kinds of requests. all values are in milliseconds.
|
||||
mod timeout {
|
||||
pub const HANDSHAKE: i64 = 2500;
|
||||
pub const ACKNOWLEDGE_UPDATE: i64 = 5000;
|
||||
pub const BASE: i64 = 1500; // base timeout for packet.
|
||||
use std::time::Duration;
|
||||
|
||||
pub const HANDSHAKE: Duration = Duration::from_millis(4_000);
|
||||
pub const ACKNOWLEDGE_UPDATE: Duration = Duration::from_millis(5_000);
|
||||
pub const BASE: u64 = 2_500; // base timeout for packet.
|
||||
|
||||
// timeouts per request within packet.
|
||||
pub const HEADERS: i64 = 250; // per header?
|
||||
pub const TRANSACTION_INDEX: i64 = 100;
|
||||
pub const BODY: i64 = 50;
|
||||
pub const RECEIPT: i64 = 50;
|
||||
pub const PROOF: i64 = 100; // state proof
|
||||
pub const CONTRACT_CODE: i64 = 100;
|
||||
pub const HEADER_PROOF: i64 = 100;
|
||||
pub const TRANSACTION_PROOF: i64 = 1000; // per gas?
|
||||
pub const EPOCH_SIGNAL: i64 = 200;
|
||||
pub const HEADERS: u64 = 250; // per header?
|
||||
pub const TRANSACTION_INDEX: u64 = 100;
|
||||
pub const BODY: u64 = 50;
|
||||
pub const RECEIPT: u64 = 50;
|
||||
pub const PROOF: u64 = 100; // state proof
|
||||
pub const CONTRACT_CODE: u64 = 100;
|
||||
pub const HEADER_PROOF: u64 = 100;
|
||||
pub const TRANSACTION_PROOF: u64 = 1000; // per gas?
|
||||
pub const EPOCH_SIGNAL: u64 = 200;
|
||||
}
|
||||
|
||||
/// A request id.
|
||||
@@ -144,7 +149,7 @@ impl fmt::Display for ReqId {
|
||||
// may not have received one for.
|
||||
struct PendingPeer {
|
||||
sent_head: H256,
|
||||
last_update: SteadyTime,
|
||||
last_update: Instant,
|
||||
}
|
||||
|
||||
/// Relevant data to each peer. Not accessible publicly, only `pub` due to
|
||||
@@ -155,13 +160,13 @@ pub struct Peer {
|
||||
capabilities: Capabilities,
|
||||
remote_flow: Option<(Credits, FlowParams)>,
|
||||
sent_head: H256, // last chain head we've given them.
|
||||
last_update: SteadyTime,
|
||||
last_update: Instant,
|
||||
pending_requests: RequestSet,
|
||||
failed_requests: Vec<ReqId>,
|
||||
propagated_transactions: HashSet<H256>,
|
||||
skip_update: bool,
|
||||
local_flow: Arc<FlowParams>,
|
||||
awaiting_acknowledge: Option<(SteadyTime, Arc<FlowParams>)>,
|
||||
awaiting_acknowledge: Option<(Instant, Arc<FlowParams>)>,
|
||||
}
|
||||
|
||||
/// Whether or not a peer was kept by a handler
|
||||
@@ -367,9 +372,9 @@ impl LightProtocol {
|
||||
let sample_store = params.sample_store.unwrap_or_else(|| Box::new(NullStore));
|
||||
let load_distribution = LoadDistribution::load(&*sample_store);
|
||||
let flow_params = FlowParams::from_request_times(
|
||||
|kind| load_distribution.expected_time_ns(kind),
|
||||
|kind| load_distribution.expected_time(kind),
|
||||
params.config.load_share,
|
||||
params.config.max_stored_seconds,
|
||||
Duration::from_secs(params.config.max_stored_seconds),
|
||||
);
|
||||
|
||||
LightProtocol {
|
||||
@@ -447,7 +452,7 @@ impl LightProtocol {
|
||||
});
|
||||
|
||||
// begin timeout.
|
||||
peer.pending_requests.insert(req_id, requests, cost, SteadyTime::now());
|
||||
peer.pending_requests.insert(req_id, requests, cost, Instant::now());
|
||||
Ok(req_id)
|
||||
}
|
||||
}
|
||||
@@ -457,7 +462,7 @@ impl LightProtocol {
|
||||
/// The announcement is expected to be valid.
|
||||
pub fn make_announcement(&self, io: &IoContext, mut announcement: Announcement) {
|
||||
let mut reorgs_map = HashMap::new();
|
||||
let now = SteadyTime::now();
|
||||
let now = Instant::now();
|
||||
|
||||
// update stored capabilities
|
||||
self.capabilities.write().update_from(&announcement);
|
||||
@@ -470,7 +475,7 @@ impl LightProtocol {
|
||||
// the timer approach will skip 1 (possibly 2) in rare occasions.
|
||||
if peer_info.sent_head == announcement.head_hash ||
|
||||
peer_info.status.head_num >= announcement.head_num ||
|
||||
now - peer_info.last_update < Duration::milliseconds(UPDATE_INTERVAL_MS) {
|
||||
now - peer_info.last_update < UPDATE_INTERVAL {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -526,7 +531,7 @@ impl LightProtocol {
|
||||
// - check whether peer exists
|
||||
// - check whether request was made
|
||||
// - check whether request kinds match
|
||||
fn pre_verify_response(&self, peer: &PeerId, raw: &UntrustedRlp) -> Result<IdGuard, Error> {
|
||||
fn pre_verify_response(&self, peer: &PeerId, raw: &Rlp) -> Result<IdGuard, Error> {
|
||||
let req_id = ReqId(raw.val_at(0)?);
|
||||
let cur_credits: U256 = raw.val_at(1)?;
|
||||
|
||||
@@ -537,7 +542,7 @@ impl LightProtocol {
|
||||
Some(peer_info) => {
|
||||
let mut peer_info = peer_info.lock();
|
||||
let peer_info: &mut Peer = &mut *peer_info;
|
||||
let req_info = peer_info.pending_requests.remove(&req_id, SteadyTime::now());
|
||||
let req_info = peer_info.pending_requests.remove(&req_id, Instant::now());
|
||||
let last_batched = peer_info.pending_requests.is_empty();
|
||||
let flow_info = peer_info.remote_flow.as_mut();
|
||||
|
||||
@@ -570,7 +575,7 @@ impl LightProtocol {
|
||||
/// Packet data is _untrusted_, which means that invalid data won't lead to
|
||||
/// issues.
|
||||
pub fn handle_packet(&self, io: &IoContext, peer: &PeerId, packet_id: u8, data: &[u8]) {
|
||||
let rlp = UntrustedRlp::new(data);
|
||||
let rlp = Rlp::new(data);
|
||||
|
||||
trace!(target: "pip", "Incoming packet {} from peer {}", packet_id, peer);
|
||||
|
||||
@@ -599,14 +604,14 @@ impl LightProtocol {
|
||||
|
||||
// check timeouts and punish peers.
|
||||
fn timeout_check(&self, io: &IoContext) {
|
||||
let now = SteadyTime::now();
|
||||
let now = Instant::now();
|
||||
|
||||
// handshake timeout
|
||||
{
|
||||
let mut pending = self.pending_peers.write();
|
||||
let slowpokes: Vec<_> = pending.iter()
|
||||
.filter(|&(_, ref peer)| {
|
||||
peer.last_update + Duration::milliseconds(timeout::HANDSHAKE) <= now
|
||||
peer.last_update + timeout::HANDSHAKE <= now
|
||||
})
|
||||
.map(|(&p, _)| p)
|
||||
.collect();
|
||||
@@ -619,7 +624,7 @@ impl LightProtocol {
|
||||
}
|
||||
|
||||
// request and update ack timeouts
|
||||
let ack_duration = Duration::milliseconds(timeout::ACKNOWLEDGE_UPDATE);
|
||||
let ack_duration = timeout::ACKNOWLEDGE_UPDATE;
|
||||
{
|
||||
for (peer_id, peer) in self.peers.read().iter() {
|
||||
let peer = peer.lock();
|
||||
@@ -643,7 +648,7 @@ impl LightProtocol {
|
||||
fn propagate_transactions(&self, io: &IoContext) {
|
||||
if self.capabilities.read().tx_relay { return }
|
||||
|
||||
let ready_transactions = self.provider.ready_transactions();
|
||||
let ready_transactions = self.provider.transactions_to_propagate();
|
||||
if ready_transactions.is_empty() { return }
|
||||
|
||||
trace!(target: "pip", "propagate transactions: {} ready", ready_transactions.len());
|
||||
@@ -686,7 +691,7 @@ impl LightProtocol {
|
||||
Err(e) => { punish(*peer, io, e); return }
|
||||
};
|
||||
|
||||
if PROTOCOL_VERSIONS.iter().find(|x| **x == proto_version).is_none() {
|
||||
if PROTOCOL_VERSIONS.iter().find(|x| x.0 == proto_version).is_none() {
|
||||
punish(*peer, io, Error::UnsupportedProtocolVersion(proto_version));
|
||||
return;
|
||||
}
|
||||
@@ -709,7 +714,7 @@ impl LightProtocol {
|
||||
|
||||
self.pending_peers.write().insert(*peer, PendingPeer {
|
||||
sent_head: chain_info.best_block_hash,
|
||||
last_update: SteadyTime::now(),
|
||||
last_update: Instant::now(),
|
||||
});
|
||||
|
||||
trace!(target: "pip", "Sending status to peer {}", peer);
|
||||
@@ -764,14 +769,14 @@ impl LightProtocol {
|
||||
self.load_distribution.end_period(&*self.sample_store);
|
||||
|
||||
let new_params = Arc::new(FlowParams::from_request_times(
|
||||
|kind| self.load_distribution.expected_time_ns(kind),
|
||||
|kind| self.load_distribution.expected_time(kind),
|
||||
self.config.load_share,
|
||||
self.config.max_stored_seconds,
|
||||
Duration::from_secs(self.config.max_stored_seconds),
|
||||
));
|
||||
*self.flow_params.write() = new_params.clone();
|
||||
|
||||
let peers = self.peers.read();
|
||||
let now = SteadyTime::now();
|
||||
let now = Instant::now();
|
||||
|
||||
let packet_body = {
|
||||
let mut stream = RlpStream::new_list(3);
|
||||
@@ -792,7 +797,7 @@ impl LightProtocol {
|
||||
|
||||
impl LightProtocol {
|
||||
// Handle status message from peer.
|
||||
fn status(&self, peer: &PeerId, io: &IoContext, data: UntrustedRlp) -> Result<(), Error> {
|
||||
fn status(&self, peer: &PeerId, io: &IoContext, data: Rlp) -> Result<(), Error> {
|
||||
let pending = match self.pending_peers.write().remove(peer) {
|
||||
Some(pending) => pending,
|
||||
None => {
|
||||
@@ -853,7 +858,7 @@ impl LightProtocol {
|
||||
}
|
||||
|
||||
// Handle an announcement.
|
||||
fn announcement(&self, peer: &PeerId, io: &IoContext, data: UntrustedRlp) -> Result<(), Error> {
|
||||
fn announcement(&self, peer: &PeerId, io: &IoContext, data: Rlp) -> Result<(), Error> {
|
||||
if !self.peers.read().contains_key(peer) {
|
||||
debug!(target: "pip", "Ignoring announcement from unknown peer");
|
||||
return Ok(())
|
||||
@@ -898,7 +903,7 @@ impl LightProtocol {
|
||||
}
|
||||
|
||||
// Receive requests from a peer.
|
||||
fn request(&self, peer_id: &PeerId, io: &IoContext, raw: UntrustedRlp) -> Result<(), Error> {
|
||||
fn request(&self, peer_id: &PeerId, io: &IoContext, raw: Rlp) -> Result<(), Error> {
|
||||
// the maximum amount of requests we'll fill in a single packet.
|
||||
const MAX_REQUESTS: usize = 256;
|
||||
|
||||
@@ -966,7 +971,7 @@ impl LightProtocol {
|
||||
}
|
||||
|
||||
// handle a packet with responses.
|
||||
fn response(&self, peer: &PeerId, io: &IoContext, raw: UntrustedRlp) -> Result<(), Error> {
|
||||
fn response(&self, peer: &PeerId, io: &IoContext, raw: Rlp) -> Result<(), Error> {
|
||||
let (req_id, responses) = {
|
||||
let id_guard = self.pre_verify_response(peer, &raw)?;
|
||||
let responses: Vec<Response> = raw.list_at(2)?;
|
||||
@@ -985,7 +990,7 @@ impl LightProtocol {
|
||||
}
|
||||
|
||||
// handle an update of request credits parameters.
|
||||
fn update_credits(&self, peer_id: &PeerId, io: &IoContext, raw: UntrustedRlp) -> Result<(), Error> {
|
||||
fn update_credits(&self, peer_id: &PeerId, io: &IoContext, raw: Rlp) -> Result<(), Error> {
|
||||
let peers = self.peers.read();
|
||||
|
||||
let peer = peers.get(peer_id).ok_or(Error::UnknownPeer)?;
|
||||
@@ -1020,7 +1025,7 @@ impl LightProtocol {
|
||||
}
|
||||
|
||||
// handle an acknowledgement of request credits update.
|
||||
fn acknowledge_update(&self, peer_id: &PeerId, _io: &IoContext, _raw: UntrustedRlp) -> Result<(), Error> {
|
||||
fn acknowledge_update(&self, peer_id: &PeerId, _io: &IoContext, _raw: Rlp) -> Result<(), Error> {
|
||||
let peers = self.peers.read();
|
||||
let peer = peers.get(peer_id).ok_or(Error::UnknownPeer)?;
|
||||
let mut peer = peer.lock();
|
||||
@@ -1039,7 +1044,7 @@ impl LightProtocol {
|
||||
}
|
||||
|
||||
// Receive a set of transactions to relay.
|
||||
fn relay_transactions(&self, peer: &PeerId, io: &IoContext, data: UntrustedRlp) -> Result<(), Error> {
|
||||
fn relay_transactions(&self, peer: &PeerId, io: &IoContext, data: Rlp) -> Result<(), Error> {
|
||||
const MAX_TRANSACTIONS: usize = 256;
|
||||
|
||||
let txs: Vec<_> = data.iter()
|
||||
@@ -1078,34 +1083,34 @@ fn punish(peer: PeerId, io: &IoContext, e: Error) {
|
||||
|
||||
impl NetworkProtocolHandler for LightProtocol {
|
||||
fn initialize(&self, io: &NetworkContext, _host_info: &HostInfo) {
|
||||
io.register_timer(TIMEOUT, TIMEOUT_INTERVAL_MS)
|
||||
io.register_timer(TIMEOUT, TIMEOUT_INTERVAL)
|
||||
.expect("Error registering sync timer.");
|
||||
io.register_timer(TICK_TIMEOUT, TICK_TIMEOUT_INTERVAL_MS)
|
||||
io.register_timer(TICK_TIMEOUT, TICK_TIMEOUT_INTERVAL)
|
||||
.expect("Error registering sync timer.");
|
||||
io.register_timer(PROPAGATE_TIMEOUT, PROPAGATE_TIMEOUT_INTERVAL_MS)
|
||||
io.register_timer(PROPAGATE_TIMEOUT, PROPAGATE_TIMEOUT_INTERVAL)
|
||||
.expect("Error registering sync timer.");
|
||||
io.register_timer(RECALCULATE_COSTS_TIMEOUT, RECALCULATE_COSTS_INTERVAL_MS)
|
||||
io.register_timer(RECALCULATE_COSTS_TIMEOUT, RECALCULATE_COSTS_INTERVAL)
|
||||
.expect("Error registering request timer interval token.");
|
||||
}
|
||||
|
||||
fn read(&self, io: &NetworkContext, peer: &PeerId, packet_id: u8, data: &[u8]) {
|
||||
self.handle_packet(io, peer, packet_id, data);
|
||||
self.handle_packet(&io, peer, packet_id, data);
|
||||
}
|
||||
|
||||
fn connected(&self, io: &NetworkContext, peer: &PeerId) {
|
||||
self.on_connect(peer, io);
|
||||
self.on_connect(peer, &io);
|
||||
}
|
||||
|
||||
fn disconnected(&self, io: &NetworkContext, peer: &PeerId) {
|
||||
self.on_disconnect(*peer, io);
|
||||
self.on_disconnect(*peer, &io);
|
||||
}
|
||||
|
||||
fn timeout(&self, io: &NetworkContext, timer: TimerToken) {
|
||||
match timer {
|
||||
TIMEOUT => self.timeout_check(io),
|
||||
TICK_TIMEOUT => self.tick_handlers(io),
|
||||
PROPAGATE_TIMEOUT => self.propagate_transactions(io),
|
||||
RECALCULATE_COSTS_TIMEOUT => self.begin_new_cost_period(io),
|
||||
TIMEOUT => self.timeout_check(&io),
|
||||
TICK_TIMEOUT => self.tick_handlers(&io),
|
||||
PROPAGATE_TIMEOUT => self.propagate_transactions(&io),
|
||||
RECALCULATE_COSTS_TIMEOUT => self.begin_new_cost_period(&io),
|
||||
_ => warn!(target: "pip", "received timeout on unknown token {}", timer),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
use request::{self, Request};
|
||||
use super::error::Error;
|
||||
|
||||
use rlp::*;
|
||||
use rlp::{Rlp, RlpStream, Decodable, Encodable, DecoderError};
|
||||
use ethereum_types::U256;
|
||||
use time::{Duration, SteadyTime};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
/// Credits value.
|
||||
///
|
||||
@@ -41,7 +41,7 @@ use time::{Duration, SteadyTime};
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Credits {
|
||||
estimate: U256,
|
||||
recharge_point: SteadyTime,
|
||||
recharge_point: Instant,
|
||||
}
|
||||
|
||||
impl Credits {
|
||||
@@ -53,7 +53,7 @@ impl Credits {
|
||||
/// a response to a request.
|
||||
pub fn update_to(&mut self, value: U256) {
|
||||
self.estimate = value;
|
||||
self.recharge_point = SteadyTime::now();
|
||||
self.recharge_point = Instant::now();
|
||||
}
|
||||
|
||||
/// Maintain ratio to current limit against an old limit.
|
||||
@@ -162,7 +162,7 @@ impl Encodable for CostTable {
|
||||
}
|
||||
|
||||
impl Decodable for CostTable {
|
||||
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
||||
let base = rlp.val_at(0)?;
|
||||
|
||||
let mut headers = None;
|
||||
@@ -235,23 +235,30 @@ impl FlowParams {
|
||||
|
||||
/// Create new flow parameters from ,
|
||||
/// proportion of total capacity which should be given to a peer,
|
||||
/// and number of seconds of stored capacity a peer can accumulate.
|
||||
pub fn from_request_times<F: Fn(::request::Kind) -> u64>(
|
||||
request_time_ns: F,
|
||||
/// and stored capacity a peer can accumulate.
|
||||
pub fn from_request_times<F: Fn(::request::Kind) -> Duration>(
|
||||
request_time: F,
|
||||
load_share: f64,
|
||||
max_stored_seconds: u64
|
||||
max_stored: Duration
|
||||
) -> Self {
|
||||
use request::Kind;
|
||||
|
||||
let load_share = load_share.abs();
|
||||
|
||||
let recharge: u64 = 100_000_000;
|
||||
let max = recharge.saturating_mul(max_stored_seconds);
|
||||
let max = {
|
||||
let sec = max_stored.as_secs().saturating_mul(recharge);
|
||||
let nanos = (max_stored.subsec_nanos() as u64).saturating_mul(recharge) / 1_000_000_000;
|
||||
sec + nanos
|
||||
};
|
||||
|
||||
let cost_for_kind = |kind| {
|
||||
// how many requests we can handle per second
|
||||
let ns = request_time_ns(kind);
|
||||
let second_duration = 1_000_000_000f64 / ns as f64;
|
||||
let rq_dur = request_time(kind);
|
||||
let second_duration = {
|
||||
let as_ns = rq_dur.as_secs() as f64 * 1_000_000_000f64 + rq_dur.subsec_nanos() as f64;
|
||||
1_000_000_000f64 / as_ns
|
||||
};
|
||||
|
||||
// scale by share of the load given to this peer.
|
||||
let serve_per_second = second_duration * load_share;
|
||||
@@ -351,19 +358,19 @@ impl FlowParams {
|
||||
pub fn create_credits(&self) -> Credits {
|
||||
Credits {
|
||||
estimate: self.limit,
|
||||
recharge_point: SteadyTime::now(),
|
||||
recharge_point: Instant::now(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Recharge the given credits based on time passed since last
|
||||
/// update.
|
||||
pub fn recharge(&self, credits: &mut Credits) {
|
||||
let now = SteadyTime::now();
|
||||
let now = Instant::now();
|
||||
|
||||
// recompute and update only in terms of full seconds elapsed
|
||||
// in order to keep the estimate as an underestimate.
|
||||
let elapsed = (now - credits.recharge_point).num_seconds();
|
||||
credits.recharge_point = credits.recharge_point + Duration::seconds(elapsed);
|
||||
let elapsed = (now - credits.recharge_point).as_secs();
|
||||
credits.recharge_point = credits.recharge_point + Duration::from_secs(elapsed);
|
||||
|
||||
let elapsed: U256 = elapsed.into();
|
||||
|
||||
@@ -400,7 +407,7 @@ mod tests {
|
||||
let costs = CostTable::default();
|
||||
let serialized = ::rlp::encode(&costs);
|
||||
|
||||
let new_costs: CostTable = ::rlp::decode(&*serialized);
|
||||
let new_costs: CostTable = ::rlp::decode(&*serialized).unwrap();
|
||||
|
||||
assert_eq!(costs, new_costs);
|
||||
}
|
||||
@@ -426,21 +433,21 @@ mod tests {
|
||||
#[test]
|
||||
fn scale_by_load_share_and_time() {
|
||||
let flow_params = FlowParams::from_request_times(
|
||||
|_| 10_000,
|
||||
|_| Duration::new(0, 10_000),
|
||||
0.05,
|
||||
60,
|
||||
Duration::from_secs(60),
|
||||
);
|
||||
|
||||
let flow_params2 = FlowParams::from_request_times(
|
||||
|_| 10_000,
|
||||
|_| Duration::new(0, 10_000),
|
||||
0.1,
|
||||
60,
|
||||
Duration::from_secs(60),
|
||||
);
|
||||
|
||||
let flow_params3 = FlowParams::from_request_times(
|
||||
|_| 5_000,
|
||||
|_| Duration::new(0, 5_000),
|
||||
0.05,
|
||||
60,
|
||||
Duration::from_secs(60),
|
||||
);
|
||||
|
||||
assert_eq!(flow_params2.costs, flow_params3.costs);
|
||||
|
||||
@@ -23,14 +23,13 @@
|
||||
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::iter::FromIterator;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use request::Request;
|
||||
use request::NetworkRequests as Requests;
|
||||
use net::{timeout, ReqId};
|
||||
use ethereum_types::U256;
|
||||
|
||||
use time::{Duration, SteadyTime};
|
||||
|
||||
// Request set entry: requests + cost.
|
||||
#[derive(Debug)]
|
||||
struct Entry(Requests, U256);
|
||||
@@ -40,7 +39,7 @@ struct Entry(Requests, U256);
|
||||
pub struct RequestSet {
|
||||
counter: u64,
|
||||
cumulative_cost: U256,
|
||||
base: Option<SteadyTime>,
|
||||
base: Option<Instant>,
|
||||
ids: HashMap<ReqId, u64>,
|
||||
reqs: BTreeMap<u64, Entry>,
|
||||
}
|
||||
@@ -59,7 +58,7 @@ impl Default for RequestSet {
|
||||
|
||||
impl RequestSet {
|
||||
/// Push requests onto the stack.
|
||||
pub fn insert(&mut self, req_id: ReqId, req: Requests, cost: U256, now: SteadyTime) {
|
||||
pub fn insert(&mut self, req_id: ReqId, req: Requests, cost: U256, now: Instant) {
|
||||
let counter = self.counter;
|
||||
self.cumulative_cost = self.cumulative_cost + cost;
|
||||
|
||||
@@ -74,7 +73,7 @@ impl RequestSet {
|
||||
}
|
||||
|
||||
/// Remove a set of requests from the stack.
|
||||
pub fn remove(&mut self, req_id: &ReqId, now: SteadyTime) -> Option<Requests> {
|
||||
pub fn remove(&mut self, req_id: &ReqId, now: Instant) -> Option<Requests> {
|
||||
let id = match self.ids.remove(&req_id) {
|
||||
Some(id) => id,
|
||||
None => return None,
|
||||
@@ -94,7 +93,7 @@ impl RequestSet {
|
||||
|
||||
/// Check for timeout against the given time. Returns true if
|
||||
/// has timed out, false otherwise.
|
||||
pub fn check_timeout(&self, now: SteadyTime) -> bool {
|
||||
pub fn check_timeout(&self, now: Instant) -> bool {
|
||||
let base = match self.base.as_ref().cloned() {
|
||||
Some(base) => base,
|
||||
None => return false,
|
||||
@@ -128,7 +127,7 @@ impl RequestSet {
|
||||
// helper to calculate timeout for a specific set of requests.
|
||||
// it's a base amount + some amount per request.
|
||||
fn compute_timeout(reqs: &Requests) -> Duration {
|
||||
Duration::milliseconds(reqs.requests().iter().fold(timeout::BASE, |tm, req| {
|
||||
Duration::from_millis(reqs.requests().iter().fold(timeout::BASE, |tm, req| {
|
||||
tm + match *req {
|
||||
Request::Headers(_) => timeout::HEADERS,
|
||||
Request::HeaderProof(_) => timeout::HEADER_PROOF,
|
||||
@@ -148,34 +147,34 @@ fn compute_timeout(reqs: &Requests) -> Duration {
|
||||
mod tests {
|
||||
use net::ReqId;
|
||||
use request::Builder;
|
||||
use time::{SteadyTime, Duration};
|
||||
use std::time::{Instant, Duration};
|
||||
use super::{RequestSet, compute_timeout};
|
||||
|
||||
#[test]
|
||||
fn multi_timeout() {
|
||||
let test_begin = SteadyTime::now();
|
||||
let test_begin = Instant::now();
|
||||
let mut req_set = RequestSet::default();
|
||||
|
||||
let the_req = Builder::default().build();
|
||||
let req_time = compute_timeout(&the_req);
|
||||
req_set.insert(ReqId(0), the_req.clone(), 0.into(), test_begin);
|
||||
req_set.insert(ReqId(1), the_req, 0.into(), test_begin + Duration::seconds(1));
|
||||
req_set.insert(ReqId(1), the_req, 0.into(), test_begin + Duration::from_secs(1));
|
||||
|
||||
assert_eq!(req_set.base, Some(test_begin));
|
||||
|
||||
let test_end = test_begin + req_time;
|
||||
assert!(req_set.check_timeout(test_end));
|
||||
|
||||
req_set.remove(&ReqId(0), test_begin + Duration::seconds(1)).unwrap();
|
||||
req_set.remove(&ReqId(0), test_begin + Duration::from_secs(1)).unwrap();
|
||||
assert!(!req_set.check_timeout(test_end));
|
||||
assert!(req_set.check_timeout(test_end + Duration::seconds(1)));
|
||||
assert!(req_set.check_timeout(test_end + Duration::from_secs(1)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cumulative_cost() {
|
||||
let the_req = Builder::default().build();
|
||||
let test_begin = SteadyTime::now();
|
||||
let test_end = test_begin + Duration::seconds(1);
|
||||
let test_begin = Instant::now();
|
||||
let test_end = test_begin + Duration::from_secs(1);
|
||||
let mut req_set = RequestSet::default();
|
||||
|
||||
for i in 0..5 {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
//! Peer status and capabilities.
|
||||
|
||||
use rlp::{DecoderError, Encodable, Decodable, RlpStream, UntrustedRlp};
|
||||
use rlp::{DecoderError, Encodable, Decodable, RlpStream, Rlp};
|
||||
use ethereum_types::{H256, U256};
|
||||
|
||||
use super::request_credits::FlowParams;
|
||||
@@ -85,7 +85,7 @@ impl Key {
|
||||
// helper for decoding key-value pairs in the handshake or an announcement.
|
||||
struct Parser<'a> {
|
||||
pos: usize,
|
||||
rlp: UntrustedRlp<'a>,
|
||||
rlp: Rlp<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
@@ -97,7 +97,7 @@ impl<'a> Parser<'a> {
|
||||
|
||||
// expect a specific next key, and get the value's RLP.
|
||||
// if the key isn't found, the position isn't advanced.
|
||||
fn expect_raw(&mut self, key: Key) -> Result<UntrustedRlp<'a>, DecoderError> {
|
||||
fn expect_raw(&mut self, key: Key) -> Result<Rlp<'a>, DecoderError> {
|
||||
trace!(target: "les", "Expecting key {}", key.as_str());
|
||||
let pre_pos = self.pos;
|
||||
if let Some((k, val)) = self.get_next()? {
|
||||
@@ -109,7 +109,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
// get the next key and value RLP.
|
||||
fn get_next(&mut self) -> Result<Option<(Key, UntrustedRlp<'a>)>, DecoderError> {
|
||||
fn get_next(&mut self) -> Result<Option<(Key, Rlp<'a>)>, DecoderError> {
|
||||
while self.pos < self.rlp.item_count()? {
|
||||
let pair = self.rlp.at(self.pos)?;
|
||||
let k: String = pair.val_at(0)?;
|
||||
@@ -208,7 +208,7 @@ impl Capabilities {
|
||||
/// - chain status
|
||||
/// - serving capabilities
|
||||
/// - request credit parameters
|
||||
pub fn parse_handshake(rlp: UntrustedRlp) -> Result<(Status, Capabilities, Option<FlowParams>), DecoderError> {
|
||||
pub fn parse_handshake(rlp: Rlp) -> Result<(Status, Capabilities, Option<FlowParams>), DecoderError> {
|
||||
let mut parser = Parser {
|
||||
pos: 0,
|
||||
rlp: rlp,
|
||||
@@ -304,7 +304,7 @@ pub struct Announcement {
|
||||
}
|
||||
|
||||
/// Parse an announcement.
|
||||
pub fn parse_announcement(rlp: UntrustedRlp) -> Result<Announcement, DecoderError> {
|
||||
pub fn parse_announcement(rlp: Rlp) -> Result<Announcement, DecoderError> {
|
||||
let mut last_key = None;
|
||||
|
||||
let mut announcement = Announcement {
|
||||
@@ -374,7 +374,7 @@ mod tests {
|
||||
use super::*;
|
||||
use super::super::request_credits::FlowParams;
|
||||
use ethereum_types::{U256, H256};
|
||||
use rlp::{RlpStream, UntrustedRlp};
|
||||
use rlp::{RlpStream, Rlp};
|
||||
|
||||
#[test]
|
||||
fn full_handshake() {
|
||||
@@ -404,7 +404,7 @@ mod tests {
|
||||
let handshake = write_handshake(&status, &capabilities, Some(&flow_params));
|
||||
|
||||
let (read_status, read_capabilities, read_flow)
|
||||
= parse_handshake(UntrustedRlp::new(&handshake)).unwrap();
|
||||
= parse_handshake(Rlp::new(&handshake)).unwrap();
|
||||
|
||||
assert_eq!(read_status, status);
|
||||
assert_eq!(read_capabilities, capabilities);
|
||||
@@ -439,7 +439,7 @@ mod tests {
|
||||
let handshake = write_handshake(&status, &capabilities, Some(&flow_params));
|
||||
|
||||
let (read_status, read_capabilities, read_flow)
|
||||
= parse_handshake(UntrustedRlp::new(&handshake)).unwrap();
|
||||
= parse_handshake(Rlp::new(&handshake)).unwrap();
|
||||
|
||||
assert_eq!(read_status, status);
|
||||
assert_eq!(read_capabilities, capabilities);
|
||||
@@ -473,7 +473,7 @@ mod tests {
|
||||
|
||||
let handshake = write_handshake(&status, &capabilities, Some(&flow_params));
|
||||
let interleaved = {
|
||||
let handshake = UntrustedRlp::new(&handshake);
|
||||
let handshake = Rlp::new(&handshake);
|
||||
let mut stream = RlpStream::new_list(handshake.item_count().unwrap_or(0) * 3);
|
||||
|
||||
for item in handshake.iter() {
|
||||
@@ -489,7 +489,7 @@ mod tests {
|
||||
};
|
||||
|
||||
let (read_status, read_capabilities, read_flow)
|
||||
= parse_handshake(UntrustedRlp::new(&interleaved)).unwrap();
|
||||
= parse_handshake(Rlp::new(&interleaved)).unwrap();
|
||||
|
||||
assert_eq!(read_status, status);
|
||||
assert_eq!(read_capabilities, capabilities);
|
||||
@@ -510,7 +510,7 @@ mod tests {
|
||||
};
|
||||
|
||||
let serialized = write_announcement(&announcement);
|
||||
let read = parse_announcement(UntrustedRlp::new(&serialized)).unwrap();
|
||||
let read = parse_announcement(Rlp::new(&serialized)).unwrap();
|
||||
|
||||
assert_eq!(read, announcement);
|
||||
}
|
||||
@@ -529,7 +529,7 @@ mod tests {
|
||||
.append_raw(&encode_flag(Key::ServeHeaders), 1);
|
||||
|
||||
let out = stream.drain();
|
||||
assert!(parse_announcement(UntrustedRlp::new(&out)).is_err());
|
||||
assert!(parse_announcement(Rlp::new(&out)).is_err());
|
||||
|
||||
let mut stream = RlpStream::new_list(6);
|
||||
stream
|
||||
@@ -541,7 +541,7 @@ mod tests {
|
||||
.append_raw(&encode_pair(Key::ServeStateSince, &44u64), 1);
|
||||
|
||||
let out = stream.drain();
|
||||
assert!(parse_announcement(UntrustedRlp::new(&out)).is_ok());
|
||||
assert!(parse_announcement(Rlp::new(&out)).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -566,7 +566,7 @@ mod tests {
|
||||
let handshake = write_handshake(&status, &capabilities, None);
|
||||
|
||||
let (read_status, read_capabilities, read_flow)
|
||||
= parse_handshake(UntrustedRlp::new(&handshake)).unwrap();
|
||||
= parse_handshake(Rlp::new(&handshake)).unwrap();
|
||||
|
||||
assert_eq!(read_status, status);
|
||||
assert_eq!(read_capabilities, capabilities);
|
||||
|
||||
@@ -31,10 +31,11 @@ use provider::Provider;
|
||||
use request;
|
||||
use request::*;
|
||||
|
||||
use rlp::*;
|
||||
use rlp::{Rlp, RlpStream};
|
||||
use ethereum_types::{H256, U256, Address};
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
|
||||
// helper for encoding a single request into a packet.
|
||||
// panics on bad backreference.
|
||||
@@ -172,8 +173,8 @@ impl Provider for TestProvider {
|
||||
})
|
||||
}
|
||||
|
||||
fn ready_transactions(&self) -> Vec<PendingTransaction> {
|
||||
self.0.client.ready_transactions()
|
||||
fn transactions_to_propagate(&self) -> Vec<PendingTransaction> {
|
||||
self.0.client.transactions_to_propagate()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,7 +405,7 @@ fn get_block_receipts() {
|
||||
// by the test client in that case.
|
||||
let block_hashes: Vec<H256> = (0..1000)
|
||||
.map(|i| provider.client.block_header(BlockId::Number(i)).unwrap().hash())
|
||||
.filter(|hash| format!("{}", hash).starts_with("f"))
|
||||
.filter(|hash| format!("{}", hash).starts_with("0xf"))
|
||||
.take(10)
|
||||
.collect();
|
||||
|
||||
@@ -661,8 +662,8 @@ fn id_guard() {
|
||||
|
||||
let mut pending_requests = RequestSet::default();
|
||||
|
||||
pending_requests.insert(req_id_1, req.clone(), 0.into(), ::time::SteadyTime::now());
|
||||
pending_requests.insert(req_id_2, req, 1.into(), ::time::SteadyTime::now());
|
||||
pending_requests.insert(req_id_1, req.clone(), 0.into(), Instant::now());
|
||||
pending_requests.insert(req_id_2, req, 1.into(), Instant::now());
|
||||
|
||||
proto.peers.write().insert(peer_id, ::parking_lot::Mutex::new(Peer {
|
||||
local_credits: flow_params.create_credits(),
|
||||
@@ -670,7 +671,7 @@ fn id_guard() {
|
||||
capabilities: capabilities.clone(),
|
||||
remote_flow: Some((flow_params.create_credits(), (&*flow_params).clone())),
|
||||
sent_head: provider.client.chain_info().best_block_hash,
|
||||
last_update: ::time::SteadyTime::now(),
|
||||
last_update: Instant::now(),
|
||||
pending_requests: pending_requests,
|
||||
failed_requests: Vec::new(),
|
||||
propagated_transactions: Default::default(),
|
||||
@@ -687,7 +688,7 @@ fn id_guard() {
|
||||
stream.begin_list(2).append(&125usize).append(&3usize);
|
||||
|
||||
let packet = stream.out();
|
||||
assert!(proto.response(&peer_id, &Expect::Nothing, UntrustedRlp::new(&packet)).is_err());
|
||||
assert!(proto.response(&peer_id, &Expect::Nothing, Rlp::new(&packet)).is_err());
|
||||
}
|
||||
|
||||
// next, do an unexpected response.
|
||||
@@ -698,7 +699,7 @@ fn id_guard() {
|
||||
stream.begin_list(0);
|
||||
|
||||
let packet = stream.out();
|
||||
assert!(proto.response(&peer_id, &Expect::Nothing, UntrustedRlp::new(&packet)).is_err());
|
||||
assert!(proto.response(&peer_id, &Expect::Nothing, Rlp::new(&packet)).is_err());
|
||||
}
|
||||
|
||||
// lastly, do a valid (but empty) response.
|
||||
@@ -709,7 +710,7 @@ fn id_guard() {
|
||||
stream.begin_list(0);
|
||||
|
||||
let packet = stream.out();
|
||||
assert!(proto.response(&peer_id, &Expect::Nothing, UntrustedRlp::new(&packet)).is_ok());
|
||||
assert!(proto.response(&peer_id, &Expect::Nothing, Rlp::new(&packet)).is_ok());
|
||||
}
|
||||
|
||||
let peers = proto.peers.read();
|
||||
|
||||
@@ -204,6 +204,8 @@ fn guess_capabilities(requests: &[CheckedRequest]) -> Capabilities {
|
||||
caps.serve_headers = true,
|
||||
CheckedRequest::HeaderByHash(_, _) =>
|
||||
caps.serve_headers = true,
|
||||
CheckedRequest::HeaderWithAncestors(_, _) =>
|
||||
caps.serve_headers = true,
|
||||
CheckedRequest::TransactionIndex(_, _) => {} // hashes yield no info.
|
||||
CheckedRequest::Signal(_, _) =>
|
||||
caps.serve_headers = true,
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
//! Request types, verification, and verification errors.
|
||||
|
||||
use std::cmp;
|
||||
use std::sync::Arc;
|
||||
|
||||
use ethcore::basic_account::BasicAccount;
|
||||
@@ -30,7 +31,7 @@ use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY, KECCAK_EMPTY_LIST_RLP, keccak};
|
||||
|
||||
use request::{self as net_request, IncompleteRequest, CompleteRequest, Output, OutputKind, Field};
|
||||
|
||||
use rlp::{RlpStream, UntrustedRlp};
|
||||
use rlp::{RlpStream, Rlp};
|
||||
use ethereum_types::{H256, U256, Address};
|
||||
use parking_lot::Mutex;
|
||||
use hashdb::HashDB;
|
||||
@@ -48,6 +49,8 @@ pub enum Request {
|
||||
HeaderProof(HeaderProof),
|
||||
/// A request for a header by hash.
|
||||
HeaderByHash(HeaderByHash),
|
||||
/// A request for a header by hash with a range of its ancestors.
|
||||
HeaderWithAncestors(HeaderWithAncestors),
|
||||
/// A request for the index of a transaction.
|
||||
TransactionIndex(TransactionIndex),
|
||||
/// A request for block receipts.
|
||||
@@ -137,6 +140,7 @@ macro_rules! impl_single {
|
||||
// implement traits for each kind of request.
|
||||
impl_single!(HeaderProof, HeaderProof, (H256, U256));
|
||||
impl_single!(HeaderByHash, HeaderByHash, encoded::Header);
|
||||
impl_single!(HeaderWithAncestors, HeaderWithAncestors, Vec<encoded::Header>);
|
||||
impl_single!(TransactionIndex, TransactionIndex, net_request::TransactionIndexResponse);
|
||||
impl_single!(Receipts, BlockReceipts, Vec<Receipt>);
|
||||
impl_single!(Body, Body, encoded::Block);
|
||||
@@ -247,6 +251,7 @@ impl From<encoded::Header> for HeaderRef {
|
||||
pub enum CheckedRequest {
|
||||
HeaderProof(HeaderProof, net_request::IncompleteHeaderProofRequest),
|
||||
HeaderByHash(HeaderByHash, net_request::IncompleteHeadersRequest),
|
||||
HeaderWithAncestors(HeaderWithAncestors, net_request::IncompleteHeadersRequest),
|
||||
TransactionIndex(TransactionIndex, net_request::IncompleteTransactionIndexRequest),
|
||||
Receipts(BlockReceipts, net_request::IncompleteReceiptsRequest),
|
||||
Body(Body, net_request::IncompleteBodyRequest),
|
||||
@@ -268,6 +273,16 @@ impl From<Request> for CheckedRequest {
|
||||
};
|
||||
CheckedRequest::HeaderByHash(req, net_req)
|
||||
}
|
||||
Request::HeaderWithAncestors(req) => {
|
||||
let net_req = net_request::IncompleteHeadersRequest {
|
||||
start: req.block_hash.map(Into::into),
|
||||
skip: 0,
|
||||
max: req.ancestor_count + 1,
|
||||
reverse: true,
|
||||
};
|
||||
trace!(target: "on_demand", "HeaderWithAncestors Request, {:?}", net_req);
|
||||
CheckedRequest::HeaderWithAncestors(req, net_req)
|
||||
}
|
||||
Request::HeaderProof(req) => {
|
||||
let net_req = net_request::IncompleteHeaderProofRequest {
|
||||
num: req.num().into(),
|
||||
@@ -336,6 +351,7 @@ impl CheckedRequest {
|
||||
match self {
|
||||
CheckedRequest::HeaderProof(_, req) => NetRequest::HeaderProof(req),
|
||||
CheckedRequest::HeaderByHash(_, req) => NetRequest::Headers(req),
|
||||
CheckedRequest::HeaderWithAncestors(_, req) => NetRequest::Headers(req),
|
||||
CheckedRequest::TransactionIndex(_, req) => NetRequest::TransactionIndex(req),
|
||||
CheckedRequest::Receipts(_, req) => NetRequest::Receipts(req),
|
||||
CheckedRequest::Body(_, req) => NetRequest::Body(req),
|
||||
@@ -391,6 +407,27 @@ impl CheckedRequest {
|
||||
|
||||
None
|
||||
}
|
||||
CheckedRequest::HeaderWithAncestors(_, ref req) => {
|
||||
if req.skip != 1 || !req.reverse {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(&net_request::HashOrNumber::Hash(start)) = req.start.as_ref() {
|
||||
let mut result = Vec::with_capacity(req.max as usize);
|
||||
let mut hash = start;
|
||||
let mut cache = cache.lock();
|
||||
for _ in 0..req.max {
|
||||
match cache.block_header(&hash) {
|
||||
Some(header) => {
|
||||
hash = header.parent_hash();
|
||||
result.push(header);
|
||||
}
|
||||
None => return None,
|
||||
}
|
||||
}
|
||||
Some(Response::HeaderWithAncestors(result))
|
||||
} else { None }
|
||||
}
|
||||
CheckedRequest::Receipts(ref check, ref req) => {
|
||||
// empty transactions -> no receipts
|
||||
if check.0.as_ref().ok().map_or(false, |hdr| hdr.receipts_root() == KECCAK_NULL_RLP) {
|
||||
@@ -439,13 +476,7 @@ impl CheckedRequest {
|
||||
block_header
|
||||
.and_then(|hdr| cache.block_body(&block_hash).map(|b| (hdr, b)))
|
||||
.map(|(hdr, body)| {
|
||||
let mut stream = RlpStream::new_list(3);
|
||||
let body = body.rlp();
|
||||
stream.append_raw(&hdr.rlp().as_raw(), 1);
|
||||
stream.append_raw(&body.at(0).as_raw(), 1);
|
||||
stream.append_raw(&body.at(1).as_raw(), 1);
|
||||
|
||||
Response::Body(encoded::Block::new(stream.out()))
|
||||
Response::Body(encoded::Block::new_from_header_and_body(&hdr.view(), &body.view()))
|
||||
})
|
||||
}
|
||||
CheckedRequest::Code(_, ref req) => {
|
||||
@@ -465,6 +496,7 @@ macro_rules! match_me {
|
||||
match $me {
|
||||
CheckedRequest::HeaderProof($check, $req) => $e,
|
||||
CheckedRequest::HeaderByHash($check, $req) => $e,
|
||||
CheckedRequest::HeaderWithAncestors($check, $req) => $e,
|
||||
CheckedRequest::TransactionIndex($check, $req) => $e,
|
||||
CheckedRequest::Receipts($check, $req) => $e,
|
||||
CheckedRequest::Body($check, $req) => $e,
|
||||
@@ -494,6 +526,15 @@ impl IncompleteRequest for CheckedRequest {
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
CheckedRequest::HeaderWithAncestors(ref check, ref req) => {
|
||||
req.check_outputs(&mut f)?;
|
||||
|
||||
// make sure the output given is definitively a hash.
|
||||
match check.block_hash {
|
||||
Field::BackReference(r, idx) => f(r, idx, OutputKind::Hash),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
CheckedRequest::TransactionIndex(_, ref req) => req.check_outputs(f),
|
||||
CheckedRequest::Receipts(_, ref req) => req.check_outputs(f),
|
||||
CheckedRequest::Body(_, ref req) => req.check_outputs(f),
|
||||
@@ -514,15 +555,46 @@ impl IncompleteRequest for CheckedRequest {
|
||||
|
||||
fn complete(self) -> Result<Self::Complete, net_request::NoSuchOutput> {
|
||||
match self {
|
||||
CheckedRequest::HeaderProof(_, req) => req.complete().map(CompleteRequest::HeaderProof),
|
||||
CheckedRequest::HeaderByHash(_, req) => req.complete().map(CompleteRequest::Headers),
|
||||
CheckedRequest::TransactionIndex(_, req) => req.complete().map(CompleteRequest::TransactionIndex),
|
||||
CheckedRequest::Receipts(_, req) => req.complete().map(CompleteRequest::Receipts),
|
||||
CheckedRequest::Body(_, req) => req.complete().map(CompleteRequest::Body),
|
||||
CheckedRequest::Account(_, req) => req.complete().map(CompleteRequest::Account),
|
||||
CheckedRequest::Code(_, req) => req.complete().map(CompleteRequest::Code),
|
||||
CheckedRequest::Execution(_, req) => req.complete().map(CompleteRequest::Execution),
|
||||
CheckedRequest::Signal(_, req) => req.complete().map(CompleteRequest::Signal),
|
||||
CheckedRequest::HeaderProof(_, req) => {
|
||||
trace!(target: "on_demand", "HeaderProof request completed {:?}", req);
|
||||
req.complete().map(CompleteRequest::HeaderProof)
|
||||
}
|
||||
CheckedRequest::HeaderByHash(_, req) => {
|
||||
trace!(target: "on_demand", "HeaderByHash request completed {:?}", req);
|
||||
req.complete().map(CompleteRequest::Headers)
|
||||
}
|
||||
CheckedRequest::HeaderWithAncestors(_, req) => {
|
||||
trace!(target: "on_demand", "HeaderWithAncestors request completed {:?}", req);
|
||||
req.complete().map(CompleteRequest::Headers)
|
||||
}
|
||||
CheckedRequest::TransactionIndex(_, req) => {
|
||||
trace!(target: "on_demand", "TransactionIndex request completed {:?}", req);
|
||||
req.complete().map(CompleteRequest::TransactionIndex)
|
||||
}
|
||||
CheckedRequest::Receipts(_, req) => {
|
||||
trace!(target: "on_demand", "Receipt request completed {:?}", req);
|
||||
req.complete().map(CompleteRequest::Receipts)
|
||||
}
|
||||
CheckedRequest::Body(_, req) => {
|
||||
trace!(target: "on_demand", "Block request completed {:?}", req);
|
||||
req.complete().map(CompleteRequest::Body)
|
||||
}
|
||||
CheckedRequest::Account(_, req) => {
|
||||
trace!(target: "on_demand", "Account request completed {:?}", req);
|
||||
req.complete().map(CompleteRequest::Account)
|
||||
}
|
||||
CheckedRequest::Code(_, req) => {
|
||||
trace!(target: "on_demand", "Code request completed {:?}", req);
|
||||
req.complete().map(CompleteRequest::Code)
|
||||
}
|
||||
CheckedRequest::Execution(_, req) => {
|
||||
trace!(target: "on_demand", "Execution request completed {:?}", req);
|
||||
req.complete().map(CompleteRequest::Execution)
|
||||
}
|
||||
CheckedRequest::Signal(_, req) => {
|
||||
trace!(target: "on_demand", "Signal request completed {:?}", req);
|
||||
req.complete().map(CompleteRequest::Signal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -559,6 +631,9 @@ impl net_request::CheckedRequest for CheckedRequest {
|
||||
CheckedRequest::HeaderByHash(ref prover, _) =>
|
||||
expect!((&NetResponse::Headers(ref res), &CompleteRequest::Headers(ref req)) =>
|
||||
prover.check_response(cache, &req.start, &res.headers).map(Response::HeaderByHash)),
|
||||
CheckedRequest::HeaderWithAncestors(ref prover, _) =>
|
||||
expect!((&NetResponse::Headers(ref res), &CompleteRequest::Headers(ref req)) =>
|
||||
prover.check_response(cache, &req.start, &res.headers).map(Response::HeaderWithAncestors)),
|
||||
CheckedRequest::TransactionIndex(ref prover, _) =>
|
||||
expect!((&NetResponse::TransactionIndex(ref res), _) =>
|
||||
prover.check_response(cache, res).map(Response::TransactionIndex)),
|
||||
@@ -592,6 +667,8 @@ pub enum Response {
|
||||
HeaderProof((H256, U256)),
|
||||
/// Response to a header-by-hash request.
|
||||
HeaderByHash(encoded::Header),
|
||||
/// Response to a header-by-hash with ancestors request.
|
||||
HeaderWithAncestors(Vec<encoded::Header>),
|
||||
/// Response to a transaction-index request.
|
||||
TransactionIndex(net_request::TransactionIndexResponse),
|
||||
/// Response to a receipts request.
|
||||
@@ -633,6 +710,10 @@ pub enum Error {
|
||||
Decoder(::rlp::DecoderError),
|
||||
/// Empty response.
|
||||
Empty,
|
||||
/// Response data length exceeds request max.
|
||||
TooManyResults(u64, u64),
|
||||
/// Response data is incomplete.
|
||||
TooFewResults(u64, u64),
|
||||
/// Trie lookup error (result of bad proof)
|
||||
Trie(TrieError),
|
||||
/// Bad inclusion proof
|
||||
@@ -649,6 +730,8 @@ pub enum Error {
|
||||
WrongTrieRoot(H256, H256),
|
||||
/// Wrong response kind.
|
||||
WrongKind,
|
||||
/// Wrong sequence of headers.
|
||||
WrongHeaderSequence,
|
||||
}
|
||||
|
||||
impl From<::rlp::DecoderError> for Error {
|
||||
@@ -709,6 +792,65 @@ impl HeaderProof {
|
||||
}
|
||||
}
|
||||
|
||||
/// Request for a header by hash with a range of ancestors.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct HeaderWithAncestors {
|
||||
/// Hash of the last block in the range to fetch.
|
||||
pub block_hash: Field<H256>,
|
||||
/// Number of headers before the last block to fetch in addition.
|
||||
pub ancestor_count: u64,
|
||||
}
|
||||
|
||||
impl HeaderWithAncestors {
|
||||
/// Check a response for the headers.
|
||||
pub fn check_response(
|
||||
&self,
|
||||
cache: &Mutex<::cache::Cache>,
|
||||
start: &net_request::HashOrNumber,
|
||||
headers: &[encoded::Header]
|
||||
) -> Result<Vec<encoded::Header>, Error> {
|
||||
let expected_hash = match (self.block_hash, start) {
|
||||
(Field::Scalar(ref h), &net_request::HashOrNumber::Hash(ref h2)) => {
|
||||
if h != h2 { return Err(Error::WrongHash(*h, *h2)) }
|
||||
*h
|
||||
}
|
||||
(_, &net_request::HashOrNumber::Hash(h2)) => h2,
|
||||
_ => return Err(Error::HeaderByNumber),
|
||||
};
|
||||
|
||||
let start_header = headers.first().ok_or(Error::Empty)?;
|
||||
let start_hash = start_header.hash();
|
||||
if start_hash != expected_hash {
|
||||
return Err(Error::WrongHash(expected_hash, start_hash));
|
||||
}
|
||||
|
||||
let expected_len = 1 + cmp::min(self.ancestor_count, start_header.number());
|
||||
let actual_len = headers.len() as u64;
|
||||
match actual_len.cmp(&expected_len) {
|
||||
cmp::Ordering::Less =>
|
||||
return Err(Error::TooFewResults(expected_len, actual_len)),
|
||||
cmp::Ordering::Greater =>
|
||||
return Err(Error::TooManyResults(expected_len, actual_len)),
|
||||
cmp::Ordering::Equal => (),
|
||||
};
|
||||
|
||||
for (header, prev_header) in headers.iter().zip(headers[1..].iter()) {
|
||||
if header.number() != prev_header.number() + 1 ||
|
||||
header.parent_hash() != prev_header.hash()
|
||||
{
|
||||
return Err(Error::WrongHeaderSequence)
|
||||
}
|
||||
}
|
||||
|
||||
let mut cache = cache.lock();
|
||||
for header in headers {
|
||||
cache.insert_block_header(header.hash(), header.clone());
|
||||
}
|
||||
|
||||
Ok(headers.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
/// Request for a header by hash.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct HeaderByHash(pub Field<H256>);
|
||||
@@ -778,25 +920,22 @@ impl Body {
|
||||
pub fn check_response(&self, cache: &Mutex<::cache::Cache>, body: &encoded::Body) -> Result<encoded::Block, Error> {
|
||||
// check the integrity of the the body against the header
|
||||
let header = self.0.as_ref()?;
|
||||
let tx_root = ::triehash::ordered_trie_root(body.rlp().at(0).iter().map(|r| r.as_raw()));
|
||||
let tx_root = ::triehash::ordered_trie_root(body.transactions_rlp().iter().map(|r| r.as_raw()));
|
||||
if tx_root != header.transactions_root() {
|
||||
return Err(Error::WrongTrieRoot(header.transactions_root(), tx_root));
|
||||
}
|
||||
|
||||
let uncles_hash = keccak(body.rlp().at(1).as_raw());
|
||||
let uncles_hash = keccak(body.uncles_rlp().as_raw());
|
||||
if uncles_hash != header.uncles_hash() {
|
||||
return Err(Error::WrongHash(header.uncles_hash(), uncles_hash));
|
||||
}
|
||||
|
||||
// concatenate the header and the body.
|
||||
let mut stream = RlpStream::new_list(3);
|
||||
stream.append_raw(header.rlp().as_raw(), 1);
|
||||
stream.append_raw(body.rlp().at(0).as_raw(), 1);
|
||||
stream.append_raw(body.rlp().at(1).as_raw(), 1);
|
||||
let block = encoded::Block::new_from_header_and_body(&header.view(), &body.view());
|
||||
|
||||
cache.lock().insert_block_body(header.hash(), body.clone());
|
||||
|
||||
Ok(encoded::Block::new(stream.out()))
|
||||
Ok(block)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -840,7 +979,7 @@ impl Account {
|
||||
|
||||
match TrieDB::new(&db, &state_root).and_then(|t| t.get(&keccak(&self.address)))? {
|
||||
Some(val) => {
|
||||
let rlp = UntrustedRlp::new(&val);
|
||||
let rlp = Rlp::new(&val);
|
||||
Ok(Some(BasicAccount {
|
||||
nonce: rlp.val_at(0)?,
|
||||
balance: rlp.val_at(1)?,
|
||||
@@ -941,6 +1080,7 @@ impl Signal {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::time::Duration;
|
||||
use ethereum_types::{H256, Address};
|
||||
use memorydb::MemoryDB;
|
||||
use parking_lot::Mutex;
|
||||
@@ -948,13 +1088,13 @@ mod tests {
|
||||
use trie::recorder::Recorder;
|
||||
use hash::keccak;
|
||||
|
||||
use ethcore::client::{BlockChainClient, TestBlockChainClient, EachBlockWith};
|
||||
use ethcore::client::{BlockChainClient, BlockInfo, TestBlockChainClient, EachBlockWith};
|
||||
use ethcore::header::Header;
|
||||
use ethcore::encoded;
|
||||
use ethcore::receipt::{Receipt, TransactionOutcome};
|
||||
|
||||
fn make_cache() -> ::cache::Cache {
|
||||
::cache::Cache::new(Default::default(), ::time::Duration::seconds(1))
|
||||
::cache::Cache::new(Default::default(), Duration::from_secs(1))
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1002,6 +1142,83 @@ mod tests {
|
||||
assert!(HeaderByHash(hash.into()).check_response(&cache, &hash.into(), &[raw_header]).is_ok())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_header_with_ancestors() {
|
||||
let mut last_header_hash = H256::default();
|
||||
let mut headers = (0..11).map(|num| {
|
||||
let mut header = Header::new();
|
||||
header.set_number(num);
|
||||
header.set_parent_hash(last_header_hash);
|
||||
|
||||
last_header_hash = header.hash();
|
||||
header
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
headers.reverse(); // because responses are in reverse order
|
||||
|
||||
let raw_headers = headers.iter()
|
||||
.map(|hdr| encoded::Header::new(::rlp::encode(hdr).into_vec()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut invalid_successor = Header::new();
|
||||
invalid_successor.set_number(11);
|
||||
invalid_successor.set_parent_hash(headers[1].hash());
|
||||
|
||||
let raw_invalid_successor = encoded::Header::new(::rlp::encode(&invalid_successor).into_vec());
|
||||
|
||||
let cache = Mutex::new(make_cache());
|
||||
|
||||
let header_with_ancestors = |hash, count| {
|
||||
HeaderWithAncestors {
|
||||
block_hash: hash,
|
||||
ancestor_count: count
|
||||
}
|
||||
};
|
||||
|
||||
// Correct responses
|
||||
assert!(header_with_ancestors(headers[0].hash().into(), 0)
|
||||
.check_response(&cache, &headers[0].hash().into(), &raw_headers[0..1]).is_ok());
|
||||
assert!(header_with_ancestors(headers[0].hash().into(), 2)
|
||||
.check_response(&cache, &headers[0].hash().into(), &raw_headers[0..3]).is_ok());
|
||||
assert!(header_with_ancestors(headers[0].hash().into(), 10)
|
||||
.check_response(&cache, &headers[0].hash().into(), &raw_headers[0..11]).is_ok());
|
||||
assert!(header_with_ancestors(headers[2].hash().into(), 2)
|
||||
.check_response(&cache, &headers[2].hash().into(), &raw_headers[2..5]).is_ok());
|
||||
assert!(header_with_ancestors(headers[2].hash().into(), 10)
|
||||
.check_response(&cache, &headers[2].hash().into(), &raw_headers[2..11]).is_ok());
|
||||
assert!(header_with_ancestors(invalid_successor.hash().into(), 0)
|
||||
.check_response(&cache, &invalid_successor.hash().into(), &[raw_invalid_successor.clone()]).is_ok());
|
||||
|
||||
// Incorrect responses
|
||||
assert_eq!(header_with_ancestors(invalid_successor.hash().into(), 0)
|
||||
.check_response(&cache, &headers[0].hash().into(), &raw_headers[0..1]),
|
||||
Err(Error::WrongHash(invalid_successor.hash(), headers[0].hash())));
|
||||
assert_eq!(header_with_ancestors(headers[0].hash().into(), 0)
|
||||
.check_response(&cache, &headers[0].hash().into(), &[]),
|
||||
Err(Error::Empty));
|
||||
assert_eq!(header_with_ancestors(headers[0].hash().into(), 10)
|
||||
.check_response(&cache, &headers[0].hash().into(), &raw_headers[0..10]),
|
||||
Err(Error::TooFewResults(11, 10)));
|
||||
assert_eq!(header_with_ancestors(headers[0].hash().into(), 9)
|
||||
.check_response(&cache, &headers[0].hash().into(), &raw_headers[0..11]),
|
||||
Err(Error::TooManyResults(10, 11)));
|
||||
|
||||
let response = &[raw_headers[0].clone(), raw_headers[2].clone()];
|
||||
assert_eq!(header_with_ancestors(headers[0].hash().into(), 1)
|
||||
.check_response(&cache, &headers[0].hash().into(), response),
|
||||
Err(Error::WrongHeaderSequence));
|
||||
|
||||
let response = &[raw_invalid_successor.clone(), raw_headers[0].clone()];
|
||||
assert_eq!(header_with_ancestors(invalid_successor.hash().into(), 1)
|
||||
.check_response(&cache, &invalid_successor.hash().into(), response),
|
||||
Err(Error::WrongHeaderSequence));
|
||||
|
||||
let response = &[raw_invalid_successor.clone(), raw_headers[1].clone()];
|
||||
assert_eq!(header_with_ancestors(invalid_successor.hash().into(), 1)
|
||||
.check_response(&cache, &invalid_successor.hash().into(), response),
|
||||
Err(Error::WrongHeaderSequence));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_body() {
|
||||
use rlp::RlpStream;
|
||||
|
||||
@@ -17,14 +17,13 @@
|
||||
//! Tests for the on-demand service.
|
||||
|
||||
use cache::Cache;
|
||||
use ethcore::encoded;
|
||||
use ethcore::header::{Header, Seal};
|
||||
use ethcore::header::Header;
|
||||
use futures::Future;
|
||||
use network::{PeerId, NodeId};
|
||||
use net::*;
|
||||
use ethereum_types::H256;
|
||||
use parking_lot::Mutex;
|
||||
use time::Duration;
|
||||
use std::time::Duration;
|
||||
use ::request::{self as basic_request, Response};
|
||||
|
||||
use std::sync::Arc;
|
||||
@@ -88,7 +87,7 @@ struct Harness {
|
||||
|
||||
impl Harness {
|
||||
fn create() -> Self {
|
||||
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::minutes(1))));
|
||||
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::from_secs(60))));
|
||||
Harness {
|
||||
service: OnDemand::new_test(cache),
|
||||
}
|
||||
@@ -148,7 +147,7 @@ fn single_request() {
|
||||
});
|
||||
|
||||
let header = Header::default();
|
||||
let encoded = encoded::Header::new(header.rlp(Seal::With));
|
||||
let encoded = header.encoded();
|
||||
|
||||
let recv = harness.service.request_raw(
|
||||
&Context::NoOp,
|
||||
@@ -209,7 +208,7 @@ fn reassign() {
|
||||
});
|
||||
|
||||
let header = Header::default();
|
||||
let encoded = encoded::Header::new(header.rlp(Seal::With));
|
||||
let encoded = header.encoded();
|
||||
|
||||
let recv = harness.service.request_raw(
|
||||
&Context::NoOp,
|
||||
@@ -257,7 +256,7 @@ fn partial_response() {
|
||||
let mut hdr = Header::default();
|
||||
hdr.set_number(num);
|
||||
|
||||
let encoded = encoded::Header::new(hdr.rlp(Seal::With));
|
||||
let encoded = hdr.encoded();
|
||||
(hdr, encoded)
|
||||
};
|
||||
|
||||
@@ -316,7 +315,7 @@ fn part_bad_part_good() {
|
||||
let mut hdr = Header::default();
|
||||
hdr.set_number(num);
|
||||
|
||||
let encoded = encoded::Header::new(hdr.rlp(Seal::With));
|
||||
let encoded = hdr.encoded();
|
||||
(hdr, encoded)
|
||||
};
|
||||
|
||||
@@ -413,7 +412,7 @@ fn back_references() {
|
||||
});
|
||||
|
||||
let header = Header::default();
|
||||
let encoded = encoded::Header::new(header.rlp(Seal::With));
|
||||
let encoded = header.encoded();
|
||||
|
||||
let recv = harness.service.request_raw(
|
||||
&Context::NoOp,
|
||||
@@ -470,7 +469,7 @@ fn fill_from_cache() {
|
||||
});
|
||||
|
||||
let header = Header::default();
|
||||
let encoded = encoded::Header::new(header.rlp(Seal::With));
|
||||
let encoded = header.encoded();
|
||||
|
||||
let recv = harness.service.request_raw(
|
||||
&Context::NoOp,
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use ethcore::blockchain_info::BlockChainInfo;
|
||||
use ethcore::client::{BlockChainClient, ProvingBlockChainClient};
|
||||
use ethcore::encoded;
|
||||
use ethcore::client::{BlockChainClient, ProvingBlockChainClient, ChainInfo, BlockInfo as ClientBlockInfo};
|
||||
use ethcore::ids::BlockId;
|
||||
use ethcore::encoded;
|
||||
use ethereum_types::H256;
|
||||
use parking_lot::RwLock;
|
||||
use transaction::PendingTransaction;
|
||||
@@ -33,6 +33,9 @@ use transaction_queue::TransactionQueue;
|
||||
|
||||
use request;
|
||||
|
||||
/// Maximum allowed size of a headers request.
|
||||
pub const MAX_HEADERS_PER_REQUEST: u64 = 512;
|
||||
|
||||
/// Defines the operations that a provider for the light subprotocol must fulfill.
|
||||
pub trait Provider: Send + Sync {
|
||||
/// Provide current blockchain info.
|
||||
@@ -54,7 +57,6 @@ pub trait Provider: Send + Sync {
|
||||
/// results within must adhere to the `skip` and `reverse` parameters.
|
||||
fn block_headers(&self, req: request::CompleteHeadersRequest) -> Option<request::HeadersResponse> {
|
||||
use request::HashOrNumber;
|
||||
const MAX_HEADERS_TO_SEND: u64 = 512;
|
||||
|
||||
if req.max == 0 { return None }
|
||||
|
||||
@@ -83,7 +85,7 @@ pub trait Provider: Send + Sync {
|
||||
}
|
||||
};
|
||||
|
||||
let max = ::std::cmp::min(MAX_HEADERS_TO_SEND, req.max);
|
||||
let max = ::std::cmp::min(MAX_HEADERS_PER_REQUEST, req.max);
|
||||
|
||||
let headers: Vec<_> = (0u64..max)
|
||||
.map(|x: u64| x.saturating_mul(req.skip.saturating_add(1)))
|
||||
@@ -128,7 +130,7 @@ pub trait Provider: Send + Sync {
|
||||
fn header_proof(&self, req: request::CompleteHeaderProofRequest) -> Option<request::HeaderProofResponse>;
|
||||
|
||||
/// Provide pending transactions.
|
||||
fn ready_transactions(&self) -> Vec<PendingTransaction>;
|
||||
fn transactions_to_propagate(&self) -> Vec<PendingTransaction>;
|
||||
|
||||
/// Provide a proof-of-execution for the given transaction proof request.
|
||||
/// Returns a vector of all state items necessary to execute the transaction.
|
||||
@@ -141,7 +143,7 @@ pub trait Provider: Send + Sync {
|
||||
// Implementation of a light client data provider for a client.
|
||||
impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
|
||||
fn chain_info(&self) -> BlockChainInfo {
|
||||
BlockChainClient::chain_info(self)
|
||||
ChainInfo::chain_info(self)
|
||||
}
|
||||
|
||||
fn reorg_depth(&self, a: &H256, b: &H256) -> Option<u64> {
|
||||
@@ -153,7 +155,7 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
|
||||
}
|
||||
|
||||
fn block_header(&self, id: BlockId) -> Option<encoded::Header> {
|
||||
BlockChainClient::block_header(self, id)
|
||||
ClientBlockInfo::block_header(self, id)
|
||||
}
|
||||
|
||||
fn transaction_index(&self, req: request::CompleteTransactionIndexRequest)
|
||||
@@ -283,8 +285,11 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
|
||||
.map(|(_, proof)| ::request::ExecutionResponse { items: proof })
|
||||
}
|
||||
|
||||
fn ready_transactions(&self) -> Vec<PendingTransaction> {
|
||||
BlockChainClient::ready_transactions(self)
|
||||
fn transactions_to_propagate(&self) -> Vec<PendingTransaction> {
|
||||
BlockChainClient::transactions_to_propagate(self)
|
||||
.into_iter()
|
||||
.map(|tx| tx.pending().clone())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn epoch_signal(&self, req: request::CompleteSignalRequest) -> Option<request::SignalResponse> {
|
||||
@@ -367,9 +372,10 @@ impl<L: AsLightClient + Send + Sync> Provider for LightProvider<L> {
|
||||
None
|
||||
}
|
||||
|
||||
fn ready_transactions(&self) -> Vec<PendingTransaction> {
|
||||
fn transactions_to_propagate(&self) -> Vec<PendingTransaction> {
|
||||
let chain_info = self.chain_info();
|
||||
self.txqueue.read().ready_transactions(chain_info.best_block_number, chain_info.best_block_timestamp)
|
||||
self.txqueue.read()
|
||||
.ready_transactions(chain_info.best_block_number, chain_info.best_block_timestamp)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -120,6 +120,18 @@ impl AccountTransactions {
|
||||
}
|
||||
}
|
||||
|
||||
/// Transaction import result.
|
||||
pub enum ImportDestination {
|
||||
/// Transaction has been imported to the current queue.
|
||||
///
|
||||
/// It's going to be propagated to peers.
|
||||
Current,
|
||||
/// Transaction has been imported to future queue.
|
||||
///
|
||||
/// It means it won't be propagated until the gap is filled.
|
||||
Future,
|
||||
}
|
||||
|
||||
type Listener = Box<Fn(&[H256]) + Send + Sync>;
|
||||
|
||||
/// Light transaction queue. See module docs for more details.
|
||||
@@ -142,7 +154,7 @@ impl fmt::Debug for TransactionQueue {
|
||||
|
||||
impl TransactionQueue {
|
||||
/// Import a pending transaction to be queued.
|
||||
pub fn import(&mut self, tx: PendingTransaction) -> Result<transaction::ImportResult, transaction::Error> {
|
||||
pub fn import(&mut self, tx: PendingTransaction) -> Result<ImportDestination, transaction::Error> {
|
||||
let sender = tx.sender();
|
||||
let hash = tx.hash();
|
||||
let nonce = tx.nonce;
|
||||
@@ -158,7 +170,7 @@ impl TransactionQueue {
|
||||
future: BTreeMap::new(),
|
||||
});
|
||||
|
||||
(transaction::ImportResult::Current, vec![hash])
|
||||
(ImportDestination::Current, vec![hash])
|
||||
}
|
||||
Entry::Occupied(mut entry) => {
|
||||
let acct_txs = entry.get_mut();
|
||||
@@ -180,7 +192,7 @@ impl TransactionQueue {
|
||||
let old = ::std::mem::replace(&mut acct_txs.current[idx], tx_info);
|
||||
self.by_hash.remove(&old.hash);
|
||||
|
||||
(transaction::ImportResult::Current, vec![hash])
|
||||
(ImportDestination::Current, vec![hash])
|
||||
}
|
||||
Err(idx) => {
|
||||
let cur_len = acct_txs.current.len();
|
||||
@@ -202,13 +214,13 @@ impl TransactionQueue {
|
||||
acct_txs.future.insert(future_nonce, future);
|
||||
}
|
||||
|
||||
(transaction::ImportResult::Current, vec![hash])
|
||||
(ImportDestination::Current, vec![hash])
|
||||
} else if idx == cur_len && acct_txs.current.last().map_or(false, |f| f.nonce + 1.into() != nonce) {
|
||||
trace!(target: "txqueue", "Queued future transaction for {}, nonce={}", sender, nonce);
|
||||
let future_nonce = nonce;
|
||||
acct_txs.future.insert(future_nonce, tx_info);
|
||||
|
||||
(transaction::ImportResult::Future, vec![])
|
||||
(ImportDestination::Future, vec![])
|
||||
} else {
|
||||
trace!(target: "txqueue", "Queued current transaction for {}, nonce={}", sender, nonce);
|
||||
|
||||
@@ -217,7 +229,7 @@ impl TransactionQueue {
|
||||
let mut promoted = acct_txs.adjust_future();
|
||||
promoted.insert(0, hash);
|
||||
|
||||
(transaction::ImportResult::Current, promoted)
|
||||
(ImportDestination::Current, promoted)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
//! Light protocol request types.
|
||||
|
||||
use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp};
|
||||
use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp};
|
||||
use ethereum_types::H256;
|
||||
|
||||
mod batch;
|
||||
@@ -148,7 +148,7 @@ impl<T> From<T> for Field<T> {
|
||||
}
|
||||
|
||||
impl<T: Decodable> Decodable for Field<T> {
|
||||
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
||||
match rlp.val_at::<u8>(0)? {
|
||||
0 => Ok(Field::Scalar(rlp.val_at::<T>(1)?)),
|
||||
1 => Ok({
|
||||
@@ -224,7 +224,7 @@ impl From<u64> for HashOrNumber {
|
||||
}
|
||||
|
||||
impl Decodable for HashOrNumber {
|
||||
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
||||
rlp.as_val::<H256>().map(HashOrNumber::Hash)
|
||||
.or_else(|_| rlp.as_val().map(HashOrNumber::Number))
|
||||
}
|
||||
@@ -331,7 +331,7 @@ impl Request {
|
||||
}
|
||||
|
||||
impl Decodable for Request {
|
||||
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
||||
match rlp.val_at::<Kind>(0)? {
|
||||
Kind::Headers => Ok(Request::Headers(rlp.val_at(1)?)),
|
||||
Kind::HeaderProof => Ok(Request::HeaderProof(rlp.val_at(1)?)),
|
||||
@@ -493,7 +493,7 @@ pub enum Kind {
|
||||
}
|
||||
|
||||
impl Decodable for Kind {
|
||||
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
||||
match rlp.as_val::<u8>()? {
|
||||
0 => Ok(Kind::Headers),
|
||||
1 => Ok(Kind::HeaderProof),
|
||||
@@ -578,7 +578,7 @@ impl Response {
|
||||
}
|
||||
|
||||
impl Decodable for Response {
|
||||
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
||||
match rlp.val_at::<Kind>(0)? {
|
||||
Kind::Headers => Ok(Response::Headers(rlp.val_at(1)?)),
|
||||
Kind::HeaderProof => Ok(Response::HeaderProof(rlp.val_at(1)?)),
|
||||
@@ -673,7 +673,7 @@ pub trait ResponseLike {
|
||||
pub mod header {
|
||||
use super::{Field, HashOrNumber, NoSuchOutput, OutputKind, Output};
|
||||
use ethcore::encoded;
|
||||
use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp};
|
||||
use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp};
|
||||
|
||||
/// Potentially incomplete headers request.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)]
|
||||
@@ -754,7 +754,7 @@ pub mod header {
|
||||
}
|
||||
|
||||
impl Decodable for Response {
|
||||
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
||||
use ethcore::header::Header as FullHeader;
|
||||
|
||||
let mut headers = Vec::new();
|
||||
@@ -785,7 +785,7 @@ pub mod header {
|
||||
/// Request and response for header proofs.
|
||||
pub mod header_proof {
|
||||
use super::{Field, NoSuchOutput, OutputKind, Output};
|
||||
use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp};
|
||||
use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp};
|
||||
use ethereum_types::{H256, U256};
|
||||
use bytes::Bytes;
|
||||
|
||||
@@ -859,7 +859,7 @@ pub mod header_proof {
|
||||
}
|
||||
|
||||
impl Decodable for Response {
|
||||
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
||||
Ok(Response {
|
||||
proof: rlp.list_at(0)?,
|
||||
hash: rlp.val_at(1)?,
|
||||
@@ -1027,7 +1027,7 @@ pub mod block_receipts {
|
||||
pub mod block_body {
|
||||
use super::{Field, NoSuchOutput, OutputKind, Output};
|
||||
use ethcore::encoded;
|
||||
use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp};
|
||||
use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp};
|
||||
use ethereum_types::H256;
|
||||
|
||||
/// Potentially incomplete block body request.
|
||||
@@ -1092,7 +1092,7 @@ pub mod block_body {
|
||||
}
|
||||
|
||||
impl Decodable for Response {
|
||||
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
||||
use ethcore::header::Header as FullHeader;
|
||||
use transaction::UnverifiedTransaction;
|
||||
|
||||
@@ -1411,7 +1411,7 @@ pub mod contract_code {
|
||||
pub mod execution {
|
||||
use super::{Field, NoSuchOutput, OutputKind, Output};
|
||||
use transaction::Action;
|
||||
use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp};
|
||||
use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp};
|
||||
use ethereum_types::{H256, U256, Address};
|
||||
use kvdb::DBValue;
|
||||
use bytes::Bytes;
|
||||
@@ -1508,7 +1508,7 @@ pub mod execution {
|
||||
}
|
||||
|
||||
impl Decodable for Response {
|
||||
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
||||
let mut items = Vec::new();
|
||||
for raw_item in rlp.iter() {
|
||||
let mut item = DBValue::new();
|
||||
@@ -1536,7 +1536,7 @@ pub mod execution {
|
||||
/// A request for epoch signal data.
|
||||
pub mod epoch_signal {
|
||||
use super::{Field, NoSuchOutput, OutputKind, Output};
|
||||
use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp};
|
||||
use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp};
|
||||
use ethereum_types::H256;
|
||||
use bytes::Bytes;
|
||||
|
||||
@@ -1548,7 +1548,7 @@ pub mod epoch_signal {
|
||||
}
|
||||
|
||||
impl Decodable for Incomplete {
|
||||
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
||||
Ok(Incomplete {
|
||||
block_hash: rlp.val_at(0)?,
|
||||
})
|
||||
@@ -1617,7 +1617,7 @@ pub mod epoch_signal {
|
||||
}
|
||||
|
||||
impl Decodable for Response {
|
||||
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
||||
|
||||
Ok(Response {
|
||||
signal: rlp.as_val()?,
|
||||
@@ -1642,7 +1642,7 @@ mod tests {
|
||||
{
|
||||
// check as single value.
|
||||
let bytes = ::rlp::encode(&val);
|
||||
let new_val: T = ::rlp::decode(&bytes);
|
||||
let new_val: T = ::rlp::decode(&bytes).unwrap();
|
||||
assert_eq!(val, new_val);
|
||||
|
||||
// check as list containing single value.
|
||||
@@ -1891,7 +1891,7 @@ mod tests {
|
||||
stream.append(&100usize).append_list(&reqs);
|
||||
let out = stream.out();
|
||||
|
||||
let rlp = UntrustedRlp::new(&out);
|
||||
let rlp = Rlp::new(&out);
|
||||
assert_eq!(rlp.val_at::<usize>(0).unwrap(), 100usize);
|
||||
assert_eq!(rlp.list_at::<Request>(1).unwrap(), reqs);
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
[package]
|
||||
name = "ethcore-migrations"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[dependencies]
|
||||
migration = { path = "../../util/migration" }
|
||||
@@ -3,14 +3,13 @@ description = "Parity smart network connections"
|
||||
homepage = "http://parity.io"
|
||||
license = "GPL-3.0"
|
||||
name = "node-filter"
|
||||
version = "1.9.0"
|
||||
version = "1.11.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[dependencies]
|
||||
ethcore = { path = ".."}
|
||||
ethcore-bytes = { path = "../../util/bytes" }
|
||||
ethcore-network = { path = "../../util/network" }
|
||||
ethereum-types = "0.2"
|
||||
ethcore-network-devp2p = { path = "../../util/network-devp2p" }
|
||||
ethereum-types = "0.3"
|
||||
log = "0.3"
|
||||
parking_lot = "0.5"
|
||||
ethabi = "5.1"
|
||||
@@ -21,3 +20,4 @@ lru-cache = "0.1"
|
||||
[dev-dependencies]
|
||||
kvdb-memorydb = { path = "../../util/kvdb-memorydb" }
|
||||
ethcore-io = { path = "../../util/io" }
|
||||
tempdir = "0.3"
|
||||
|
||||
@@ -18,8 +18,7 @@
|
||||
|
||||
extern crate ethabi;
|
||||
extern crate ethcore;
|
||||
extern crate ethcore_bytes as bytes;
|
||||
extern crate ethcore_network as network;
|
||||
extern crate ethcore_network_devp2p as network;
|
||||
extern crate ethereum_types;
|
||||
extern crate lru_cache;
|
||||
extern crate parking_lot;
|
||||
@@ -32,6 +31,8 @@ extern crate ethabi_contract;
|
||||
extern crate ethcore_io as io;
|
||||
#[cfg(test)]
|
||||
extern crate kvdb_memorydb;
|
||||
#[cfg(test)]
|
||||
extern crate tempdir;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
@@ -40,8 +41,7 @@ use std::sync::Weak;
|
||||
use lru_cache::LruCache;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use bytes::Bytes;
|
||||
use ethcore::client::{BlockChainClient, BlockId, ChainNotify};
|
||||
use ethcore::client::{BlockChainClient, BlockId};
|
||||
use ethereum_types::{H256, Address};
|
||||
use network::{NodeId, ConnectionFilter, ConnectionDirection};
|
||||
|
||||
@@ -54,7 +54,7 @@ pub struct NodeFilter {
|
||||
contract: peer_set::PeerSet,
|
||||
client: Weak<BlockChainClient>,
|
||||
contract_address: Address,
|
||||
permission_cache: Mutex<LruCache<NodeId, bool>>,
|
||||
permission_cache: Mutex<LruCache<(H256, NodeId), bool>>,
|
||||
}
|
||||
|
||||
impl NodeFilter {
|
||||
@@ -62,31 +62,33 @@ impl NodeFilter {
|
||||
pub fn new(client: Weak<BlockChainClient>, contract_address: Address) -> NodeFilter {
|
||||
NodeFilter {
|
||||
contract: peer_set::PeerSet::default(),
|
||||
client: client,
|
||||
contract_address: contract_address,
|
||||
client,
|
||||
contract_address,
|
||||
permission_cache: Mutex::new(LruCache::new(MAX_CACHE_SIZE)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear cached permissions.
|
||||
pub fn clear_cache(&self) {
|
||||
self.permission_cache.lock().clear();
|
||||
}
|
||||
}
|
||||
|
||||
impl ConnectionFilter for NodeFilter {
|
||||
fn connection_allowed(&self, own_id: &NodeId, connecting_id: &NodeId, _direction: ConnectionDirection) -> bool {
|
||||
|
||||
let mut cache = self.permission_cache.lock();
|
||||
if let Some(res) = cache.get_mut(connecting_id) {
|
||||
return *res;
|
||||
}
|
||||
|
||||
let client = match self.client.upgrade() {
|
||||
Some(client) => client,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
let block_hash = match client.block_hash(BlockId::Latest) {
|
||||
Some(block_hash) => block_hash,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
let key = (block_hash, *connecting_id);
|
||||
|
||||
let mut cache = self.permission_cache.lock();
|
||||
if let Some(res) = cache.get_mut(&key) {
|
||||
return *res;
|
||||
}
|
||||
|
||||
|
||||
let address = self.contract_address;
|
||||
let own_low = H256::from_slice(&own_id[0..32]);
|
||||
let own_high = H256::from_slice(&own_id[32..64]);
|
||||
@@ -101,59 +103,48 @@ impl ConnectionFilter for NodeFilter {
|
||||
false
|
||||
});
|
||||
|
||||
cache.insert(*connecting_id, allowed);
|
||||
cache.insert(key, allowed);
|
||||
allowed
|
||||
}
|
||||
}
|
||||
|
||||
impl ChainNotify for NodeFilter {
|
||||
fn new_blocks(&self, imported: Vec<H256>, _invalid: Vec<H256>, _enacted: Vec<H256>, _retracted: Vec<H256>, _sealed: Vec<H256>, _proposed: Vec<Bytes>, _duration: u64) {
|
||||
if !imported.is_empty() {
|
||||
self.clear_cache();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::str::FromStr;
|
||||
use ethcore::spec::Spec;
|
||||
use ethcore::client::{BlockChainClient, Client, ClientConfig};
|
||||
use ethcore::miner::Miner;
|
||||
use ethereum_types::Address;
|
||||
use network::{ConnectionDirection, ConnectionFilter, NodeId};
|
||||
use io::IoChannel;
|
||||
use super::NodeFilter;
|
||||
use tempdir::TempDir;
|
||||
|
||||
/// Contract code: https://gist.github.com/arkpar/467dbcc73cbb85b0997a7a10ffa0695f
|
||||
#[test]
|
||||
fn node_filter() {
|
||||
let contract_addr = Address::from_str("0000000000000000000000000000000000000005").unwrap();
|
||||
let contract_addr = "0000000000000000000000000000000000000005".into();
|
||||
let data = include_bytes!("../res/node_filter.json");
|
||||
let spec = Spec::load(&::std::env::temp_dir(), &data[..]).unwrap();
|
||||
let tempdir = TempDir::new("").unwrap();
|
||||
let spec = Spec::load(&tempdir.path(), &data[..]).unwrap();
|
||||
let client_db = Arc::new(::kvdb_memorydb::create(::ethcore::db::NUM_COLUMNS.unwrap_or(0)));
|
||||
|
||||
let client = Client::new(
|
||||
ClientConfig::default(),
|
||||
&spec,
|
||||
client_db,
|
||||
Arc::new(Miner::with_spec(&spec)),
|
||||
Arc::new(Miner::new_for_tests(&spec, None)),
|
||||
IoChannel::disconnected(),
|
||||
).unwrap();
|
||||
let filter = NodeFilter::new(Arc::downgrade(&client) as Weak<BlockChainClient>, contract_addr);
|
||||
let self1 = NodeId::from_str("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002").unwrap();
|
||||
let self2 = NodeId::from_str("00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003").unwrap();
|
||||
let node1 = NodeId::from_str("00000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012").unwrap();
|
||||
let node2 = NodeId::from_str("00000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000022").unwrap();
|
||||
let nodex = NodeId::from_str("77000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||
let self1: NodeId = "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002".into();
|
||||
let self2: NodeId = "00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003".into();
|
||||
let node1: NodeId = "00000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012".into();
|
||||
let node2: NodeId = "00000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000022".into();
|
||||
let nodex: NodeId = "77000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into();
|
||||
|
||||
assert!(filter.connection_allowed(&self1, &node1, ConnectionDirection::Inbound));
|
||||
assert!(filter.connection_allowed(&self1, &nodex, ConnectionDirection::Inbound));
|
||||
filter.clear_cache();
|
||||
assert!(filter.connection_allowed(&self2, &node1, ConnectionDirection::Inbound));
|
||||
assert!(filter.connection_allowed(&self2, &node2, ConnectionDirection::Inbound));
|
||||
assert!(!filter.connection_allowed(&self2, &nodex, ConnectionDirection::Inbound));
|
||||
}
|
||||
}
|
||||
|
||||
37
ethcore/private-tx/Cargo.toml
Normal file
37
ethcore/private-tx/Cargo.toml
Normal file
@@ -0,0 +1,37 @@
|
||||
[package]
|
||||
description = "Parity Private Transactions"
|
||||
name = "ethcore-private-tx"
|
||||
version = "1.0.0"
|
||||
license = "GPL-3.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[dependencies]
|
||||
error-chain = { version = "0.11", default-features = false }
|
||||
ethabi = "5.1"
|
||||
ethabi-contract = "5.0"
|
||||
ethabi-derive = "5.0"
|
||||
ethcore = { path = ".." }
|
||||
ethcore-bytes = { path = "../../util/bytes" }
|
||||
ethcore-crypto = { path = "../crypto" }
|
||||
ethcore-io = { path = "../../util/io" }
|
||||
ethcore-logger = { path = "../../logger" }
|
||||
ethcore-miner = { path = "../../miner" }
|
||||
ethcore-transaction = { path = "../transaction" }
|
||||
ethereum-types = "0.3"
|
||||
ethjson = { path = "../../json" }
|
||||
ethkey = { path = "../../ethkey" }
|
||||
fetch = { path = "../../util/fetch" }
|
||||
futures = "0.1"
|
||||
keccak-hash = { path = "../../util/hash" }
|
||||
log = "0.3"
|
||||
parking_lot = "0.5"
|
||||
patricia-trie = { path = "../../util/patricia_trie" }
|
||||
rand = "0.3"
|
||||
rlp = { path = "../../util/rlp" }
|
||||
rlp_derive = { path = "../../util/rlp_derive" }
|
||||
rustc-hex = "1.0"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0"
|
||||
tiny-keccak = "1.3"
|
||||
url = "1"
|
||||
1
ethcore/private-tx/res/private.evm
Normal file
1
ethcore/private-tx/res/private.evm
Normal file
File diff suppressed because one or more lines are too long
1
ethcore/private-tx/res/private.json
Normal file
1
ethcore/private-tx/res/private.json
Normal file
@@ -0,0 +1 @@
|
||||
[{"constant": false,"inputs": [{"name": "newState","type": "bytes"},{"name": "v","type": "uint8[]"},{"name": "r","type": "bytes32[]"},{"name": "s","type": "bytes32[]"}],"name": "setState","outputs": [],"payable": false,"stateMutability": "nonpayable","type": "function"},{"constant": true,"inputs": [],"name": "code","outputs": [{"name": "","type": "bytes"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": true,"inputs": [{"name": "","type": "uint256"}],"name": "validators","outputs": [{"name": "","type": "address"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": true,"inputs": [],"name": "nonce","outputs": [{"name": "","type": "uint256"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": true,"inputs": [],"name": "getValidators","outputs": [{"name": "","type": "address[]"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": true,"inputs": [],"name": "state","outputs": [{"name": "","type": "bytes"}],"payable": false,"stateMutability": "view","type": "function"},{"inputs": [{"name": "initialValidators","type": "address[]"},{"name": "initialCode","type": "bytes"},{"name": "initialState","type": "bytes"}],"payable": false,"stateMutability": "nonpayable","type": "constructor"}]
|
||||
275
ethcore/private-tx/src/encryptor.rs
Normal file
275
ethcore/private-tx/src/encryptor.rs
Normal file
@@ -0,0 +1,275 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Encryption providers.
|
||||
|
||||
use std::io::Read;
|
||||
use std::str::FromStr;
|
||||
use std::iter::repeat;
|
||||
use std::time::{Instant, Duration};
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
use parking_lot::Mutex;
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use ethereum_types::{H128, H256, Address};
|
||||
use ethjson;
|
||||
use ethkey::{Signature, Public};
|
||||
use crypto;
|
||||
use futures::Future;
|
||||
use fetch::{Fetch, Client as FetchClient, Method, BodyReader, Request};
|
||||
use bytes::{Bytes, ToPretty};
|
||||
use error::{Error, ErrorKind};
|
||||
use url::Url;
|
||||
use super::find_account_password;
|
||||
|
||||
/// Initialization vector length.
|
||||
const INIT_VEC_LEN: usize = 16;
|
||||
|
||||
/// Duration of storing retrieved keys (in ms)
|
||||
const ENCRYPTION_SESSION_DURATION: u64 = 30 * 1000;
|
||||
|
||||
/// Trait for encryption/decryption operations.
|
||||
pub trait Encryptor: Send + Sync + 'static {
|
||||
/// Generate unique contract key && encrypt passed data. Encryption can only be performed once.
|
||||
fn encrypt(
|
||||
&self,
|
||||
contract_address: &Address,
|
||||
accounts: &AccountProvider,
|
||||
initialisation_vector: &H128,
|
||||
plain_data: &[u8],
|
||||
) -> Result<Bytes, Error>;
|
||||
|
||||
/// Decrypt data using previously generated contract key.
|
||||
fn decrypt(
|
||||
&self,
|
||||
contract_address: &Address,
|
||||
accounts: &AccountProvider,
|
||||
cypher: &[u8],
|
||||
) -> Result<Bytes, Error>;
|
||||
}
|
||||
|
||||
/// Configurtion for key server encryptor
|
||||
#[derive(Default, PartialEq, Debug, Clone)]
|
||||
pub struct EncryptorConfig {
|
||||
/// URL to key server
|
||||
pub base_url: Option<String>,
|
||||
/// Key server's threshold
|
||||
pub threshold: u32,
|
||||
/// Account used for signing requests to key server
|
||||
pub key_server_account: Option<Address>,
|
||||
/// Passwords used to unlock accounts
|
||||
pub passwords: Vec<String>,
|
||||
}
|
||||
|
||||
struct EncryptionSession {
|
||||
key: Bytes,
|
||||
end_time: Instant,
|
||||
}
|
||||
|
||||
/// SecretStore-based encryption/decryption operations.
|
||||
pub struct SecretStoreEncryptor {
|
||||
config: EncryptorConfig,
|
||||
client: FetchClient,
|
||||
sessions: Mutex<HashMap<Address, EncryptionSession>>,
|
||||
}
|
||||
|
||||
impl SecretStoreEncryptor {
|
||||
/// Create new encryptor
|
||||
pub fn new(config: EncryptorConfig, client: FetchClient) -> Result<Self, Error> {
|
||||
Ok(SecretStoreEncryptor {
|
||||
config,
|
||||
client,
|
||||
sessions: Mutex::default(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Ask secret store for key && decrypt the key.
|
||||
fn retrieve_key(
|
||||
&self,
|
||||
url_suffix: &str,
|
||||
use_post: bool,
|
||||
contract_address: &Address,
|
||||
accounts: &AccountProvider,
|
||||
) -> Result<Bytes, Error> {
|
||||
// check if the key was already cached
|
||||
if let Some(key) = self.obtained_key(contract_address) {
|
||||
return Ok(key);
|
||||
}
|
||||
let contract_address_signature = self.sign_contract_address(contract_address, accounts)?;
|
||||
let requester = self.config.key_server_account.ok_or_else(|| ErrorKind::KeyServerAccountNotSet)?;
|
||||
|
||||
// key id in SS is H256 && we have H160 here => expand with assitional zeros
|
||||
let contract_address_extended: H256 = contract_address.into();
|
||||
let base_url = self.config.base_url.clone().ok_or_else(|| ErrorKind::KeyServerNotSet)?;
|
||||
|
||||
// prepare request url
|
||||
let url = format!("{}/{}/{}{}",
|
||||
base_url,
|
||||
contract_address_extended.to_hex(),
|
||||
contract_address_signature,
|
||||
url_suffix,
|
||||
);
|
||||
|
||||
// send HTTP request
|
||||
let method = if use_post {
|
||||
Method::Post
|
||||
} else {
|
||||
Method::Get
|
||||
};
|
||||
|
||||
let url = Url::from_str(&url).map_err(|e| ErrorKind::Encrypt(e.to_string()))?;
|
||||
let response = self.client.fetch(Request::new(url, method), Default::default()).wait()
|
||||
.map_err(|e| ErrorKind::Encrypt(e.to_string()))?;
|
||||
|
||||
if response.is_not_found() {
|
||||
bail!(ErrorKind::EncryptionKeyNotFound(*contract_address));
|
||||
}
|
||||
|
||||
if !response.is_success() {
|
||||
bail!(ErrorKind::Encrypt(response.status().canonical_reason().unwrap_or("unknown").into()));
|
||||
}
|
||||
|
||||
// read HTTP response
|
||||
let mut result = String::new();
|
||||
BodyReader::new(response).read_to_string(&mut result)?;
|
||||
|
||||
// response is JSON string (which is, in turn, hex-encoded, encrypted Public)
|
||||
let encrypted_bytes: ethjson::bytes::Bytes = result.trim_matches('\"').parse().map_err(|e| ErrorKind::Encrypt(e))?;
|
||||
let password = find_account_password(&self.config.passwords, &*accounts, &requester);
|
||||
|
||||
// decrypt Public
|
||||
let decrypted_bytes = accounts.decrypt(requester, password, &crypto::DEFAULT_MAC, &encrypted_bytes)?;
|
||||
let decrypted_key = Public::from_slice(&decrypted_bytes);
|
||||
|
||||
// and now take x coordinate of Public as a key
|
||||
let key: Bytes = (*decrypted_key)[..INIT_VEC_LEN].into();
|
||||
|
||||
// cache the key in the session and clear expired sessions
|
||||
self.sessions.lock().insert(*contract_address, EncryptionSession{
|
||||
key: key.clone(),
|
||||
end_time: Instant::now() + Duration::from_millis(ENCRYPTION_SESSION_DURATION),
|
||||
});
|
||||
self.clean_expired_sessions();
|
||||
Ok(key)
|
||||
}
|
||||
|
||||
fn clean_expired_sessions(&self) {
|
||||
let mut sessions = self.sessions.lock();
|
||||
sessions.retain(|_, session| session.end_time < Instant::now());
|
||||
}
|
||||
|
||||
fn obtained_key(&self, contract_address: &Address) -> Option<Bytes> {
|
||||
let mut sessions = self.sessions.lock();
|
||||
let stored_session = sessions.entry(*contract_address);
|
||||
match stored_session {
|
||||
Entry::Occupied(session) => {
|
||||
if Instant::now() > session.get().end_time {
|
||||
session.remove_entry();
|
||||
None
|
||||
} else {
|
||||
Some(session.get().key.clone())
|
||||
}
|
||||
}
|
||||
Entry::Vacant(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn sign_contract_address(&self, contract_address: &Address, accounts: &AccountProvider) -> Result<Signature, Error> {
|
||||
// key id in SS is H256 && we have H160 here => expand with assitional zeros
|
||||
let contract_address_extended: H256 = contract_address.into();
|
||||
let key_server_account = self.config.key_server_account.ok_or_else(|| ErrorKind::KeyServerAccountNotSet)?;
|
||||
let password = find_account_password(&self.config.passwords, accounts, &key_server_account);
|
||||
Ok(accounts.sign(key_server_account, password, H256::from_slice(&contract_address_extended))?)
|
||||
}
|
||||
}
|
||||
|
||||
impl Encryptor for SecretStoreEncryptor {
|
||||
fn encrypt(
|
||||
&self,
|
||||
contract_address: &Address,
|
||||
accounts: &AccountProvider,
|
||||
initialisation_vector: &H128,
|
||||
plain_data: &[u8],
|
||||
) -> Result<Bytes, Error> {
|
||||
// retrieve the key, try to generate it if it doesn't exist yet
|
||||
let key = match self.retrieve_key("", false, contract_address, &*accounts) {
|
||||
Ok(key) => Ok(key),
|
||||
Err(Error(ErrorKind::EncryptionKeyNotFound(_), _)) => {
|
||||
trace!("Key for account wasnt found in sstore. Creating. Address: {:?}", contract_address);
|
||||
self.retrieve_key(&format!("/{}", self.config.threshold), true, contract_address, &*accounts)
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}?;
|
||||
|
||||
// encrypt data
|
||||
let mut cypher = Vec::with_capacity(plain_data.len() + initialisation_vector.len());
|
||||
cypher.extend(repeat(0).take(plain_data.len()));
|
||||
crypto::aes::encrypt(&key, initialisation_vector, plain_data, &mut cypher);
|
||||
cypher.extend_from_slice(&initialisation_vector);
|
||||
|
||||
Ok(cypher)
|
||||
}
|
||||
|
||||
/// Decrypt data using previously generated contract key.
|
||||
fn decrypt(
|
||||
&self,
|
||||
contract_address: &Address,
|
||||
accounts: &AccountProvider,
|
||||
cypher: &[u8],
|
||||
) -> Result<Bytes, Error> {
|
||||
// initialization vector takes INIT_VEC_LEN bytes
|
||||
let cypher_len = cypher.len();
|
||||
if cypher_len < INIT_VEC_LEN {
|
||||
bail!(ErrorKind::Decrypt("Invalid cypher".into()));
|
||||
}
|
||||
|
||||
// retrieve existing key
|
||||
let key = self.retrieve_key("", false, contract_address, accounts)?;
|
||||
|
||||
// use symmetric decryption to decrypt document
|
||||
let (cypher, iv) = cypher.split_at(cypher_len - INIT_VEC_LEN);
|
||||
let mut plain_data = Vec::with_capacity(cypher_len - INIT_VEC_LEN);
|
||||
plain_data.extend(repeat(0).take(cypher_len - INIT_VEC_LEN));
|
||||
crypto::aes::decrypt(&key, &iv, cypher, &mut plain_data);
|
||||
|
||||
Ok(plain_data)
|
||||
}
|
||||
}
|
||||
|
||||
/// Dummy encryptor.
|
||||
#[derive(Default)]
|
||||
pub struct NoopEncryptor;
|
||||
|
||||
impl Encryptor for NoopEncryptor {
|
||||
fn encrypt(
|
||||
&self,
|
||||
_contract_address: &Address,
|
||||
_accounts: &AccountProvider,
|
||||
_initialisation_vector: &H128,
|
||||
data: &[u8],
|
||||
) -> Result<Bytes, Error> {
|
||||
Ok(data.to_vec())
|
||||
}
|
||||
|
||||
fn decrypt(
|
||||
&self,
|
||||
_contract_address: &Address,
|
||||
_accounts: &AccountProvider,
|
||||
data: &[u8],
|
||||
) -> Result<Bytes, Error> {
|
||||
Ok(data.to_vec())
|
||||
}
|
||||
}
|
||||
208
ethcore/private-tx/src/error.rs
Normal file
208
ethcore/private-tx/src/error.rs
Normal file
@@ -0,0 +1,208 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use ethereum_types::Address;
|
||||
use rlp::DecoderError;
|
||||
use trie::TrieError;
|
||||
use ethcore::account_provider::SignError;
|
||||
use ethcore::error::{Error as EthcoreError, ExecutionError};
|
||||
use transaction::Error as TransactionError;
|
||||
use ethkey::Error as KeyError;
|
||||
|
||||
error_chain! {
|
||||
foreign_links {
|
||||
Io(::std::io::Error) #[doc = "Error concerning the Rust standard library's IO subsystem."];
|
||||
Decoder(DecoderError) #[doc = "RLP decoding error."];
|
||||
Trie(TrieError) #[doc = "Error concerning TrieDBs."];
|
||||
}
|
||||
|
||||
errors {
|
||||
#[doc = "Encryption error."]
|
||||
Encrypt(err: String) {
|
||||
description("Encryption error"),
|
||||
display("Encryption error. ({})", err),
|
||||
}
|
||||
|
||||
#[doc = "Decryption error."]
|
||||
Decrypt(err: String) {
|
||||
description("Decryption error"),
|
||||
display("Decryption error. ({})", err),
|
||||
}
|
||||
|
||||
#[doc = "Address not authorized."]
|
||||
NotAuthorised(address: Address) {
|
||||
description("Address not authorized"),
|
||||
display("Private transaction execution is not authorised for {}", address),
|
||||
}
|
||||
|
||||
#[doc = "Transaction creates more than one contract."]
|
||||
TooManyContracts {
|
||||
description("Transaction creates more than one contract."),
|
||||
display("Private transaction created too many contracts"),
|
||||
}
|
||||
|
||||
#[doc = "Contract call error."]
|
||||
Call(err: String) {
|
||||
description("Contract call error."),
|
||||
display("Contract call error. ({})", err),
|
||||
}
|
||||
|
||||
#[doc = "State is not available."]
|
||||
StatePruned {
|
||||
description("State is not available."),
|
||||
display("State is not available"),
|
||||
}
|
||||
|
||||
#[doc = "State is incorrect."]
|
||||
StateIncorrect {
|
||||
description("State is incorrect."),
|
||||
display("State is incorrect"),
|
||||
}
|
||||
|
||||
#[doc = "Wrong private transaction type."]
|
||||
BadTransactonType {
|
||||
description("Wrong private transaction type."),
|
||||
display("Wrong private transaction type"),
|
||||
}
|
||||
|
||||
#[doc = "Contract does not exist or was not created."]
|
||||
ContractDoesNotExist {
|
||||
description("Contract does not exist or was not created."),
|
||||
display("Contract does not exist or was not created"),
|
||||
}
|
||||
|
||||
#[doc = "Reference to the client is corrupted."]
|
||||
ClientIsMalformed {
|
||||
description("Reference to the client is corrupted."),
|
||||
display("Reference to the client is corrupted"),
|
||||
}
|
||||
|
||||
#[doc = "Queue of private transactions for verification is full."]
|
||||
QueueIsFull {
|
||||
description("Queue of private transactions for verification is full."),
|
||||
display("Queue of private transactions for verification is full"),
|
||||
}
|
||||
|
||||
#[doc = "The transaction already exists in queue of private transactions."]
|
||||
PrivateTransactionAlreadyImported {
|
||||
description("The transaction already exists in queue of private transactions."),
|
||||
display("The transaction already exists in queue of private transactions."),
|
||||
}
|
||||
|
||||
#[doc = "The information about private transaction is not found in the store."]
|
||||
PrivateTransactionNotFound {
|
||||
description("The information about private transaction is not found in the store."),
|
||||
display("The information about private transaction is not found in the store."),
|
||||
}
|
||||
|
||||
#[doc = "Account for signing public transactions not set."]
|
||||
SignerAccountNotSet {
|
||||
description("Account for signing public transactions not set."),
|
||||
display("Account for signing public transactions not set."),
|
||||
}
|
||||
|
||||
#[doc = "Account for validating private transactions not set."]
|
||||
ValidatorAccountNotSet {
|
||||
description("Account for validating private transactions not set."),
|
||||
display("Account for validating private transactions not set."),
|
||||
}
|
||||
|
||||
#[doc = "Account for signing requests to key server not set."]
|
||||
KeyServerAccountNotSet {
|
||||
description("Account for signing requests to key server not set."),
|
||||
display("Account for signing requests to key server not set."),
|
||||
}
|
||||
|
||||
#[doc = "Encryption key is not found on key server."]
|
||||
EncryptionKeyNotFound(address: Address) {
|
||||
description("Encryption key is not found on key server"),
|
||||
display("Encryption key is not found on key server for {}", address),
|
||||
}
|
||||
|
||||
#[doc = "Key server URL is not set."]
|
||||
KeyServerNotSet {
|
||||
description("Key server URL is not set."),
|
||||
display("Key server URL is not set."),
|
||||
}
|
||||
|
||||
#[doc = "VM execution error."]
|
||||
Execution(err: ExecutionError) {
|
||||
description("VM execution error."),
|
||||
display("VM execution error {}", err),
|
||||
}
|
||||
|
||||
#[doc = "General signing error."]
|
||||
Key(err: KeyError) {
|
||||
description("General signing error."),
|
||||
display("General signing error {}", err),
|
||||
}
|
||||
|
||||
#[doc = "Account provider signing error."]
|
||||
Sign(err: SignError) {
|
||||
description("Account provider signing error."),
|
||||
display("Account provider signing error {}", err),
|
||||
}
|
||||
|
||||
#[doc = "Error of transactions processing."]
|
||||
Transaction(err: TransactionError) {
|
||||
description("Error of transactions processing."),
|
||||
display("Error of transactions processing {}", err),
|
||||
}
|
||||
|
||||
#[doc = "General ethcore error."]
|
||||
Ethcore(err: EthcoreError) {
|
||||
description("General ethcore error."),
|
||||
display("General ethcore error {}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SignError> for Error {
|
||||
fn from(err: SignError) -> Self {
|
||||
ErrorKind::Sign(err).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KeyError> for Error {
|
||||
fn from(err: KeyError) -> Self {
|
||||
ErrorKind::Key(err).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExecutionError> for Error {
|
||||
fn from(err: ExecutionError) -> Self {
|
||||
ErrorKind::Execution(err).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TransactionError> for Error {
|
||||
fn from(err: TransactionError) -> Self {
|
||||
ErrorKind::Transaction(err).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EthcoreError> for Error {
|
||||
fn from(err: EthcoreError) -> Self {
|
||||
ErrorKind::Ethcore(err).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> From<Box<E>> for Error where Error: From<E> {
|
||||
fn from(err: Box<E>) -> Error {
|
||||
Error::from(*err)
|
||||
}
|
||||
}
|
||||
|
||||
694
ethcore/private-tx/src/lib.rs
Normal file
694
ethcore/private-tx/src/lib.rs
Normal file
@@ -0,0 +1,694 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Private transactions module.
|
||||
|
||||
// Recursion limit required because of
|
||||
// error_chain foreign_links.
|
||||
#![recursion_limit="256"]
|
||||
|
||||
mod encryptor;
|
||||
mod private_transactions;
|
||||
mod messages;
|
||||
mod error;
|
||||
|
||||
extern crate ethcore;
|
||||
extern crate ethcore_bytes as bytes;
|
||||
extern crate ethcore_crypto as crypto;
|
||||
extern crate ethcore_io as io;
|
||||
extern crate ethcore_miner;
|
||||
extern crate ethcore_transaction as transaction;
|
||||
extern crate ethabi;
|
||||
extern crate ethereum_types;
|
||||
extern crate ethkey;
|
||||
extern crate ethjson;
|
||||
extern crate fetch;
|
||||
extern crate futures;
|
||||
extern crate keccak_hash as hash;
|
||||
extern crate parking_lot;
|
||||
extern crate patricia_trie as trie;
|
||||
extern crate rlp;
|
||||
extern crate url;
|
||||
extern crate rustc_hex;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
#[macro_use]
|
||||
extern crate ethabi_derive;
|
||||
#[macro_use]
|
||||
extern crate ethabi_contract;
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
#[macro_use]
|
||||
extern crate rlp_derive;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate rand;
|
||||
#[cfg(test)]
|
||||
extern crate ethcore_logger;
|
||||
|
||||
pub use encryptor::{Encryptor, SecretStoreEncryptor, EncryptorConfig, NoopEncryptor};
|
||||
pub use private_transactions::{PrivateTransactionDesc, VerificationStore, PrivateTransactionSigningDesc, SigningStore};
|
||||
pub use messages::{PrivateTransaction, SignedPrivateTransaction};
|
||||
pub use error::{Error, ErrorKind};
|
||||
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::time::Duration;
|
||||
use ethereum_types::{H128, H256, U256, Address};
|
||||
use hash::keccak;
|
||||
use rlp::*;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use bytes::Bytes;
|
||||
use ethkey::{Signature, recover, public_to_address};
|
||||
use io::IoChannel;
|
||||
use ethcore::executive::{Executive, TransactOptions};
|
||||
use ethcore::executed::{Executed};
|
||||
use transaction::{SignedTransaction, Transaction, Action, UnverifiedTransaction};
|
||||
use ethcore::{contract_address as ethcore_contract_address};
|
||||
use ethcore::client::{
|
||||
Client, ChainNotify, ChainRoute, ChainMessageType, ClientIoMessage, BlockId, CallContract
|
||||
};
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use ethcore::miner::{self, Miner, MinerService, pool_client::NonceCache};
|
||||
use ethcore::trace::{Tracer, VMTracer};
|
||||
use rustc_hex::FromHex;
|
||||
|
||||
// Source avaiable at https://github.com/parity-contracts/private-tx/blob/master/contracts/PrivateContract.sol
|
||||
const DEFAULT_STUB_CONTRACT: &'static str = include_str!("../res/private.evm");
|
||||
|
||||
use_contract!(private, "PrivateContract", "res/private.json");
|
||||
|
||||
/// Initialization vector length.
|
||||
const INIT_VEC_LEN: usize = 16;
|
||||
|
||||
/// Size of nonce cache
|
||||
const NONCE_CACHE_SIZE: usize = 128;
|
||||
|
||||
/// Configurtion for private transaction provider
|
||||
#[derive(Default, PartialEq, Debug, Clone)]
|
||||
pub struct ProviderConfig {
|
||||
/// Accounts that can be used for validation
|
||||
pub validator_accounts: Vec<Address>,
|
||||
/// Account used for signing public transactions created from private transactions
|
||||
pub signer_account: Option<Address>,
|
||||
/// Passwords used to unlock accounts
|
||||
pub passwords: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Private transaction execution receipt.
|
||||
pub struct Receipt {
|
||||
/// Private transaction hash.
|
||||
pub hash: H256,
|
||||
/// Created contract address if any.
|
||||
pub contract_address: Option<Address>,
|
||||
/// Execution status.
|
||||
pub status_code: u8,
|
||||
}
|
||||
|
||||
/// Manager of private transactions
|
||||
pub struct Provider {
|
||||
encryptor: Box<Encryptor>,
|
||||
validator_accounts: HashSet<Address>,
|
||||
signer_account: Option<Address>,
|
||||
passwords: Vec<String>,
|
||||
notify: RwLock<Vec<Weak<ChainNotify>>>,
|
||||
transactions_for_signing: Mutex<SigningStore>,
|
||||
// TODO [ToDr] Move the Mutex/RwLock inside `VerificationStore` after refactored to `drain`.
|
||||
transactions_for_verification: Mutex<VerificationStore>,
|
||||
client: Arc<Client>,
|
||||
miner: Arc<Miner>,
|
||||
accounts: Arc<AccountProvider>,
|
||||
channel: IoChannel<ClientIoMessage>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PrivateExecutionResult<T, V> where T: Tracer, V: VMTracer {
|
||||
code: Option<Bytes>,
|
||||
state: Bytes,
|
||||
contract_address: Option<Address>,
|
||||
result: Executed<T::Output, V::Output>,
|
||||
}
|
||||
|
||||
impl Provider where {
|
||||
/// Create a new provider.
|
||||
pub fn new(
|
||||
client: Arc<Client>,
|
||||
miner: Arc<Miner>,
|
||||
accounts: Arc<AccountProvider>,
|
||||
encryptor: Box<Encryptor>,
|
||||
config: ProviderConfig,
|
||||
channel: IoChannel<ClientIoMessage>,
|
||||
) -> Self {
|
||||
Provider {
|
||||
encryptor,
|
||||
validator_accounts: config.validator_accounts.into_iter().collect(),
|
||||
signer_account: config.signer_account,
|
||||
passwords: config.passwords,
|
||||
notify: RwLock::default(),
|
||||
transactions_for_signing: Mutex::default(),
|
||||
transactions_for_verification: Mutex::default(),
|
||||
client,
|
||||
miner,
|
||||
accounts,
|
||||
channel,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO [ToDr] Don't use `ChainNotify` here!
|
||||
// Better to create a separate notification type for this.
|
||||
/// Adds an actor to be notified on certain events
|
||||
pub fn add_notify(&self, target: Arc<ChainNotify>) {
|
||||
self.notify.write().push(Arc::downgrade(&target));
|
||||
}
|
||||
|
||||
fn notify<F>(&self, f: F) where F: Fn(&ChainNotify) {
|
||||
for np in self.notify.read().iter() {
|
||||
if let Some(n) = np.upgrade() {
|
||||
f(&*n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 1. Create private transaction from the signed transaction
|
||||
/// 2. Executes private transaction
|
||||
/// 3. Save it with state returned on prev step to the queue for signing
|
||||
/// 4. Broadcast corresponding message to the chain
|
||||
pub fn create_private_transaction(&self, signed_transaction: SignedTransaction) -> Result<Receipt, Error> {
|
||||
trace!("Creating private transaction from regular transaction: {:?}", signed_transaction);
|
||||
if self.signer_account.is_none() {
|
||||
trace!("Signing account not set");
|
||||
bail!(ErrorKind::SignerAccountNotSet);
|
||||
}
|
||||
let tx_hash = signed_transaction.hash();
|
||||
match signed_transaction.action {
|
||||
Action::Create => {
|
||||
bail!(ErrorKind::BadTransactonType);
|
||||
}
|
||||
Action::Call(contract) => {
|
||||
let data = signed_transaction.rlp_bytes();
|
||||
let encrypted_transaction = self.encrypt(&contract, &Self::iv_from_transaction(&signed_transaction), &data)?;
|
||||
let private = PrivateTransaction {
|
||||
encrypted: encrypted_transaction,
|
||||
contract,
|
||||
};
|
||||
// TODO [ToDr] Using BlockId::Latest is bad here,
|
||||
// the block may change in the middle of execution
|
||||
// causing really weird stuff to happen.
|
||||
// We should retrieve hash and stick to that. IMHO
|
||||
// best would be to change the API and only allow H256 instead of BlockID
|
||||
// in private-tx to avoid such mistakes.
|
||||
let contract_nonce = self.get_contract_nonce(&contract, BlockId::Latest)?;
|
||||
let private_state = self.execute_private_transaction(BlockId::Latest, &signed_transaction)?;
|
||||
trace!("Private transaction created, encrypted transaction: {:?}, private state: {:?}", private, private_state);
|
||||
let contract_validators = self.get_validators(BlockId::Latest, &contract)?;
|
||||
trace!("Required validators: {:?}", contract_validators);
|
||||
let private_state_hash = self.calculate_state_hash(&private_state, contract_nonce);
|
||||
trace!("Hashed effective private state for sender: {:?}", private_state_hash);
|
||||
self.transactions_for_signing.lock().add_transaction(private.hash(), signed_transaction, contract_validators, private_state, contract_nonce)?;
|
||||
self.broadcast_private_transaction(private.rlp_bytes().into_vec());
|
||||
Ok(Receipt {
|
||||
hash: tx_hash,
|
||||
contract_address: None,
|
||||
status_code: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate hash from united private state and contract nonce
|
||||
pub fn calculate_state_hash(&self, state: &Bytes, nonce: U256) -> H256 {
|
||||
let state_hash = keccak(state);
|
||||
let mut state_buf = [0u8; 64];
|
||||
state_buf[..32].clone_from_slice(&state_hash);
|
||||
state_buf[32..].clone_from_slice(&H256::from(nonce));
|
||||
keccak(&state_buf.as_ref())
|
||||
}
|
||||
|
||||
/// Extract signed transaction from private transaction
|
||||
fn extract_original_transaction(&self, private: PrivateTransaction, contract: &Address) -> Result<UnverifiedTransaction, Error> {
|
||||
let encrypted_transaction = private.encrypted;
|
||||
let transaction_bytes = self.decrypt(contract, &encrypted_transaction)?;
|
||||
let original_transaction: UnverifiedTransaction = Rlp::new(&transaction_bytes).as_val()?;
|
||||
Ok(original_transaction)
|
||||
}
|
||||
|
||||
fn pool_client<'a>(&'a self, nonce_cache: &'a NonceCache) -> miner::pool_client::PoolClient<'a, Client> {
|
||||
let engine = self.client.engine();
|
||||
let refuse_service_transactions = true;
|
||||
miner::pool_client::PoolClient::new(
|
||||
&*self.client,
|
||||
nonce_cache,
|
||||
engine,
|
||||
Some(&*self.accounts),
|
||||
refuse_service_transactions,
|
||||
)
|
||||
}
|
||||
|
||||
/// Retrieve and verify the first available private transaction for every sender
|
||||
///
|
||||
/// TODO [ToDr] It seems that:
|
||||
/// The 3 methods `ready_transaction,get_descriptor,remove` are always used in conjuction so most likely
|
||||
/// can be replaced with a single `drain()` method instead.
|
||||
/// Thanks to this we also don't really need to lock the entire verification for the time of execution.
|
||||
fn process_queue(&self) -> Result<(), Error> {
|
||||
let nonce_cache = NonceCache::new(NONCE_CACHE_SIZE);
|
||||
let mut verification_queue = self.transactions_for_verification.lock();
|
||||
let ready_transactions = verification_queue.ready_transactions(self.pool_client(&nonce_cache));
|
||||
for transaction in ready_transactions {
|
||||
let transaction_hash = transaction.signed().hash();
|
||||
match verification_queue.private_transaction_descriptor(&transaction_hash) {
|
||||
Ok(desc) => {
|
||||
if !self.validator_accounts.contains(&desc.validator_account) {
|
||||
trace!("Cannot find validator account in config");
|
||||
bail!(ErrorKind::ValidatorAccountNotSet);
|
||||
}
|
||||
let account = desc.validator_account;
|
||||
if let Action::Call(contract) = transaction.signed().action {
|
||||
// TODO [ToDr] Usage of BlockId::Latest
|
||||
let contract_nonce = self.get_contract_nonce(&contract, BlockId::Latest)?;
|
||||
let private_state = self.execute_private_transaction(BlockId::Latest, transaction.signed())?;
|
||||
let private_state_hash = self.calculate_state_hash(&private_state, contract_nonce);
|
||||
trace!("Hashed effective private state for validator: {:?}", private_state_hash);
|
||||
let password = find_account_password(&self.passwords, &*self.accounts, &account);
|
||||
let signed_state = self.accounts.sign(account, password, private_state_hash)?;
|
||||
let signed_private_transaction = SignedPrivateTransaction::new(desc.private_hash, signed_state, None);
|
||||
trace!("Sending signature for private transaction: {:?}", signed_private_transaction);
|
||||
self.broadcast_signed_private_transaction(signed_private_transaction.rlp_bytes().into_vec());
|
||||
} else {
|
||||
warn!("Incorrect type of action for the transaction");
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
warn!("Cannot retrieve descriptor for transaction with error {:?}", e);
|
||||
}
|
||||
}
|
||||
verification_queue.remove_private_transaction(&transaction_hash);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn last_required_signature(&self, desc: &PrivateTransactionSigningDesc, sign: Signature) -> Result<bool, Error> {
|
||||
if desc.received_signatures.contains(&sign) {
|
||||
return Ok(false);
|
||||
}
|
||||
let state_hash = self.calculate_state_hash(&desc.state, desc.contract_nonce);
|
||||
match recover(&sign, &state_hash) {
|
||||
Ok(public) => {
|
||||
let sender = public_to_address(&public);
|
||||
match desc.validators.contains(&sender) {
|
||||
true => {
|
||||
Ok(desc.received_signatures.len() + 1 == desc.validators.len())
|
||||
}
|
||||
false => {
|
||||
trace!("Sender's state doesn't correspond to validator's");
|
||||
bail!(ErrorKind::StateIncorrect);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
trace!("Sender's state doesn't correspond to validator's, error {:?}", err);
|
||||
bail!(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Broadcast the private transaction message to the chain
|
||||
fn broadcast_private_transaction(&self, message: Bytes) {
|
||||
self.notify(|notify| notify.broadcast(ChainMessageType::PrivateTransaction(message.clone())));
|
||||
}
|
||||
|
||||
/// Broadcast signed private transaction message to the chain
|
||||
fn broadcast_signed_private_transaction(&self, message: Bytes) {
|
||||
self.notify(|notify| notify.broadcast(ChainMessageType::SignedPrivateTransaction(message.clone())));
|
||||
}
|
||||
|
||||
fn iv_from_transaction(transaction: &SignedTransaction) -> H128 {
|
||||
let nonce = keccak(&transaction.nonce.rlp_bytes());
|
||||
let (iv, _) = nonce.split_at(INIT_VEC_LEN);
|
||||
H128::from_slice(iv)
|
||||
}
|
||||
|
||||
fn iv_from_address(contract_address: &Address) -> H128 {
|
||||
let address = keccak(&contract_address.rlp_bytes());
|
||||
let (iv, _) = address.split_at(INIT_VEC_LEN);
|
||||
H128::from_slice(iv)
|
||||
}
|
||||
|
||||
fn encrypt(&self, contract_address: &Address, initialisation_vector: &H128, data: &[u8]) -> Result<Bytes, Error> {
|
||||
trace!("Encrypt data using key(address): {:?}", contract_address);
|
||||
Ok(self.encryptor.encrypt(contract_address, &*self.accounts, initialisation_vector, data)?)
|
||||
}
|
||||
|
||||
fn decrypt(&self, contract_address: &Address, data: &[u8]) -> Result<Bytes, Error> {
|
||||
trace!("Decrypt data using key(address): {:?}", contract_address);
|
||||
Ok(self.encryptor.decrypt(contract_address, &*self.accounts, data)?)
|
||||
}
|
||||
|
||||
fn get_decrypted_state(&self, address: &Address, block: BlockId) -> Result<Bytes, Error> {
|
||||
let contract = private::PrivateContract::default();
|
||||
let state = contract.functions()
|
||||
.state()
|
||||
.call(&|data| self.client.call_contract(block, *address, data))
|
||||
.map_err(|e| ErrorKind::Call(format!("Contract call failed {:?}", e)))?;
|
||||
|
||||
self.decrypt(address, &state)
|
||||
}
|
||||
|
||||
fn get_decrypted_code(&self, address: &Address, block: BlockId) -> Result<Bytes, Error> {
|
||||
let contract = private::PrivateContract::default();
|
||||
let code = contract.functions()
|
||||
.code()
|
||||
.call(&|data| self.client.call_contract(block, *address, data))
|
||||
.map_err(|e| ErrorKind::Call(format!("Contract call failed {:?}", e)))?;
|
||||
|
||||
self.decrypt(address, &code)
|
||||
}
|
||||
|
||||
pub fn get_contract_nonce(&self, address: &Address, block: BlockId) -> Result<U256, Error> {
|
||||
let contract = private::PrivateContract::default();
|
||||
Ok(contract.functions()
|
||||
.nonce()
|
||||
.call(&|data| self.client.call_contract(block, *address, data))
|
||||
.map_err(|e| ErrorKind::Call(format!("Contract call failed {:?}", e)))?)
|
||||
}
|
||||
|
||||
fn snapshot_to_storage(raw: Bytes) -> HashMap<H256, H256> {
|
||||
let items = raw.len() / 64;
|
||||
(0..items).map(|i| {
|
||||
let offset = i * 64;
|
||||
let key = H256::from_slice(&raw[offset..(offset + 32)]);
|
||||
let value = H256::from_slice(&raw[(offset + 32)..(offset + 64)]);
|
||||
(key, value)
|
||||
}).collect()
|
||||
}
|
||||
|
||||
fn snapshot_from_storage(storage: &HashMap<H256, H256>) -> Bytes {
|
||||
let mut raw = Vec::with_capacity(storage.len() * 64);
|
||||
for (key, value) in storage {
|
||||
raw.extend_from_slice(key);
|
||||
raw.extend_from_slice(value);
|
||||
};
|
||||
raw
|
||||
}
|
||||
|
||||
pub fn execute_private<T, V>(&self, transaction: &SignedTransaction, options: TransactOptions<T, V>, block: BlockId) -> Result<PrivateExecutionResult<T, V>, Error>
|
||||
where
|
||||
T: Tracer,
|
||||
V: VMTracer,
|
||||
{
|
||||
let mut env_info = self.client.env_info(block).ok_or(ErrorKind::StatePruned)?;
|
||||
env_info.gas_limit = transaction.gas;
|
||||
|
||||
let mut state = self.client.state_at(block).ok_or(ErrorKind::StatePruned)?;
|
||||
// TODO: in case of BlockId::Latest these need to operate on the same state
|
||||
let contract_address = match transaction.action {
|
||||
Action::Call(ref contract_address) => {
|
||||
let contract_code = Arc::new(self.get_decrypted_code(contract_address, block)?);
|
||||
let contract_state = self.get_decrypted_state(contract_address, block)?;
|
||||
trace!("Patching contract at {:?}, code: {:?}, state: {:?}", contract_address, contract_code, contract_state);
|
||||
state.patch_account(contract_address, contract_code, Self::snapshot_to_storage(contract_state))?;
|
||||
Some(*contract_address)
|
||||
},
|
||||
Action::Create => None,
|
||||
};
|
||||
|
||||
let engine = self.client.engine();
|
||||
let contract_address = contract_address.or({
|
||||
let sender = transaction.sender();
|
||||
let nonce = state.nonce(&sender)?;
|
||||
let (new_address, _) = ethcore_contract_address(engine.create_address_scheme(env_info.number), &sender, &nonce, &transaction.data);
|
||||
Some(new_address)
|
||||
});
|
||||
let result = Executive::new(&mut state, &env_info, engine.machine()).transact_virtual(transaction, options)?;
|
||||
let (encrypted_code, encrypted_storage) = match contract_address {
|
||||
None => bail!(ErrorKind::ContractDoesNotExist),
|
||||
Some(address) => {
|
||||
let (code, storage) = state.into_account(&address)?;
|
||||
let enc_code = match code {
|
||||
Some(c) => Some(self.encrypt(&address, &Self::iv_from_address(&address), &c)?),
|
||||
None => None,
|
||||
};
|
||||
(enc_code, self.encrypt(&address, &Self::iv_from_transaction(transaction), &Self::snapshot_from_storage(&storage))?)
|
||||
},
|
||||
};
|
||||
trace!("Private contract executed. code: {:?}, state: {:?}, result: {:?}", encrypted_code, encrypted_storage, result.output);
|
||||
Ok(PrivateExecutionResult {
|
||||
code: encrypted_code,
|
||||
state: encrypted_storage,
|
||||
contract_address,
|
||||
result,
|
||||
})
|
||||
}
|
||||
|
||||
fn generate_constructor(validators: &[Address], code: Bytes, storage: Bytes) -> Bytes {
|
||||
let constructor_code = DEFAULT_STUB_CONTRACT.from_hex().expect("Default contract code is valid");
|
||||
let private = private::PrivateContract::default();
|
||||
private.constructor(constructor_code, validators.iter().map(|a| *a).collect::<Vec<Address>>(), code, storage)
|
||||
}
|
||||
|
||||
fn generate_set_state_call(signatures: &[Signature], storage: Bytes) -> Bytes {
|
||||
let private = private::PrivateContract::default();
|
||||
private.functions().set_state().input(
|
||||
storage,
|
||||
signatures.iter().map(|s| {
|
||||
let mut v: [u8; 32] = [0; 32];
|
||||
v[31] = s.v();
|
||||
v
|
||||
}).collect::<Vec<[u8; 32]>>(),
|
||||
signatures.iter().map(|s| s.r()).collect::<Vec<&[u8]>>(),
|
||||
signatures.iter().map(|s| s.s()).collect::<Vec<&[u8]>>()
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the key from the key server associated with the contract
|
||||
pub fn contract_key_id(&self, contract_address: &Address) -> Result<H256, Error> {
|
||||
//current solution uses contract address extended with 0 as id
|
||||
let contract_address_extended: H256 = contract_address.into();
|
||||
|
||||
Ok(H256::from_slice(&contract_address_extended))
|
||||
}
|
||||
|
||||
/// Create encrypted public contract deployment transaction.
|
||||
pub fn public_creation_transaction(&self, block: BlockId, source: &SignedTransaction, validators: &[Address], gas_price: U256) -> Result<(Transaction, Option<Address>), Error> {
|
||||
if let Action::Call(_) = source.action {
|
||||
bail!(ErrorKind::BadTransactonType);
|
||||
}
|
||||
let sender = source.sender();
|
||||
let state = self.client.state_at(block).ok_or(ErrorKind::StatePruned)?;
|
||||
let nonce = state.nonce(&sender)?;
|
||||
let executed = self.execute_private(source, TransactOptions::with_no_tracing(), block)?;
|
||||
let gas: u64 = 650000 +
|
||||
validators.len() as u64 * 30000 +
|
||||
executed.code.as_ref().map_or(0, |c| c.len() as u64) * 8000 +
|
||||
executed.state.len() as u64 * 8000;
|
||||
Ok((Transaction {
|
||||
nonce: nonce,
|
||||
action: Action::Create,
|
||||
gas: gas.into(),
|
||||
gas_price: gas_price,
|
||||
value: source.value,
|
||||
data: Self::generate_constructor(validators, executed.code.unwrap_or_default(), executed.state)
|
||||
},
|
||||
executed.contract_address))
|
||||
}
|
||||
|
||||
/// Create encrypted public contract deployment transaction. Returns updated encrypted state.
|
||||
pub fn execute_private_transaction(&self, block: BlockId, source: &SignedTransaction) -> Result<Bytes, Error> {
|
||||
if let Action::Create = source.action {
|
||||
bail!(ErrorKind::BadTransactonType);
|
||||
}
|
||||
let result = self.execute_private(source, TransactOptions::with_no_tracing(), block)?;
|
||||
Ok(result.state)
|
||||
}
|
||||
|
||||
/// Create encrypted public transaction from private transaction.
|
||||
pub fn public_transaction(&self, state: Bytes, source: &SignedTransaction, signatures: &[Signature], nonce: U256, gas_price: U256) -> Result<Transaction, Error> {
|
||||
let gas: u64 = 650000 + state.len() as u64 * 8000 + signatures.len() as u64 * 50000;
|
||||
Ok(Transaction {
|
||||
nonce: nonce,
|
||||
action: source.action.clone(),
|
||||
gas: gas.into(),
|
||||
gas_price: gas_price,
|
||||
value: 0.into(),
|
||||
data: Self::generate_set_state_call(signatures, state)
|
||||
})
|
||||
}
|
||||
|
||||
/// Call into private contract.
|
||||
pub fn private_call(&self, block: BlockId, transaction: &SignedTransaction) -> Result<Executed, Error> {
|
||||
let result = self.execute_private(transaction, TransactOptions::with_no_tracing(), block)?;
|
||||
Ok(result.result)
|
||||
}
|
||||
|
||||
/// Returns private validators for a contract.
|
||||
pub fn get_validators(&self, block: BlockId, address: &Address) -> Result<Vec<Address>, Error> {
|
||||
let contract = private::PrivateContract::default();
|
||||
Ok(contract.functions()
|
||||
.get_validators()
|
||||
.call(&|data| self.client.call_contract(block, *address, data))
|
||||
.map_err(|e| ErrorKind::Call(format!("Contract call failed {:?}", e)))?)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Importer {
|
||||
/// Process received private transaction
|
||||
fn import_private_transaction(&self, _rlp: &[u8]) -> Result<(), Error>;
|
||||
|
||||
/// Add signed private transaction into the store
|
||||
///
|
||||
/// Creates corresponding public transaction if last required signature collected and sends it to the chain
|
||||
fn import_signed_private_transaction(&self, _rlp: &[u8]) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
// TODO [ToDr] Offload more heavy stuff to the IoService thread.
|
||||
// It seems that a lot of heavy work (verification) is done in this thread anyway
|
||||
// it might actually make sense to decouple it from clientService and just use dedicated thread
|
||||
// for both verification and execution.
|
||||
|
||||
impl Importer for Arc<Provider> {
|
||||
fn import_private_transaction(&self, rlp: &[u8]) -> Result<(), Error> {
|
||||
trace!("Private transaction received");
|
||||
let private_tx: PrivateTransaction = Rlp::new(rlp).as_val()?;
|
||||
let contract = private_tx.contract;
|
||||
let contract_validators = self.get_validators(BlockId::Latest, &contract)?;
|
||||
|
||||
let validation_account = contract_validators
|
||||
.iter()
|
||||
.find(|address| self.validator_accounts.contains(address));
|
||||
|
||||
match validation_account {
|
||||
None => {
|
||||
// TODO [ToDr] This still seems a bit invalid, imho we should still import the transaction to the pool.
|
||||
// Importing to pool verifies correctness and nonce; here we are just blindly forwarding.
|
||||
//
|
||||
// Not for verification, broadcast further to peers
|
||||
self.broadcast_private_transaction(rlp.into());
|
||||
return Ok(());
|
||||
},
|
||||
Some(&validation_account) => {
|
||||
let hash = private_tx.hash();
|
||||
trace!("Private transaction taken for verification");
|
||||
let original_tx = self.extract_original_transaction(private_tx, &contract)?;
|
||||
trace!("Validating transaction: {:?}", original_tx);
|
||||
// Verify with the first account available
|
||||
trace!("The following account will be used for verification: {:?}", validation_account);
|
||||
let nonce_cache = NonceCache::new(NONCE_CACHE_SIZE);
|
||||
self.transactions_for_verification.lock().add_transaction(
|
||||
original_tx,
|
||||
contract,
|
||||
validation_account,
|
||||
hash,
|
||||
self.pool_client(&nonce_cache),
|
||||
)?;
|
||||
let provider = Arc::downgrade(self);
|
||||
self.channel.send(ClientIoMessage::execute(move |_| {
|
||||
if let Some(provider) = provider.upgrade() {
|
||||
if let Err(e) = provider.process_queue() {
|
||||
debug!("Unable to process the queue: {}", e);
|
||||
}
|
||||
}
|
||||
})).map_err(|_| ErrorKind::ClientIsMalformed.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn import_signed_private_transaction(&self, rlp: &[u8]) -> Result<(), Error> {
|
||||
let tx: SignedPrivateTransaction = Rlp::new(rlp).as_val()?;
|
||||
trace!("Signature for private transaction received: {:?}", tx);
|
||||
let private_hash = tx.private_transaction_hash();
|
||||
let desc = match self.transactions_for_signing.lock().get(&private_hash) {
|
||||
None => {
|
||||
// TODO [ToDr] Verification (we can't just blindly forward every transaction)
|
||||
|
||||
// Not our transaction, broadcast further to peers
|
||||
self.broadcast_signed_private_transaction(rlp.into());
|
||||
return Ok(());
|
||||
},
|
||||
Some(desc) => desc,
|
||||
};
|
||||
|
||||
let last = self.last_required_signature(&desc, tx.signature())?;
|
||||
|
||||
if last {
|
||||
let mut signatures = desc.received_signatures.clone();
|
||||
signatures.push(tx.signature());
|
||||
let rsv: Vec<Signature> = signatures.into_iter().map(|sign| sign.into_electrum().into()).collect();
|
||||
//Create public transaction
|
||||
let public_tx = self.public_transaction(
|
||||
desc.state.clone(),
|
||||
&desc.original_transaction,
|
||||
&rsv,
|
||||
desc.original_transaction.nonce,
|
||||
desc.original_transaction.gas_price
|
||||
)?;
|
||||
trace!("Last required signature received, public transaction created: {:?}", public_tx);
|
||||
//Sign and add it to the queue
|
||||
let chain_id = desc.original_transaction.chain_id();
|
||||
let hash = public_tx.hash(chain_id);
|
||||
let signer_account = self.signer_account.ok_or_else(|| ErrorKind::SignerAccountNotSet)?;
|
||||
let password = find_account_password(&self.passwords, &*self.accounts, &signer_account);
|
||||
let signature = self.accounts.sign(signer_account, password, hash)?;
|
||||
let signed = SignedTransaction::new(public_tx.with_signature(signature, chain_id))?;
|
||||
match self.miner.import_own_transaction(&*self.client, signed.into()) {
|
||||
Ok(_) => trace!("Public transaction added to queue"),
|
||||
Err(err) => {
|
||||
trace!("Failed to add transaction to queue, error: {:?}", err);
|
||||
bail!(err);
|
||||
}
|
||||
}
|
||||
//Remove from store for signing
|
||||
match self.transactions_for_signing.lock().remove(&private_hash) {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
trace!("Failed to remove transaction from signing store, error: {:?}", err);
|
||||
bail!(err);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//Add signature to the store
|
||||
match self.transactions_for_signing.lock().add_signature(&private_hash, tx.signature()) {
|
||||
Ok(_) => trace!("Signature stored for private transaction"),
|
||||
Err(err) => {
|
||||
trace!("Failed to add signature to signing store, error: {:?}", err);
|
||||
bail!(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to unlock account using stored password, return found password if any
|
||||
fn find_account_password(passwords: &Vec<String>, account_provider: &AccountProvider, account: &Address) -> Option<String> {
|
||||
for password in passwords {
|
||||
if let Ok(true) = account_provider.test_password(account, password) {
|
||||
return Some(password.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
impl ChainNotify for Provider {
|
||||
fn new_blocks(&self, imported: Vec<H256>, _invalid: Vec<H256>, _route: ChainRoute, _sealed: Vec<H256>, _proposed: Vec<Bytes>, _duration: Duration) {
|
||||
if !imported.is_empty() {
|
||||
trace!("New blocks imported, try to prune the queue");
|
||||
if let Err(err) = self.process_queue() {
|
||||
trace!("Cannot prune private transactions queue. error: {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
76
ethcore/private-tx/src/messages.rs
Normal file
76
ethcore/private-tx/src/messages.rs
Normal file
@@ -0,0 +1,76 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use ethereum_types::{H256, U256, Address};
|
||||
use bytes::Bytes;
|
||||
use hash::keccak;
|
||||
use rlp::Encodable;
|
||||
use ethkey::Signature;
|
||||
use transaction::signature::{add_chain_replay_protection, check_replay_protection};
|
||||
|
||||
/// Message with private transaction encrypted
|
||||
#[derive(Default, Debug, Clone, PartialEq, RlpEncodable, RlpDecodable, Eq)]
|
||||
pub struct PrivateTransaction {
|
||||
/// Encrypted data
|
||||
pub encrypted: Bytes,
|
||||
/// Address of the contract
|
||||
pub contract: Address,
|
||||
}
|
||||
|
||||
impl PrivateTransaction {
|
||||
/// Compute hash on private transaction
|
||||
pub fn hash(&self) -> H256 {
|
||||
keccak(&*self.rlp_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
/// Message about private transaction's signing
|
||||
#[derive(Default, Debug, Clone, PartialEq, RlpEncodable, RlpDecodable, Eq)]
|
||||
pub struct SignedPrivateTransaction {
|
||||
/// Hash of the corresponding private transaction
|
||||
private_transaction_hash: H256,
|
||||
/// Signature of the validator
|
||||
/// The V field of the signature
|
||||
v: u64,
|
||||
/// The R field of the signature
|
||||
r: U256,
|
||||
/// The S field of the signature
|
||||
s: U256,
|
||||
}
|
||||
|
||||
impl SignedPrivateTransaction {
|
||||
/// Construct a signed private transaction message
|
||||
pub fn new(private_transaction_hash: H256, sig: Signature, chain_id: Option<u64>) -> Self {
|
||||
SignedPrivateTransaction {
|
||||
private_transaction_hash: private_transaction_hash,
|
||||
r: sig.r().into(),
|
||||
s: sig.s().into(),
|
||||
v: add_chain_replay_protection(sig.v() as u64, chain_id),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn standard_v(&self) -> u8 { check_replay_protection(self.v) }
|
||||
|
||||
/// Construct a signature object from the sig.
|
||||
pub fn signature(&self) -> Signature {
|
||||
Signature::from_rsv(&self.r.into(), &self.s.into(), self.standard_v())
|
||||
}
|
||||
|
||||
/// Get the hash of of the original transaction.
|
||||
pub fn private_transaction_hash(&self) -> H256 {
|
||||
self.private_transaction_hash
|
||||
}
|
||||
}
|
||||
208
ethcore/private-tx/src/private_transactions.rs
Normal file
208
ethcore/private-tx/src/private_transactions.rs
Normal file
@@ -0,0 +1,208 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use bytes::Bytes;
|
||||
use ethcore_miner::pool;
|
||||
use ethereum_types::{H256, U256, Address};
|
||||
use ethkey::Signature;
|
||||
use transaction::{UnverifiedTransaction, SignedTransaction};
|
||||
|
||||
use error::{Error, ErrorKind};
|
||||
|
||||
/// Maximum length for private transactions queues.
|
||||
const MAX_QUEUE_LEN: usize = 8312;
|
||||
|
||||
/// Desriptor for private transaction stored in queue for verification
|
||||
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct PrivateTransactionDesc {
|
||||
/// Hash of the private transaction
|
||||
pub private_hash: H256,
|
||||
/// Contract's address used in private transaction
|
||||
pub contract: Address,
|
||||
/// Address that should be used for verification
|
||||
pub validator_account: Address,
|
||||
}
|
||||
|
||||
/// Storage for private transactions for verification
|
||||
pub struct VerificationStore {
|
||||
/// Descriptors for private transactions in queue for verification with key - hash of the original transaction
|
||||
descriptors: HashMap<H256, PrivateTransactionDesc>,
|
||||
/// Queue with transactions for verification
|
||||
///
|
||||
/// TODO [ToDr] Might actually be better to use `txpool` directly and:
|
||||
/// 1. Store descriptors inside `VerifiedTransaction`
|
||||
/// 2. Use custom `ready` implementation to only fetch one transaction per sender.
|
||||
/// 3. Get rid of passing dummy `block_number` and `timestamp`
|
||||
transactions: pool::TransactionQueue,
|
||||
}
|
||||
|
||||
impl Default for VerificationStore {
|
||||
fn default() -> Self {
|
||||
VerificationStore {
|
||||
descriptors: Default::default(),
|
||||
transactions: pool::TransactionQueue::new(
|
||||
pool::Options {
|
||||
max_count: MAX_QUEUE_LEN,
|
||||
max_per_sender: MAX_QUEUE_LEN / 10,
|
||||
max_mem_usage: 8 * 1024 * 1024,
|
||||
},
|
||||
pool::verifier::Options {
|
||||
// TODO [ToDr] This should probably be based on some real values?
|
||||
minimal_gas_price: 0.into(),
|
||||
block_gas_limit: 8_000_000.into(),
|
||||
tx_gas_limit: U256::max_value(),
|
||||
},
|
||||
pool::PrioritizationStrategy::GasPriceOnly,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VerificationStore {
|
||||
/// Adds private transaction for verification into the store
|
||||
pub fn add_transaction<C: pool::client::Client>(
|
||||
&mut self,
|
||||
transaction: UnverifiedTransaction,
|
||||
contract: Address,
|
||||
validator_account: Address,
|
||||
private_hash: H256,
|
||||
client: C,
|
||||
) -> Result<(), Error> {
|
||||
if self.descriptors.len() > MAX_QUEUE_LEN {
|
||||
bail!(ErrorKind::QueueIsFull);
|
||||
}
|
||||
|
||||
let transaction_hash = transaction.hash();
|
||||
if self.descriptors.get(&transaction_hash).is_some() {
|
||||
bail!(ErrorKind::PrivateTransactionAlreadyImported);
|
||||
}
|
||||
|
||||
let results = self.transactions.import(
|
||||
client,
|
||||
vec![pool::verifier::Transaction::Unverified(transaction)],
|
||||
);
|
||||
|
||||
// Verify that transaction was imported
|
||||
results.into_iter()
|
||||
.next()
|
||||
.expect("One transaction inserted; one result returned; qed")?;
|
||||
|
||||
self.descriptors.insert(transaction_hash, PrivateTransactionDesc {
|
||||
private_hash,
|
||||
contract,
|
||||
validator_account,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns transactions ready for verification
|
||||
/// Returns only one transaction per sender because several cannot be verified in a row without verification from other peers
|
||||
pub fn ready_transactions<C: pool::client::NonceClient>(&self, client: C) -> Vec<Arc<pool::VerifiedTransaction>> {
|
||||
// We never store PendingTransactions and we don't use internal cache,
|
||||
// so we don't need to provide real block number of timestamp here
|
||||
let block_number = 0;
|
||||
let timestamp = 0;
|
||||
let nonce_cap = None;
|
||||
|
||||
self.transactions.collect_pending(client, block_number, timestamp, nonce_cap, |transactions| {
|
||||
// take only one transaction per sender
|
||||
let mut senders = HashSet::with_capacity(self.descriptors.len());
|
||||
transactions.filter(move |tx| senders.insert(tx.signed().sender())).collect()
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns descriptor of the corresponding private transaction
|
||||
pub fn private_transaction_descriptor(&self, transaction_hash: &H256) -> Result<&PrivateTransactionDesc, Error> {
|
||||
self.descriptors.get(transaction_hash).ok_or(ErrorKind::PrivateTransactionNotFound.into())
|
||||
}
|
||||
|
||||
/// Remove transaction from the queue for verification
|
||||
pub fn remove_private_transaction(&mut self, transaction_hash: &H256) {
|
||||
self.descriptors.remove(transaction_hash);
|
||||
self.transactions.remove(&[*transaction_hash], true);
|
||||
}
|
||||
}
|
||||
|
||||
/// Desriptor for private transaction stored in queue for signing
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PrivateTransactionSigningDesc {
|
||||
/// Original unsigned transaction
|
||||
pub original_transaction: SignedTransaction,
|
||||
/// Supposed validators from the contract
|
||||
pub validators: Vec<Address>,
|
||||
/// Already obtained signatures
|
||||
pub received_signatures: Vec<Signature>,
|
||||
/// State after transaction execution to compare further with received from validators
|
||||
pub state: Bytes,
|
||||
/// Build-in nonce of the contract
|
||||
pub contract_nonce: U256,
|
||||
}
|
||||
|
||||
/// Storage for private transactions for signing
|
||||
#[derive(Default)]
|
||||
pub struct SigningStore {
|
||||
/// Transactions and descriptors for signing
|
||||
transactions: HashMap<H256, PrivateTransactionSigningDesc>,
|
||||
}
|
||||
|
||||
impl SigningStore {
|
||||
/// Adds new private transaction into the store for signing
|
||||
pub fn add_transaction(
|
||||
&mut self,
|
||||
private_hash: H256,
|
||||
transaction: SignedTransaction,
|
||||
validators: Vec<Address>,
|
||||
state: Bytes,
|
||||
contract_nonce: U256,
|
||||
) -> Result<(), Error> {
|
||||
if self.transactions.len() > MAX_QUEUE_LEN {
|
||||
bail!(ErrorKind::QueueIsFull);
|
||||
}
|
||||
|
||||
self.transactions.insert(private_hash, PrivateTransactionSigningDesc {
|
||||
original_transaction: transaction.clone(),
|
||||
validators: validators.clone(),
|
||||
received_signatures: Vec::new(),
|
||||
state,
|
||||
contract_nonce,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get copy of private transaction's description from the storage
|
||||
pub fn get(&self, private_hash: &H256) -> Option<PrivateTransactionSigningDesc> {
|
||||
self.transactions.get(private_hash).cloned()
|
||||
}
|
||||
|
||||
/// Removes desc from the store (after verification is completed)
|
||||
pub fn remove(&mut self, private_hash: &H256) -> Result<(), Error> {
|
||||
self.transactions.remove(private_hash);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Adds received signature for the stored private transaction
|
||||
pub fn add_signature(&mut self, private_hash: &H256, signature: Signature) -> Result<(), Error> {
|
||||
let desc = self.transactions.get_mut(private_hash).ok_or_else(|| ErrorKind::PrivateTransactionNotFound)?;
|
||||
if !desc.received_signatures.contains(&signature) {
|
||||
desc.received_signatures.push(signature);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
146
ethcore/private-tx/tests/private_contract.rs
Normal file
146
ethcore/private-tx/tests/private_contract.rs
Normal file
@@ -0,0 +1,146 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Contract for private transactions tests.
|
||||
|
||||
extern crate rustc_hex;
|
||||
extern crate ethcore;
|
||||
extern crate ethkey;
|
||||
extern crate keccak_hash as hash;
|
||||
extern crate ethcore_io;
|
||||
extern crate ethcore_logger;
|
||||
extern crate ethcore_private_tx;
|
||||
extern crate ethcore_transaction;
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
use std::sync::Arc;
|
||||
use rustc_hex::FromHex;
|
||||
|
||||
use ethcore::CreateContractAddress;
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use ethcore::client::BlockChainClient;
|
||||
use ethcore::client::BlockId;
|
||||
use ethcore::executive::{contract_address};
|
||||
use ethcore::miner::Miner;
|
||||
use ethcore::test_helpers::{generate_dummy_client, push_block_with_transactions};
|
||||
use ethcore_transaction::{Transaction, Action};
|
||||
use ethkey::{Secret, KeyPair, Signature};
|
||||
use hash::keccak;
|
||||
|
||||
use ethcore_private_tx::{NoopEncryptor, Provider, ProviderConfig};
|
||||
|
||||
#[test]
|
||||
fn private_contract() {
|
||||
// This uses a simple private contract: contract Test1 { bytes32 public x; function setX(bytes32 _x) { x = _x; } }
|
||||
ethcore_logger::init_log();
|
||||
let client = generate_dummy_client(0);
|
||||
let chain_id = client.signing_chain_id();
|
||||
let key1 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000011")).unwrap();
|
||||
let _key2 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000012")).unwrap();
|
||||
let key3 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000013")).unwrap();
|
||||
let key4 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000014")).unwrap();
|
||||
let ap = Arc::new(AccountProvider::transient_provider());
|
||||
ap.insert_account(key1.secret().clone(), "").unwrap();
|
||||
ap.insert_account(key3.secret().clone(), "").unwrap();
|
||||
ap.insert_account(key4.secret().clone(), "").unwrap();
|
||||
|
||||
let config = ProviderConfig{
|
||||
validator_accounts: vec![key3.address(), key4.address()],
|
||||
signer_account: None,
|
||||
passwords: vec!["".into()],
|
||||
};
|
||||
|
||||
let io = ethcore_io::IoChannel::disconnected();
|
||||
let miner = Arc::new(Miner::new_for_tests(&::ethcore::spec::Spec::new_test(), None));
|
||||
let pm = Arc::new(Provider::new(
|
||||
client.clone(),
|
||||
miner,
|
||||
ap.clone(),
|
||||
Box::new(NoopEncryptor::default()),
|
||||
config,
|
||||
io,
|
||||
));
|
||||
|
||||
let (address, _) = contract_address(CreateContractAddress::FromSenderAndNonce, &key1.address(), &0.into(), &[]);
|
||||
|
||||
trace!("Creating private contract");
|
||||
let private_contract_test = "6060604052341561000f57600080fd5b60d88061001d6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630c55699c146046578063bc64b76d14607457600080fd5b3415605057600080fd5b60566098565b60405180826000191660001916815260200191505060405180910390f35b3415607e57600080fd5b6096600480803560001916906020019091905050609e565b005b60005481565b8060008160001916905550505600a165627a7a723058206acbdf4b15ca4c2d43e1b1879b830451a34f1e9d02ff1f2f394d8d857e79d2080029".from_hex().unwrap();
|
||||
let mut private_create_tx = Transaction::default();
|
||||
private_create_tx.action = Action::Create;
|
||||
private_create_tx.data = private_contract_test;
|
||||
private_create_tx.gas = 200000.into();
|
||||
let private_create_tx_signed = private_create_tx.sign(&key1.secret(), None);
|
||||
let validators = vec![key3.address(), key4.address()];
|
||||
let (public_tx, _) = pm.public_creation_transaction(BlockId::Latest, &private_create_tx_signed, &validators, 0.into()).unwrap();
|
||||
let public_tx = public_tx.sign(&key1.secret(), chain_id);
|
||||
trace!("Transaction created. Pushing block");
|
||||
push_block_with_transactions(&client, &[public_tx]);
|
||||
|
||||
trace!("Modifying private state");
|
||||
let mut private_tx = Transaction::default();
|
||||
private_tx.action = Action::Call(address.clone());
|
||||
private_tx.data = "bc64b76d2a00000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap(); //setX(42)
|
||||
private_tx.gas = 120000.into();
|
||||
private_tx.nonce = 1.into();
|
||||
let private_tx = private_tx.sign(&key1.secret(), None);
|
||||
let private_contract_nonce = pm.get_contract_nonce(&address, BlockId::Latest).unwrap();
|
||||
let private_state = pm.execute_private_transaction(BlockId::Latest, &private_tx).unwrap();
|
||||
let nonced_state_hash = pm.calculate_state_hash(&private_state, private_contract_nonce);
|
||||
let signatures: Vec<_> = [&key3, &key4].iter().map(|k|
|
||||
Signature::from(::ethkey::sign(&k.secret(), &nonced_state_hash).unwrap().into_electrum())).collect();
|
||||
let public_tx = pm.public_transaction(private_state, &private_tx, &signatures, 1.into(), 0.into()).unwrap();
|
||||
let public_tx = public_tx.sign(&key1.secret(), chain_id);
|
||||
push_block_with_transactions(&client, &[public_tx]);
|
||||
|
||||
trace!("Querying private state");
|
||||
let mut query_tx = Transaction::default();
|
||||
query_tx.action = Action::Call(address.clone());
|
||||
query_tx.data = "0c55699c".from_hex().unwrap(); // getX
|
||||
query_tx.gas = 50000.into();
|
||||
query_tx.nonce = 2.into();
|
||||
let query_tx = query_tx.sign(&key1.secret(), chain_id);
|
||||
let result = pm.private_call(BlockId::Latest, &query_tx).unwrap();
|
||||
assert_eq!(&result.output[..], &("2a00000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap()[..]));
|
||||
assert_eq!(pm.get_validators(BlockId::Latest, &address).unwrap(), validators);
|
||||
|
||||
// Now try modification with just one signature
|
||||
trace!("Modifying private state");
|
||||
let mut private_tx = Transaction::default();
|
||||
private_tx.action = Action::Call(address.clone());
|
||||
private_tx.data = "bc64b76d2b00000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap(); //setX(43)
|
||||
private_tx.gas = 120000.into();
|
||||
private_tx.nonce = 2.into();
|
||||
let private_tx = private_tx.sign(&key1.secret(), None);
|
||||
let private_state = pm.execute_private_transaction(BlockId::Latest, &private_tx).unwrap();
|
||||
let private_state_hash = keccak(&private_state);
|
||||
let signatures: Vec<_> = [&key4].iter().map(|k|
|
||||
Signature::from(::ethkey::sign(&k.secret(), &private_state_hash).unwrap().into_electrum())).collect();
|
||||
let public_tx = pm.public_transaction(private_state, &private_tx, &signatures, 2.into(), 0.into()).unwrap();
|
||||
let public_tx = public_tx.sign(&key1.secret(), chain_id);
|
||||
push_block_with_transactions(&client, &[public_tx]);
|
||||
|
||||
trace!("Querying private state");
|
||||
let mut query_tx = Transaction::default();
|
||||
query_tx.action = Action::Call(address.clone());
|
||||
query_tx.data = "0c55699c".from_hex().unwrap(); // getX
|
||||
query_tx.gas = 50000.into();
|
||||
query_tx.nonce = 3.into();
|
||||
let query_tx = query_tx.sign(&key1.secret(), chain_id);
|
||||
let result = pm.private_call(BlockId::Latest, &query_tx).unwrap();
|
||||
assert_eq!(result.output, "2a00000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap());
|
||||
}
|
||||
61
ethcore/res/authority_round_block_reward_contract.json
Normal file
61
ethcore/res/authority_round_block_reward_contract.json
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"name": "TestAuthorityRoundBlockRewardContract",
|
||||
"engine": {
|
||||
"authorityRound": {
|
||||
"params": {
|
||||
"stepDuration": 1,
|
||||
"startStep": 2,
|
||||
"validators": {
|
||||
"list": [
|
||||
"0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e",
|
||||
"0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1"
|
||||
]
|
||||
},
|
||||
"immediateTransitions": true,
|
||||
"emptyStepsTransition": "1",
|
||||
"maximumEmptySteps": "2",
|
||||
"blockRewardContractAddress": "0x0000000000000000000000000000000000000042"
|
||||
}
|
||||
}
|
||||
},
|
||||
"params": {
|
||||
"gasLimitBoundDivisor": "0x0400",
|
||||
"accountStartNonce": "0x0",
|
||||
"maximumExtraDataSize": "0x20",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID" : "0x69",
|
||||
"eip140Transition": "0x0",
|
||||
"eip211Transition": "0x0",
|
||||
"eip214Transition": "0x0",
|
||||
"eip658Transition": "0x0"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
"authorityRound": {
|
||||
"step": "0x0",
|
||||
"signature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
},
|
||||
"difficulty": "0x20000",
|
||||
"author": "0x0000000000000000000000000000000000000000",
|
||||
"timestamp": "0x00",
|
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"extraData": "0x",
|
||||
"gasLimit": "0x222222"
|
||||
},
|
||||
"accounts": {
|
||||
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||
"0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||
"0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
|
||||
"0000000000000000000000000000000000000005": { "balance": "1", "builtin": { "name": "modexp", "activate_at": 0, "pricing": { "modexp": { "divisor": 20 } } } },
|
||||
"0000000000000000000000000000000000000006": { "balance": "1", "builtin": { "name": "alt_bn128_add", "activate_at": 0, "pricing": { "linear": { "base": 500, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000007": { "balance": "1", "builtin": { "name": "alt_bn128_mul", "activate_at": 0, "pricing": { "linear": { "base": 40000, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000008": { "balance": "1", "builtin": { "name": "alt_bn128_pairing", "activate_at": 0, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } },
|
||||
"9cce34f7ab185c7aba1b7c8140d620b4bda941d6": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" },
|
||||
"0000000000000000000000000000000000000042": {
|
||||
"balance": "1",
|
||||
"constructor": "6060604052341561000f57600080fd5b6102b88061001e6000396000f300606060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063f91c289814610046575b600080fd5b341561005157600080fd5b610086600480803590602001908201803590602001919091929080359060200190820180359060200191909192905050610125565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156100cd5780820151818401526020810190506100b2565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561010f5780820151818401526020810190506100f4565b5050505090500194505050505060405180910390f35b61012d610264565b610135610278565b61013d610278565b600073fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561018d57600080fd5b85859050888890501415156101a157600080fd5b878790506040518059106101b25750595b90808252806020026020018201604052509150600090505b815181101561021d5785858281811015156101e157fe5b9050602002013561ffff166103e80161ffff16828281518110151561020257fe5b906020019060200201818152505080806001019150506101ca565b878783828280806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050915090915093509350505094509492505050565b602060405190810160405280600081525090565b6020604051908101604052806000815250905600a165627a7a723058201da0f164e75517fb8baf51f030b904032cb748334938e7386f63025bfb23f3de0029"
|
||||
}
|
||||
}
|
||||
}
|
||||
29
ethcore/res/contracts/block_reward.json
Normal file
29
ethcore/res/contracts/block_reward.json
Normal file
@@ -0,0 +1,29 @@
|
||||
[
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "benefactors",
|
||||
"type": "address[]"
|
||||
},
|
||||
{
|
||||
"name": "kind",
|
||||
"type": "uint16[]"
|
||||
}
|
||||
],
|
||||
"name": "reward",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "address[]"
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256[]"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
}
|
||||
]
|
||||
File diff suppressed because it is too large
Load Diff
89
ethcore/res/ethereum/easthub.json
Normal file
89
ethcore/res/ethereum/easthub.json
Normal file
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"name": "Easthub",
|
||||
"dataDir": "easthub",
|
||||
"engine": {
|
||||
"Ethash": {
|
||||
"params": {
|
||||
"minimumDifficulty": "0x020000",
|
||||
"difficultyBoundDivisor": "0x0800",
|
||||
"durationLimit": "0x0d",
|
||||
"blockReward": "0x2B5E3AF16B1880000",
|
||||
"homesteadTransition": "0x0",
|
||||
"bombDefuseTransition": "0x0",
|
||||
"eip150Transition": "0x0",
|
||||
"eip160Transition": "0x0",
|
||||
"ecip1017EraRounds": 5000000,
|
||||
"eip161abcTransition": "0x7fffffffffffffff",
|
||||
"eip161dTransition": "0x7fffffffffffffff"
|
||||
}
|
||||
}
|
||||
},
|
||||
"params": {
|
||||
"gasLimitBoundDivisor": "0x0400",
|
||||
"registrar": "0x0000000000000000000000000000000000000000",
|
||||
"accountStartNonce": "0x00",
|
||||
"maximumExtraDataSize": "0x20",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID": "0x7",
|
||||
"chainID": "0x7",
|
||||
"eip155Transition": "0x0",
|
||||
"eip98Transition": "0x7fffffffffffff",
|
||||
"eip86Transition": "0x7fffffffffffff"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
"ethereum": {
|
||||
"nonce": "0x0000000000000042",
|
||||
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
},
|
||||
"difficulty": "0x0400000000",
|
||||
"author": "0x0000000000000000000000000000000000000000",
|
||||
"timestamp": "0x00",
|
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"extraData": "0x323031382045617374636f696e2050726f6a656374",
|
||||
"gasLimit": "0x1388"
|
||||
},
|
||||
"nodes": [
|
||||
"enode://ca57e40edb95a08a81b85a91e91099a0aaab777ad329ea7f3f772bc0fd511a276a5d84944725d181ff80f8c7dc1034814bff25b9723b03363d48617fed4b15f0@13.125.109.174:30303",
|
||||
"enode://57254e23a7e5fe1e081ee5d1b236e37735a120660daeb4bf1fec6943a82c915c5b6fad23eeb1a43a27c23f236e084e8051aaa28f7d4139149f844747facb62bb@18.217.39.51:30303",
|
||||
"enode://ef248f327c73c0318f4d51a62270b0612f3c4a4fd04b77d04854dc355980e137708d1e48811bc91387b0d7eb85cf447d8bbc095404f39bb7064e76751bda9cd4@52.221.160.236:30303",
|
||||
"enode://bf6f0e37dd733cf04f2b079c753d2dea7cc7c59d8637eff9a8e63e17d08e2bfc91229fbb2dff08fe6ee12e51c1b6f8ed969d7042b89d77029e7ea02b05e17be3@18.197.47.177:30303"
|
||||
],
|
||||
"accounts": {
|
||||
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||
"0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||
"0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
|
||||
"20c1252a8cb33a7a9a257b2a4cfeed8daf87c847": {
|
||||
"balance": "100000000000000000000000000"
|
||||
},
|
||||
"9dcd37c8e5aea3a0d37c5d0a2db683362d81febd": {
|
||||
"balance": "100000000000000000000000000"
|
||||
},
|
||||
"9eff080302333f44a60bfd8c33bd63015c6d921b": {
|
||||
"balance": "100000000000000000000000000"
|
||||
},
|
||||
"c1df2e5de98d5c41fec0642dc302971f5d3500bd": {
|
||||
"balance": "100000000000000000000000000"
|
||||
},
|
||||
"2e0fb67cd1d029cbaea4b74c361efcc06b3105fd": {
|
||||
"balance": "100000000000000000000000000"
|
||||
},
|
||||
"2b6425cc3cd90654f077889ef7262ac2f5846460": {
|
||||
"balance": "100000000000000000000000000"
|
||||
},
|
||||
"28562041230c6d575e233e4ed1b35c514884d964": {
|
||||
"balance": "100000000000000000000000000"
|
||||
},
|
||||
"16eb6896a5a83d39ac762d79d21f825f5f980d12": {
|
||||
"balance": "100000000000000000000000000"
|
||||
},
|
||||
"f09e3f1de27dd03a1ac0a021b2d9e45bde1b360c": {
|
||||
"balance": "100000000000000000000000000"
|
||||
},
|
||||
"2d87547819c6433f208ee3096161cdb2835a2333": {
|
||||
"balance": "100000000000000000000000000"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,21 +51,14 @@
|
||||
"gasLimit": "0x1388"
|
||||
},
|
||||
"nodes": [
|
||||
"enode://98b48cc7149326d00a57994ad55014a095a3e5cd4f0144cd7b034fb667d8e8017082bd90047d72c4403798b8ece11a33bd2e344d6500faba30889ebcfa5316fa@172.104.163.204:30303",
|
||||
"enode://0d88e242aa0b01ee306ca43e956174677c96ec8eba4197f4d8be6fd7d4f2e57731e95d533b88229b66eb1a44399d870e99b7a4fe6547c8c80cdf00407a986e14@94.130.237.158:30303",
|
||||
"enode://4be9e419d3efb0214faf3ef1794a0c33ebbd7633ece734a0a956faa166fefc496b2692a2a485adc66af805e461ba3e12f8d3941ec207e56bb9f3d3626787a705@94.130.237.158:60606",
|
||||
"enode://834246cc2a7584df29ccdcf3b5366f118a0e291264980376769e809665a02c4caf0d68c43eecf8390dbeaf861823b05583807af0a62542a1f3f717046b958a76@45.77.106.33:30303",
|
||||
"enode://d1373d7187a20d695220fafb5746a289786bad92469d6bbe800f07572f8f444479f507cfcb8fcd8f5bee5dd44efb6185df4a1e4f1a7170408ada9876ef5b3fe4@178.79.189.58:30303",
|
||||
"enode://d8059dcb137cb52b8960ca82613eeba1d121105572decd8f1d3ea22b09070645eeab548d2a3cd2914f206e1331c7870bd2bd5a231ebac6b3d4886ec3b8e627e5@173.212.216.105:30303",
|
||||
"enode://5a89c8664d29a321fd4cb1b55b0f0be832ce376b5e7feb14a2073fdbd9bd7b7394169ed289dd991112b42ecfb74ea36e436bc72a1c99dcdb50d96eaf3b0ed254@213.136.91.42:30303",
|
||||
"enode://9215ad77bd081e35013cb42a8ceadff9d8e94a78fcc680dff1752a54e7484badff0904e331c4b40a68be593782e55acfd800f076d22f9d2832e8483733ade149@213.14.82.125:30303",
|
||||
"enode://07913818dafbadf44d4fc796fa414ec1d720ecfb087eff37efbe7134556658e92351559de788fa319c291e40b915cc26d902069d03bd935553d4efa688bdbbf8@45.32.19.37:30303",
|
||||
"enode://645a59b6e6e20ed8864767a1d0c731f89ae276ed4e04c4f10becce655532d95cbe1bc9e2da3f13a6564f9ca8fe46fab2781a380b3a89148bccac883d6068f684@45.77.159.123:30303",
|
||||
"enode://7c2f43b2e7fded9469917311574d267427e62cd12e1864effd15f31c1246e4e955463d843acaa37309693a515df7986cb6d160b7e85a4ca2779a798a72d90850@108.61.194.191:30303",
|
||||
"enode://5dd35866da95aea15211fb1f98684f6e8c4e355e6aa3cc17585680ed53fa164477b8c52cb6ca4b24ec4d80f3d48ff9212b53feb131d825c7945a3abaaf02d24d@178.79.189.58:60606",
|
||||
"enode://6c585c18024eb902ca093278af73b04863ac904caabc39ac2920c23532307c572ad92afd828a990c980d272b1f26307f2409cc97aec3ff9fe866732cae49a8c2@144.217.163.224:31337",
|
||||
"enode://edd90c4cc64528802ad52fd127d80b641ff80fd43fa5292fb111c8bd2914482dffee288fd1b0d26440c6b2c669b10a53cbcd37c895ba0d6194110e100a965b2d@188.166.179.159:30303",
|
||||
"enode://d19783546438e8bfc11a35457ff1f47871a2ce4801b9b2dbe7606321a9ce29007305497eb8c98d7ae9dc5a913ee5533c3691b1080f7066697c4276e6140d2eac@45.77.47.184:30303",
|
||||
"enode://13ed57615447bc9bf1da4e28249369babc00d2530d6c103c12350453e469a5e90cbcdb787c436977467f5864be6e64f2520180fc60b841c8c3daf84df9450190@104.207.152.17:30303",
|
||||
"enode://59c228a6a0939a0b53edf6924bc7bd1384652dc1da0777495acd0707975f485f54a77c7b2dcbeece9340a43ccd9c7ea70f0cdfe48936537d238b50e5cb5dc0b2@45.77.233.0:30303",
|
||||
"enode://9d960373335c1cc38ca696dea8f2893e2a071c8f21524f21e8aae22be032acc3b67797b1d21e866f9d832943ae7d9555b8466c6ab34f473d21e547114952df37@213.32.53.183:30303"
|
||||
],
|
||||
"accounts": {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
8857
ethcore/res/ethereum/social.json
Normal file
8857
ethcore/res/ethereum/social.json
Normal file
File diff suppressed because it is too large
Load Diff
73
ethcore/res/ethereum/tobalaba.json
Normal file
73
ethcore/res/ethereum/tobalaba.json
Normal file
File diff suppressed because one or more lines are too long
@@ -24,7 +24,7 @@
|
||||
"timestamp": "0x00",
|
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"extraData": "0x",
|
||||
"gasLimit": "0x5B8D80"
|
||||
"gasLimit": "0x7A1200"
|
||||
},
|
||||
"accounts": {
|
||||
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||
|
||||
20
ethcore/service/Cargo.toml
Normal file
20
ethcore/service/Cargo.toml
Normal file
@@ -0,0 +1,20 @@
|
||||
[package]
|
||||
name = "ethcore-service"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[dependencies]
|
||||
ansi_term = "0.10"
|
||||
error-chain = { version = "0.11", default-features = false }
|
||||
ethcore = { path = ".." }
|
||||
ethcore-io = { path = "../../util/io" }
|
||||
ethcore-private-tx = { path = "../private-tx" }
|
||||
ethcore-sync = { path = "../sync" }
|
||||
kvdb = { path = "../../util/kvdb" }
|
||||
log = "0.3"
|
||||
stop-guard = { path = "../../util/stop-guard" }
|
||||
trace-time = { path = "../../util/trace-time" }
|
||||
|
||||
[dev-dependencies]
|
||||
tempdir = "0.3"
|
||||
kvdb-rocksdb = { path = "../../util/kvdb-rocksdb" }
|
||||
30
ethcore/service/src/error.rs
Normal file
30
ethcore/service/src/error.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use ethcore;
|
||||
use io;
|
||||
use ethcore_private_tx;
|
||||
|
||||
error_chain! {
|
||||
links {
|
||||
PrivateTransactions(ethcore_private_tx::Error, ethcore_private_tx::ErrorKind);
|
||||
}
|
||||
|
||||
foreign_links {
|
||||
Ethcore(ethcore::error::Error);
|
||||
IoError(io::IoError);
|
||||
}
|
||||
}
|
||||
44
ethcore/service/src/lib.rs
Normal file
44
ethcore/service/src/lib.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
extern crate ansi_term;
|
||||
extern crate ethcore;
|
||||
extern crate ethcore_io as io;
|
||||
extern crate ethcore_private_tx;
|
||||
extern crate ethcore_sync as sync;
|
||||
extern crate kvdb;
|
||||
extern crate stop_guard;
|
||||
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
#[macro_use]
|
||||
extern crate trace_time;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate tempdir;
|
||||
|
||||
mod error;
|
||||
mod service;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate kvdb_rocksdb;
|
||||
|
||||
pub use error::{Error, ErrorKind};
|
||||
pub use service::{ClientService, PrivateTxService};
|
||||
@@ -18,40 +18,49 @@
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::path::Path;
|
||||
use ethereum_types::H256;
|
||||
use kvdb::KeyValueDB;
|
||||
use kvdb_rocksdb::{Database, DatabaseConfig};
|
||||
use bytes::Bytes;
|
||||
use io::*;
|
||||
use spec::Spec;
|
||||
use error::*;
|
||||
use client::{Client, ClientConfig, ChainNotify};
|
||||
use miner::Miner;
|
||||
use std::time::Duration;
|
||||
|
||||
use snapshot::{ManifestData, RestorationStatus};
|
||||
use snapshot::service::{Service as SnapshotService, ServiceParams as SnapServiceParams};
|
||||
use ansi_term::Colour;
|
||||
use io::{IoContext, TimerToken, IoHandler, IoService, IoError};
|
||||
use kvdb::{KeyValueDB, KeyValueDBHandler};
|
||||
use stop_guard::StopGuard;
|
||||
|
||||
/// Message type for external and internal events
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub enum ClientIoMessage {
|
||||
/// Best Block Hash in chain has been changed
|
||||
NewChainHead,
|
||||
/// A block is ready
|
||||
BlockVerified,
|
||||
/// New transaction RLPs are ready to be imported
|
||||
NewTransactions(Vec<Bytes>, usize),
|
||||
/// Begin snapshot restoration
|
||||
BeginRestoration(ManifestData),
|
||||
/// Feed a state chunk to the snapshot service
|
||||
FeedStateChunk(H256, Bytes),
|
||||
/// Feed a block chunk to the snapshot service
|
||||
FeedBlockChunk(H256, Bytes),
|
||||
/// Take a snapshot for the block with given number.
|
||||
TakeSnapshot(u64),
|
||||
/// New consensus message received.
|
||||
NewMessage(Bytes)
|
||||
use sync::PrivateTxHandler;
|
||||
use ethcore::client::{Client, ClientConfig, ChainNotify, ClientIoMessage};
|
||||
use ethcore::miner::Miner;
|
||||
use ethcore::snapshot::service::{Service as SnapshotService, ServiceParams as SnapServiceParams};
|
||||
use ethcore::snapshot::{SnapshotService as _SnapshotService, RestorationStatus};
|
||||
use ethcore::spec::Spec;
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
|
||||
use ethcore_private_tx::{self, Importer};
|
||||
use Error;
|
||||
|
||||
pub struct PrivateTxService {
|
||||
provider: Arc<ethcore_private_tx::Provider>,
|
||||
}
|
||||
|
||||
impl PrivateTxService {
|
||||
fn new(provider: Arc<ethcore_private_tx::Provider>) -> Self {
|
||||
PrivateTxService {
|
||||
provider,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns underlying provider.
|
||||
pub fn provider(&self) -> Arc<ethcore_private_tx::Provider> {
|
||||
self.provider.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl PrivateTxHandler for PrivateTxService {
|
||||
fn import_private_transaction(&self, rlp: &[u8]) -> Result<(), String> {
|
||||
self.provider.import_private_transaction(rlp).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
fn import_signed_private_transaction(&self, rlp: &[u8]) -> Result<(), String> {
|
||||
self.provider.import_signed_private_transaction(rlp).map_err(|e| e.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// Client service setup. Creates and registers client and network services with the IO subsystem.
|
||||
@@ -59,7 +68,8 @@ pub struct ClientService {
|
||||
io_service: Arc<IoService<ClientIoMessage>>,
|
||||
client: Arc<Client>,
|
||||
snapshot: Arc<SnapshotService>,
|
||||
database: Arc<Database>,
|
||||
private_tx: Arc<PrivateTxService>,
|
||||
database: Arc<KeyValueDB>,
|
||||
_stop_guard: StopGuard,
|
||||
}
|
||||
|
||||
@@ -68,35 +78,28 @@ impl ClientService {
|
||||
pub fn start(
|
||||
config: ClientConfig,
|
||||
spec: &Spec,
|
||||
client_path: &Path,
|
||||
client_db: Arc<KeyValueDB>,
|
||||
snapshot_path: &Path,
|
||||
restoration_db_handler: Box<KeyValueDBHandler>,
|
||||
_ipc_path: &Path,
|
||||
miner: Arc<Miner>,
|
||||
account_provider: Arc<AccountProvider>,
|
||||
encryptor: Box<ethcore_private_tx::Encryptor>,
|
||||
private_tx_conf: ethcore_private_tx::ProviderConfig,
|
||||
) -> Result<ClientService, Error>
|
||||
{
|
||||
let io_service = IoService::<ClientIoMessage>::start()?;
|
||||
|
||||
info!("Configured for {} using {} engine", Colour::White.bold().paint(spec.name.clone()), Colour::Yellow.bold().paint(spec.engine.name()));
|
||||
|
||||
let mut db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS);
|
||||
|
||||
db_config.memory_budget = config.db_cache_size;
|
||||
db_config.compaction = config.db_compaction.compaction_profile(client_path);
|
||||
db_config.wal = config.db_wal;
|
||||
|
||||
let db = Arc::new(Database::open(
|
||||
&db_config,
|
||||
&client_path.to_str().expect("DB path could not be converted to string.")
|
||||
).map_err(::client::Error::Database)?);
|
||||
|
||||
|
||||
let pruning = config.pruning;
|
||||
let client = Client::new(config, &spec, db.clone(), miner, io_service.channel())?;
|
||||
let client = Client::new(config, &spec, client_db.clone(), miner.clone(), io_service.channel())?;
|
||||
miner.set_io_channel(io_service.channel());
|
||||
|
||||
let snapshot_params = SnapServiceParams {
|
||||
engine: spec.engine.clone(),
|
||||
genesis_block: spec.genesis_block(),
|
||||
db_config: db_config.clone(),
|
||||
restoration_db_handler: restoration_db_handler,
|
||||
pruning: pruning,
|
||||
channel: io_service.channel(),
|
||||
snapshot_root: snapshot_path.into(),
|
||||
@@ -104,6 +107,16 @@ impl ClientService {
|
||||
};
|
||||
let snapshot = Arc::new(SnapshotService::new(snapshot_params)?);
|
||||
|
||||
let provider = Arc::new(ethcore_private_tx::Provider::new(
|
||||
client.clone(),
|
||||
miner,
|
||||
account_provider,
|
||||
encryptor,
|
||||
private_tx_conf,
|
||||
io_service.channel(),
|
||||
));
|
||||
let private_tx = Arc::new(PrivateTxService::new(provider));
|
||||
|
||||
let client_io = Arc::new(ClientIoHandler {
|
||||
client: client.clone(),
|
||||
snapshot: snapshot.clone(),
|
||||
@@ -118,7 +131,8 @@ impl ClientService {
|
||||
io_service: Arc::new(io_service),
|
||||
client: client,
|
||||
snapshot: snapshot,
|
||||
database: db,
|
||||
private_tx,
|
||||
database: client_db,
|
||||
_stop_guard: stop_guard,
|
||||
})
|
||||
}
|
||||
@@ -138,6 +152,11 @@ impl ClientService {
|
||||
self.snapshot.clone()
|
||||
}
|
||||
|
||||
/// Get private transaction service.
|
||||
pub fn private_tx_service(&self) -> Arc<PrivateTxService> {
|
||||
self.private_tx.clone()
|
||||
}
|
||||
|
||||
/// Get network service component
|
||||
pub fn io(&self) -> Arc<IoService<ClientIoMessage>> {
|
||||
self.io_service.clone()
|
||||
@@ -150,6 +169,11 @@ impl ClientService {
|
||||
|
||||
/// Get a handle to the database.
|
||||
pub fn db(&self) -> Arc<KeyValueDB> { self.database.clone() }
|
||||
|
||||
/// Shutdown the Client Service
|
||||
pub fn shutdown(&self) {
|
||||
self.snapshot.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/// IO interface for the Client handler
|
||||
@@ -161,19 +185,20 @@ struct ClientIoHandler {
|
||||
const CLIENT_TICK_TIMER: TimerToken = 0;
|
||||
const SNAPSHOT_TICK_TIMER: TimerToken = 1;
|
||||
|
||||
const CLIENT_TICK_MS: u64 = 5000;
|
||||
const SNAPSHOT_TICK_MS: u64 = 10000;
|
||||
const CLIENT_TICK: Duration = Duration::from_secs(5);
|
||||
const SNAPSHOT_TICK: Duration = Duration::from_secs(10);
|
||||
|
||||
impl IoHandler<ClientIoMessage> for ClientIoHandler {
|
||||
fn initialize(&self, io: &IoContext<ClientIoMessage>) {
|
||||
io.register_timer(CLIENT_TICK_TIMER, CLIENT_TICK_MS).expect("Error registering client timer");
|
||||
io.register_timer(SNAPSHOT_TICK_TIMER, SNAPSHOT_TICK_MS).expect("Error registering snapshot timer");
|
||||
io.register_timer(CLIENT_TICK_TIMER, CLIENT_TICK).expect("Error registering client timer");
|
||||
io.register_timer(SNAPSHOT_TICK_TIMER, SNAPSHOT_TICK).expect("Error registering snapshot timer");
|
||||
}
|
||||
|
||||
fn timeout(&self, _io: &IoContext<ClientIoMessage>, timer: TimerToken) {
|
||||
trace_time!("service::read");
|
||||
match timer {
|
||||
CLIENT_TICK_TIMER => {
|
||||
use snapshot::SnapshotService;
|
||||
use ethcore::snapshot::SnapshotService;
|
||||
let snapshot_restoration = if let RestorationStatus::Ongoing{..} = self.snapshot.status() { true } else { false };
|
||||
self.client.tick(snapshot_restoration)
|
||||
},
|
||||
@@ -183,20 +208,24 @@ impl IoHandler<ClientIoMessage> for ClientIoHandler {
|
||||
}
|
||||
|
||||
fn message(&self, _io: &IoContext<ClientIoMessage>, net_message: &ClientIoMessage) {
|
||||
trace_time!("service::message");
|
||||
use std::thread;
|
||||
|
||||
match *net_message {
|
||||
ClientIoMessage::BlockVerified => { self.client.import_verified_blocks(); }
|
||||
ClientIoMessage::NewTransactions(ref transactions, peer_id) => {
|
||||
self.client.import_queued_transactions(transactions, peer_id);
|
||||
ClientIoMessage::BlockVerified => {
|
||||
self.client.import_verified_blocks();
|
||||
}
|
||||
ClientIoMessage::BeginRestoration(ref manifest) => {
|
||||
if let Err(e) = self.snapshot.init_restore(manifest.clone(), true) {
|
||||
warn!("Failed to initialize snapshot restoration: {}", e);
|
||||
}
|
||||
}
|
||||
ClientIoMessage::FeedStateChunk(ref hash, ref chunk) => self.snapshot.feed_state_chunk(*hash, chunk),
|
||||
ClientIoMessage::FeedBlockChunk(ref hash, ref chunk) => self.snapshot.feed_block_chunk(*hash, chunk),
|
||||
ClientIoMessage::FeedStateChunk(ref hash, ref chunk) => {
|
||||
self.snapshot.feed_state_chunk(*hash, chunk)
|
||||
}
|
||||
ClientIoMessage::FeedBlockChunk(ref hash, ref chunk) => {
|
||||
self.snapshot.feed_block_chunk(*hash, chunk)
|
||||
}
|
||||
ClientIoMessage::TakeSnapshot(num) => {
|
||||
let client = self.client.clone();
|
||||
let snapshot = self.snapshot.clone();
|
||||
@@ -211,9 +240,9 @@ impl IoHandler<ClientIoMessage> for ClientIoHandler {
|
||||
debug!(target: "snapshot", "Failed to initialize periodic snapshot thread: {:?}", e);
|
||||
}
|
||||
},
|
||||
ClientIoMessage::NewMessage(ref message) => if let Err(e) = self.client.engine().handle_message(message) {
|
||||
trace!(target: "poa", "Invalid message received: {}", e);
|
||||
},
|
||||
ClientIoMessage::Execute(ref exec) => {
|
||||
(*exec.0)(&self.client);
|
||||
}
|
||||
_ => {} // ignore other messages
|
||||
}
|
||||
}
|
||||
@@ -221,28 +250,66 @@ impl IoHandler<ClientIoMessage> for ClientIoHandler {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{time, thread};
|
||||
use super::*;
|
||||
use tests::helpers::*;
|
||||
use client::ClientConfig;
|
||||
use std::sync::Arc;
|
||||
use miner::Miner;
|
||||
use std::{time, thread};
|
||||
|
||||
use tempdir::TempDir;
|
||||
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use ethcore::client::ClientConfig;
|
||||
use ethcore::miner::Miner;
|
||||
use ethcore::spec::Spec;
|
||||
use ethcore::db::NUM_COLUMNS;
|
||||
use kvdb::Error;
|
||||
use kvdb_rocksdb::{Database, DatabaseConfig, CompactionProfile};
|
||||
use super::*;
|
||||
|
||||
use ethcore_private_tx;
|
||||
|
||||
#[test]
|
||||
fn it_can_be_started() {
|
||||
let tempdir = TempDir::new("").unwrap();
|
||||
let client_path = tempdir.path().join("client");
|
||||
let snapshot_path = tempdir.path().join("snapshot");
|
||||
|
||||
let spec = get_test_spec();
|
||||
let client_config = ClientConfig::default();
|
||||
let mut client_db_config = DatabaseConfig::with_columns(NUM_COLUMNS);
|
||||
|
||||
client_db_config.memory_budget = client_config.db_cache_size;
|
||||
client_db_config.compaction = CompactionProfile::auto(&client_path);
|
||||
client_db_config.wal = client_config.db_wal;
|
||||
|
||||
let client_db = Arc::new(Database::open(
|
||||
&client_db_config,
|
||||
&client_path.to_str().expect("DB path could not be converted to string.")
|
||||
).unwrap());
|
||||
|
||||
struct RestorationDBHandler {
|
||||
config: DatabaseConfig,
|
||||
}
|
||||
|
||||
impl KeyValueDBHandler for RestorationDBHandler {
|
||||
fn open(&self, db_path: &Path) -> Result<Arc<KeyValueDB>, Error> {
|
||||
Ok(Arc::new(Database::open(&self.config, &db_path.to_string_lossy())?))
|
||||
}
|
||||
}
|
||||
|
||||
let restoration_db_handler = Box::new(RestorationDBHandler {
|
||||
config: client_db_config,
|
||||
});
|
||||
|
||||
let spec = Spec::new_test();
|
||||
let service = ClientService::start(
|
||||
ClientConfig::default(),
|
||||
&spec,
|
||||
&client_path,
|
||||
client_db,
|
||||
&snapshot_path,
|
||||
restoration_db_handler,
|
||||
tempdir.path(),
|
||||
Arc::new(Miner::with_spec(&spec)),
|
||||
Arc::new(Miner::new_for_tests(&spec, None)),
|
||||
Arc::new(AccountProvider::transient_provider()),
|
||||
Box::new(ethcore_private_tx::NoopEncryptor),
|
||||
Default::default(),
|
||||
);
|
||||
assert!(service.is_ok());
|
||||
drop(service.unwrap());
|
||||
17
ethcore/src/account_provider/mod.rs
Executable file → Normal file
17
ethcore/src/account_provider/mod.rs
Executable file → Normal file
@@ -66,8 +66,6 @@ pub enum SignError {
|
||||
Hardware(HardwareError),
|
||||
/// Low-level error from store
|
||||
SStore(SSError),
|
||||
/// Inappropriate chain
|
||||
InappropriateChain,
|
||||
}
|
||||
|
||||
impl fmt::Display for SignError {
|
||||
@@ -77,7 +75,6 @@ impl fmt::Display for SignError {
|
||||
SignError::NotFound => write!(f, "Account does not exist"),
|
||||
SignError::Hardware(ref e) => write!(f, "{}", e),
|
||||
SignError::SStore(ref e) => write!(f, "{}", e),
|
||||
SignError::InappropriateChain => write!(f, "Inappropriate chain"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -275,8 +272,8 @@ impl AccountProvider {
|
||||
}
|
||||
|
||||
/// Checks whether an account with a given address is present.
|
||||
pub fn has_account(&self, address: Address) -> Result<bool, Error> {
|
||||
Ok(self.sstore.account_ref(&address).is_ok() && !self.blacklisted_accounts.contains(&address))
|
||||
pub fn has_account(&self, address: Address) -> bool {
|
||||
self.sstore.account_ref(&address).is_ok() && !self.blacklisted_accounts.contains(&address)
|
||||
}
|
||||
|
||||
/// Returns addresses of all accounts.
|
||||
@@ -641,8 +638,8 @@ impl AccountProvider {
|
||||
}
|
||||
|
||||
/// Unlocks account temporarily with a timeout.
|
||||
pub fn unlock_account_timed(&self, account: Address, password: String, duration_ms: u32) -> Result<(), Error> {
|
||||
self.unlock_account(account, password, Unlock::Timed(Instant::now() + Duration::from_millis(duration_ms as u64)))
|
||||
pub fn unlock_account_timed(&self, account: Address, password: String, duration: Duration) -> Result<(), Error> {
|
||||
self.unlock_account(account, password, Unlock::Timed(Instant::now() + duration))
|
||||
}
|
||||
|
||||
/// Checks if given account is unlocked
|
||||
@@ -837,7 +834,7 @@ impl AccountProvider {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{AccountProvider, Unlock, DappId};
|
||||
use std::time::Instant;
|
||||
use std::time::{Duration, Instant};
|
||||
use ethstore::ethkey::{Generator, Random, Address};
|
||||
use ethstore::{StoreAccountRef, Derivation};
|
||||
use ethereum_types::H256;
|
||||
@@ -941,8 +938,8 @@ mod tests {
|
||||
let kp = Random.generate().unwrap();
|
||||
let ap = AccountProvider::transient_provider();
|
||||
assert!(ap.insert_account(kp.secret().clone(), "test").is_ok());
|
||||
assert!(ap.unlock_account_timed(kp.address(), "test1".into(), 60000).is_err());
|
||||
assert!(ap.unlock_account_timed(kp.address(), "test".into(), 60000).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());
|
||||
|
||||
@@ -22,7 +22,7 @@ use std::collections::HashSet;
|
||||
use hash::{keccak, KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP};
|
||||
use triehash::ordered_trie_root;
|
||||
|
||||
use rlp::{UntrustedRlp, RlpStream, Encodable, Decodable, DecoderError};
|
||||
use rlp::{Rlp, RlpStream, Encodable, Decodable, DecoderError, encode_list};
|
||||
use ethereum_types::{H256, U256, Address, Bloom};
|
||||
use bytes::Bytes;
|
||||
use unexpected::{Mismatch, OutOfBounds};
|
||||
@@ -31,7 +31,7 @@ use vm::{EnvInfo, LastHashes};
|
||||
use engines::EthEngine;
|
||||
use error::{Error, BlockError};
|
||||
use factory::Factories;
|
||||
use header::{Header, Seal};
|
||||
use header::Header;
|
||||
use receipt::{Receipt, TransactionOutcome};
|
||||
use state::State;
|
||||
use state_db::StateDB;
|
||||
@@ -54,22 +54,21 @@ pub struct Block {
|
||||
impl Block {
|
||||
/// Returns true if the given bytes form a valid encoding of a block in RLP.
|
||||
pub fn is_good(b: &[u8]) -> bool {
|
||||
UntrustedRlp::new(b).as_val::<Block>().is_ok()
|
||||
Rlp::new(b).as_val::<Block>().is_ok()
|
||||
}
|
||||
|
||||
/// Get the RLP-encoding of the block with or without the seal.
|
||||
pub fn rlp_bytes(&self, seal: Seal) -> Bytes {
|
||||
/// Get the RLP-encoding of the block with the seal.
|
||||
pub fn rlp_bytes(&self) -> Bytes {
|
||||
let mut block_rlp = RlpStream::new_list(3);
|
||||
self.header.stream_rlp(&mut block_rlp, seal);
|
||||
block_rlp.append(&self.header);
|
||||
block_rlp.append_list(&self.transactions);
|
||||
block_rlp.append_list(&self.uncles);
|
||||
block_rlp.out()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Decodable for Block {
|
||||
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
||||
if rlp.as_raw().len() != rlp.payload_info()?.total() {
|
||||
return Err(DecoderError::RlpIsTooBig);
|
||||
}
|
||||
@@ -268,9 +267,8 @@ impl<'x> OpenBlock<'x> {
|
||||
r.block.header.set_parent_hash(parent.hash());
|
||||
r.block.header.set_number(number);
|
||||
r.block.header.set_author(author);
|
||||
r.block.header.set_timestamp_now(parent.timestamp());
|
||||
r.block.header.set_timestamp(engine.open_block_header_timestamp(parent.timestamp()));
|
||||
r.block.header.set_extra_data(extra_data);
|
||||
r.block.header.note_dirty();
|
||||
|
||||
let gas_floor_target = cmp::max(gas_range_target.0, engine.params().min_gas_limit);
|
||||
let gas_ceil_target = cmp::max(gas_range_target.1, gas_floor_target);
|
||||
@@ -284,38 +282,14 @@ impl<'x> OpenBlock<'x> {
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
/// Alter the author for the block.
|
||||
pub fn set_author(&mut self, author: Address) { self.block.header.set_author(author); }
|
||||
|
||||
/// Alter the timestamp of the block.
|
||||
pub fn set_timestamp(&mut self, timestamp: u64) { self.block.header.set_timestamp(timestamp); }
|
||||
pub fn set_timestamp(&mut self, timestamp: u64) {
|
||||
self.block.header.set_timestamp(timestamp);
|
||||
}
|
||||
|
||||
/// Alter the difficulty for the block.
|
||||
pub fn set_difficulty(&mut self, a: U256) { self.block.header.set_difficulty(a); }
|
||||
|
||||
/// Alter the gas limit for the block.
|
||||
pub fn set_gas_limit(&mut self, a: U256) { self.block.header.set_gas_limit(a); }
|
||||
|
||||
/// Alter the gas limit for the block.
|
||||
pub fn set_gas_used(&mut self, a: U256) { self.block.header.set_gas_used(a); }
|
||||
|
||||
/// Alter the uncles hash the block.
|
||||
pub fn set_uncles_hash(&mut self, h: H256) { self.block.header.set_uncles_hash(h); }
|
||||
|
||||
/// Alter transactions root for the block.
|
||||
pub fn set_transactions_root(&mut self, h: H256) { self.block.header.set_transactions_root(h); }
|
||||
|
||||
/// Alter the receipts root for the block.
|
||||
pub fn set_receipts_root(&mut self, h: H256) { self.block.header.set_receipts_root(h); }
|
||||
|
||||
/// Alter the extra_data for the block.
|
||||
pub fn set_extra_data(&mut self, extra_data: Bytes) -> Result<(), BlockError> {
|
||||
if extra_data.len() > self.engine.maximum_extra_data_size() {
|
||||
Err(BlockError::ExtraDataOutOfBounds(OutOfBounds{min: None, max: Some(self.engine.maximum_extra_data_size()), found: extra_data.len()}))
|
||||
} else {
|
||||
self.block.header.set_extra_data(extra_data);
|
||||
Ok(())
|
||||
}
|
||||
/// Removes block gas limit.
|
||||
pub fn remove_gas_limit(&mut self) {
|
||||
self.block.header.set_gas_limit(U256::max_value());
|
||||
}
|
||||
|
||||
/// Add an uncle to the block, if possible.
|
||||
@@ -347,40 +321,65 @@ impl<'x> OpenBlock<'x> {
|
||||
/// If valid, it will be executed, and archived together with the receipt.
|
||||
pub fn push_transaction(&mut self, t: SignedTransaction, h: Option<H256>) -> Result<&Receipt, Error> {
|
||||
if self.block.transactions_set.contains(&t.hash()) {
|
||||
return Err(From::from(TransactionError::AlreadyImported));
|
||||
return Err(TransactionError::AlreadyImported.into());
|
||||
}
|
||||
|
||||
let env_info = self.env_info();
|
||||
// info!("env_info says gas_used={}", env_info.gas_used);
|
||||
match self.block.state.apply(&env_info, self.engine.machine(), &t, self.block.traces.is_enabled()) {
|
||||
Ok(outcome) => {
|
||||
self.block.transactions_set.insert(h.unwrap_or_else(||t.hash()));
|
||||
self.block.transactions.push(t.into());
|
||||
let t = outcome.trace;
|
||||
if let Tracing::Enabled(ref mut traces) = self.block.traces {
|
||||
traces.push(t.into());
|
||||
}
|
||||
self.block.receipts.push(outcome.receipt);
|
||||
Ok(self.block.receipts.last().expect("receipt just pushed; qed"))
|
||||
}
|
||||
Err(x) => Err(From::from(x))
|
||||
let outcome = self.block.state.apply(&env_info, self.engine.machine(), &t, self.block.traces.is_enabled())?;
|
||||
|
||||
self.block.transactions_set.insert(h.unwrap_or_else(||t.hash()));
|
||||
self.block.transactions.push(t.into());
|
||||
if let Tracing::Enabled(ref mut traces) = self.block.traces {
|
||||
traces.push(outcome.trace.into());
|
||||
}
|
||||
self.block.receipts.push(outcome.receipt);
|
||||
Ok(self.block.receipts.last().expect("receipt just pushed; qed"))
|
||||
}
|
||||
|
||||
/// Push transactions onto the block.
|
||||
pub fn push_transactions(&mut self, transactions: &[SignedTransaction]) -> Result<(), Error> {
|
||||
push_transactions(self, transactions)
|
||||
#[cfg(not(feature = "slow-blocks"))]
|
||||
fn push_transactions(&mut self, transactions: Vec<SignedTransaction>) -> Result<(), Error> {
|
||||
for t in transactions {
|
||||
self.push_transaction(t, None)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Push transactions onto the block.
|
||||
#[cfg(feature = "slow-blocks")]
|
||||
fn push_transactions(&mut self, transactions: Vec<SignedTransaction>) -> Result<(), Error> {
|
||||
use std::time;
|
||||
|
||||
let slow_tx = option_env!("SLOW_TX_DURATION").and_then(|v| v.parse().ok()).unwrap_or(100);
|
||||
for t in transactions {
|
||||
let hash = t.hash();
|
||||
let start = time::Instant::now();
|
||||
self.push_transaction(t, None)?;
|
||||
let took = start.elapsed();
|
||||
let took_ms = took.as_secs() * 1000 + took.subsec_nanos() as u64 / 1000000;
|
||||
if took > time::Duration::from_millis(slow_tx) {
|
||||
warn!("Heavy ({} ms) transaction in block {:?}: {:?}", took_ms, block.header().number(), hash);
|
||||
}
|
||||
debug!(target: "tx", "Transaction {:?} took: {} ms", hash, took_ms);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Populate self from a header.
|
||||
pub fn populate_from(&mut self, header: &Header) {
|
||||
self.set_difficulty(*header.difficulty());
|
||||
self.set_gas_limit(*header.gas_limit());
|
||||
self.set_timestamp(header.timestamp());
|
||||
self.set_author(header.author().clone());
|
||||
self.set_extra_data(header.extra_data().clone()).unwrap_or_else(|e| warn!("Couldn't set extradata: {}. Ignoring.", e));
|
||||
self.set_uncles_hash(header.uncles_hash().clone());
|
||||
self.set_transactions_root(header.transactions_root().clone());
|
||||
fn populate_from(&mut self, header: &Header) {
|
||||
self.block.header.set_difficulty(*header.difficulty());
|
||||
self.block.header.set_gas_limit(*header.gas_limit());
|
||||
self.block.header.set_timestamp(header.timestamp());
|
||||
self.block.header.set_author(*header.author());
|
||||
self.block.header.set_uncles_hash(*header.uncles_hash());
|
||||
self.block.header.set_transactions_root(*header.transactions_root());
|
||||
// TODO: that's horrible. set only for backwards compatibility
|
||||
if header.extra_data().len() > self.engine.maximum_extra_data_size() {
|
||||
warn!("Couldn't set extradata. Ignoring.");
|
||||
} else {
|
||||
self.block.header.set_extra_data(header.extra_data().clone());
|
||||
}
|
||||
}
|
||||
|
||||
/// Turn this into a `ClosedBlock`.
|
||||
@@ -397,17 +396,20 @@ impl<'x> OpenBlock<'x> {
|
||||
warn!("Encountered error on state commit: {}", e);
|
||||
}
|
||||
s.block.header.set_transactions_root(ordered_trie_root(s.block.transactions.iter().map(|e| e.rlp_bytes())));
|
||||
let uncle_bytes = s.block.uncles.iter().fold(RlpStream::new_list(s.block.uncles.len()), |mut s, u| {s.append_raw(&u.rlp(Seal::With), 1); s} ).out();
|
||||
let uncle_bytes = encode_list(&s.block.uncles).into_vec();
|
||||
s.block.header.set_uncles_hash(keccak(&uncle_bytes));
|
||||
s.block.header.set_state_root(s.block.state.root().clone());
|
||||
s.block.header.set_receipts_root(ordered_trie_root(s.block.receipts.iter().map(|r| r.rlp_bytes())));
|
||||
s.block.header.set_log_bloom(s.block.receipts.iter().fold(Bloom::zero(), |mut b, r| {b = &b | &r.log_bloom; b})); //TODO: use |= operator
|
||||
s.block.header.set_gas_used(s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used));
|
||||
s.block.header.set_log_bloom(s.block.receipts.iter().fold(Bloom::zero(), |mut b, r| {
|
||||
b.accrue_bloom(&r.log_bloom);
|
||||
b
|
||||
}));
|
||||
s.block.header.set_gas_used(s.block.receipts.last().map_or_else(U256::zero, |r| r.gas_used));
|
||||
|
||||
ClosedBlock {
|
||||
block: s.block,
|
||||
uncle_bytes: uncle_bytes,
|
||||
unclosed_state: unclosed_state,
|
||||
uncle_bytes,
|
||||
unclosed_state,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,10 +424,11 @@ impl<'x> OpenBlock<'x> {
|
||||
if let Err(e) = s.block.state.commit() {
|
||||
warn!("Encountered error on state commit: {}", e);
|
||||
}
|
||||
|
||||
if s.block.header.transactions_root().is_zero() || s.block.header.transactions_root() == &KECCAK_NULL_RLP {
|
||||
s.block.header.set_transactions_root(ordered_trie_root(s.block.transactions.iter().map(|e| e.rlp_bytes())));
|
||||
}
|
||||
let uncle_bytes = s.block.uncles.iter().fold(RlpStream::new_list(s.block.uncles.len()), |mut s, u| {s.append_raw(&u.rlp(Seal::With), 1); s} ).out();
|
||||
let uncle_bytes = encode_list(&s.block.uncles).into_vec();
|
||||
if s.block.header.uncles_hash().is_zero() || s.block.header.uncles_hash() == &KECCAK_EMPTY_LIST_RLP {
|
||||
s.block.header.set_uncles_hash(keccak(&uncle_bytes));
|
||||
}
|
||||
@@ -434,12 +437,15 @@ impl<'x> OpenBlock<'x> {
|
||||
}
|
||||
|
||||
s.block.header.set_state_root(s.block.state.root().clone());
|
||||
s.block.header.set_log_bloom(s.block.receipts.iter().fold(Bloom::zero(), |mut b, r| {b = &b | &r.log_bloom; b})); //TODO: use |= operator
|
||||
s.block.header.set_gas_used(s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used));
|
||||
s.block.header.set_log_bloom(s.block.receipts.iter().fold(Bloom::zero(), |mut b, r| {
|
||||
b.accrue_bloom(&r.log_bloom);
|
||||
b
|
||||
}));
|
||||
s.block.header.set_gas_used(s.block.receipts.last().map_or_else(U256::zero, |r| r.gas_used));
|
||||
|
||||
LockedBlock {
|
||||
block: s.block,
|
||||
uncle_bytes: uncle_bytes,
|
||||
uncle_bytes,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,7 +468,7 @@ impl<'x> IsBlock for LockedBlock {
|
||||
|
||||
impl ClosedBlock {
|
||||
/// Get the hash of the header without seal arguments.
|
||||
pub fn hash(&self) -> H256 { self.header().rlp_keccak(Seal::Without) }
|
||||
pub fn hash(&self) -> H256 { self.header().bare_hash() }
|
||||
|
||||
/// Turn this into a `LockedBlock`, unable to be reopened again.
|
||||
pub fn lock(self) -> LockedBlock {
|
||||
@@ -485,8 +491,26 @@ impl ClosedBlock {
|
||||
}
|
||||
|
||||
impl LockedBlock {
|
||||
|
||||
/// Removes outcomes from receipts and updates the receipt root.
|
||||
///
|
||||
/// This is done after the block is enacted for historical reasons.
|
||||
/// We allow inconsistency in receipts for some chains if `validate_receipts_transition`
|
||||
/// is set to non-zero value, so the check only happens if we detect
|
||||
/// unmatching root first and then fall back to striped receipts.
|
||||
pub fn strip_receipts_outcomes(&mut self) {
|
||||
for receipt in &mut self.block.receipts {
|
||||
receipt.outcome = TransactionOutcome::Unknown;
|
||||
}
|
||||
self.block.header.set_receipts_root(
|
||||
ordered_trie_root(self.block.receipts.iter().map(|r| r.rlp_bytes()))
|
||||
);
|
||||
// compute hash and cache it.
|
||||
self.block.header.compute_hash();
|
||||
}
|
||||
|
||||
/// Get the hash of the header without seal arguments.
|
||||
pub fn hash(&self) -> H256 { self.header().rlp_keccak(Seal::Without) }
|
||||
pub fn hash(&self) -> H256 { self.header().bare_hash() }
|
||||
|
||||
/// Provide a valid seal in order to turn this into a `SealedBlock`.
|
||||
///
|
||||
@@ -499,6 +523,7 @@ impl LockedBlock {
|
||||
Mismatch { expected: expected_seal_fields, found: seal.len() }));
|
||||
}
|
||||
s.block.header.set_seal(seal);
|
||||
s.block.header.compute_hash();
|
||||
Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes })
|
||||
}
|
||||
|
||||
@@ -512,6 +537,7 @@ impl LockedBlock {
|
||||
) -> Result<SealedBlock, (Error, LockedBlock)> {
|
||||
let mut s = self;
|
||||
s.block.header.set_seal(seal);
|
||||
s.block.header.compute_hash();
|
||||
|
||||
// TODO: passing state context to avoid engines owning it?
|
||||
match engine.verify_local_seal(&s.block.header) {
|
||||
@@ -519,16 +545,6 @@ impl LockedBlock {
|
||||
_ => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }),
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove state root from transaction receipts to make them EIP-98 compatible.
|
||||
pub fn strip_receipts(self) -> LockedBlock {
|
||||
let mut block = self;
|
||||
for receipt in &mut block.block.receipts {
|
||||
receipt.outcome = TransactionOutcome::Unknown;
|
||||
}
|
||||
block.block.header.set_receipts_root(ordered_trie_root(block.block.receipts.iter().map(|r| r.rlp_bytes())));
|
||||
block
|
||||
}
|
||||
}
|
||||
|
||||
impl Drain for LockedBlock {
|
||||
@@ -542,7 +558,7 @@ impl SealedBlock {
|
||||
/// Get the RLP-encoding of the block.
|
||||
pub fn rlp_bytes(&self) -> Bytes {
|
||||
let mut block_rlp = RlpStream::new_list(3);
|
||||
self.block.header.stream_rlp(&mut block_rlp, Seal::With);
|
||||
block_rlp.append(&self.block.header);
|
||||
block_rlp.append_list(&self.block.transactions);
|
||||
block_rlp.append_raw(&self.uncle_bytes, 1);
|
||||
block_rlp.out()
|
||||
@@ -561,10 +577,10 @@ impl IsBlock for SealedBlock {
|
||||
}
|
||||
|
||||
/// Enact the block given by block header, transactions and uncles
|
||||
pub fn enact(
|
||||
header: &Header,
|
||||
transactions: &[SignedTransaction],
|
||||
uncles: &[Header],
|
||||
fn enact(
|
||||
header: Header,
|
||||
transactions: Vec<SignedTransaction>,
|
||||
uncles: Vec<Header>,
|
||||
engine: &EthEngine,
|
||||
tracing: bool,
|
||||
db: StateDB,
|
||||
@@ -594,48 +610,19 @@ pub fn enact(
|
||||
is_epoch_begin,
|
||||
)?;
|
||||
|
||||
b.populate_from(header);
|
||||
b.populate_from(&header);
|
||||
b.push_transactions(transactions)?;
|
||||
|
||||
for u in uncles {
|
||||
b.push_uncle(u.clone())?;
|
||||
b.push_uncle(u)?;
|
||||
}
|
||||
|
||||
Ok(b.close_and_lock())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(not(feature = "slow-blocks"))]
|
||||
fn push_transactions(block: &mut OpenBlock, transactions: &[SignedTransaction]) -> Result<(), Error> {
|
||||
for t in transactions {
|
||||
block.push_transaction(t.clone(), None)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "slow-blocks")]
|
||||
fn push_transactions(block: &mut OpenBlock, transactions: &[SignedTransaction]) -> Result<(), Error> {
|
||||
use std::time;
|
||||
|
||||
let slow_tx = option_env!("SLOW_TX_DURATION").and_then(|v| v.parse().ok()).unwrap_or(100);
|
||||
for t in transactions {
|
||||
let hash = t.hash();
|
||||
let start = time::Instant::now();
|
||||
block.push_transaction(t.clone(), None)?;
|
||||
let took = start.elapsed();
|
||||
let took_ms = took.as_secs() * 1000 + took.subsec_nanos() as u64 / 1000000;
|
||||
if took > time::Duration::from_millis(slow_tx) {
|
||||
warn!("Heavy ({} ms) transaction in block {:?}: {:?}", took_ms, block.header().number(), hash);
|
||||
}
|
||||
debug!(target: "tx", "Transaction {:?} took: {} ms", hash, took_ms);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO [ToDr] Pass `PreverifiedBlock` by move, this will avoid unecessary allocation
|
||||
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
|
||||
pub fn enact_verified(
|
||||
block: &PreverifiedBlock,
|
||||
block: PreverifiedBlock,
|
||||
engine: &EthEngine,
|
||||
tracing: bool,
|
||||
db: StateDB,
|
||||
@@ -644,12 +631,12 @@ pub fn enact_verified(
|
||||
factories: Factories,
|
||||
is_epoch_begin: bool,
|
||||
) -> Result<LockedBlock, Error> {
|
||||
let view = BlockView::new(&block.bytes);
|
||||
let view = view!(BlockView, &block.bytes);
|
||||
|
||||
enact(
|
||||
&block.header,
|
||||
&block.transactions,
|
||||
&view.uncles(),
|
||||
block.header,
|
||||
block.transactions,
|
||||
view.uncles(),
|
||||
engine,
|
||||
tracing,
|
||||
db,
|
||||
@@ -662,7 +649,7 @@ pub fn enact_verified(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use tests::helpers::*;
|
||||
use test_helpers::get_temp_state_db;
|
||||
use super::*;
|
||||
use engines::EthEngine;
|
||||
use vm::LastHashes;
|
||||
@@ -685,7 +672,7 @@ mod tests {
|
||||
last_hashes: Arc<LastHashes>,
|
||||
factories: Factories,
|
||||
) -> Result<LockedBlock, Error> {
|
||||
let block = BlockView::new(block_bytes);
|
||||
let block = view!(BlockView, block_bytes);
|
||||
let header = block.header();
|
||||
let transactions: Result<Vec<_>, Error> = block
|
||||
.transactions()
|
||||
@@ -717,7 +704,7 @@ mod tests {
|
||||
)?;
|
||||
|
||||
b.populate_from(&header);
|
||||
b.push_transactions(&transactions)?;
|
||||
b.push_transactions(transactions)?;
|
||||
|
||||
for u in &block.uncles() {
|
||||
b.push_uncle(u.clone())?;
|
||||
@@ -736,7 +723,7 @@ mod tests {
|
||||
last_hashes: Arc<LastHashes>,
|
||||
factories: Factories,
|
||||
) -> Result<SealedBlock, Error> {
|
||||
let header = BlockView::new(block_bytes).header_view();
|
||||
let header = view!(BlockView, block_bytes).header_view();
|
||||
Ok(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, factories)?.seal(engine, header.seal())?)
|
||||
}
|
||||
|
||||
@@ -802,7 +789,7 @@ mod tests {
|
||||
|
||||
let bytes = e.rlp_bytes();
|
||||
assert_eq!(bytes, orig_bytes);
|
||||
let uncles = BlockView::new(&bytes).uncles();
|
||||
let uncles = view!(BlockView, &bytes).uncles();
|
||||
assert_eq!(uncles[1].extra_data(), b"uncle2");
|
||||
|
||||
let db = e.drain();
|
||||
@@ -810,3 +797,4 @@ mod tests {
|
||||
assert!(orig_db.journal_db().keys().iter().filter(|k| orig_db.journal_db().get(k.0) != db.journal_db().get(k.0)).next() == None);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,22 +15,23 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use ethereum_types::{H256, U256};
|
||||
use bytes::Bytes;
|
||||
use header::BlockNumber;
|
||||
|
||||
/// Best block info.
|
||||
#[derive(Default)]
|
||||
use encoded;
|
||||
use header::{Header, BlockNumber};
|
||||
|
||||
/// Contains information on a best block that is specific to the consensus engine.
|
||||
///
|
||||
/// For GHOST fork-choice rule it would typically describe the block with highest
|
||||
/// combined difficulty (usually the block with the highest block number).
|
||||
///
|
||||
/// Sometimes refered as 'latest block'.
|
||||
pub struct BestBlock {
|
||||
/// Best block hash.
|
||||
pub hash: H256,
|
||||
/// Best block number.
|
||||
pub number: BlockNumber,
|
||||
/// Best block timestamp.
|
||||
pub timestamp: u64,
|
||||
/// Best block decoded header.
|
||||
pub header: Header,
|
||||
/// Best block uncompressed bytes.
|
||||
pub block: encoded::Block,
|
||||
/// Best block total difficulty.
|
||||
pub total_difficulty: U256,
|
||||
/// Best block uncompressed bytes
|
||||
pub block: Bytes,
|
||||
}
|
||||
|
||||
/// Best ancient block info. If the blockchain has a gap this keeps track of where it starts.
|
||||
|
||||
@@ -25,11 +25,11 @@ use heapsize::HeapSizeOf;
|
||||
use ethereum_types::{H256, Bloom, U256};
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use bytes::Bytes;
|
||||
use rlp::*;
|
||||
use rlp::RlpStream;
|
||||
use rlp_compress::{compress, decompress, blocks_swapper};
|
||||
use header::*;
|
||||
use transaction::*;
|
||||
use views::*;
|
||||
use views::{BlockView, HeaderView};
|
||||
use log_entry::{LogEntry, LocalizedLogEntry};
|
||||
use receipt::Receipt;
|
||||
use blooms::{BloomGroup, GroupPosition};
|
||||
@@ -96,11 +96,6 @@ pub trait BlockProvider {
|
||||
/// Get receipts of block with given hash.
|
||||
fn block_receipts(&self, hash: &H256) -> Option<BlockReceipts>;
|
||||
|
||||
/// Get the partial-header of a block.
|
||||
fn block_header(&self, hash: &H256) -> Option<Header> {
|
||||
self.block_header_data(hash).map(|header| header.decode())
|
||||
}
|
||||
|
||||
/// Get the header RLP of a block.
|
||||
fn block_header_data(&self, hash: &H256) -> Option<encoded::Header>;
|
||||
|
||||
@@ -121,7 +116,7 @@ pub trait BlockProvider {
|
||||
|
||||
/// Get the number of given block's hash.
|
||||
fn block_number(&self, hash: &H256) -> Option<BlockNumber> {
|
||||
self.block_details(hash).map(|details| details.number)
|
||||
self.block_header_data(hash).map(|header| header.number())
|
||||
}
|
||||
|
||||
/// Get transaction with given transaction hash.
|
||||
@@ -150,8 +145,8 @@ pub trait BlockProvider {
|
||||
}
|
||||
|
||||
/// Returns the header of the genesis block.
|
||||
fn genesis_header(&self) -> Header {
|
||||
self.block_header(&self.genesis_hash())
|
||||
fn genesis_header(&self) -> encoded::Header {
|
||||
self.block_header_data(&self.genesis_hash())
|
||||
.expect("Genesis header always stored; qed")
|
||||
}
|
||||
|
||||
@@ -199,8 +194,8 @@ pub struct BlockChain {
|
||||
first_block: Option<H256>,
|
||||
|
||||
// block cache
|
||||
block_headers: RwLock<HashMap<H256, Bytes>>,
|
||||
block_bodies: RwLock<HashMap<H256, Bytes>>,
|
||||
block_headers: RwLock<HashMap<H256, encoded::Header>>,
|
||||
block_bodies: RwLock<HashMap<H256, encoded::Body>>,
|
||||
|
||||
// extra caches
|
||||
block_details: RwLock<HashMap<H256, BlockDetails>>,
|
||||
@@ -240,17 +235,9 @@ impl BlockProvider for BlockChain {
|
||||
|
||||
/// Get raw block data
|
||||
fn block(&self, hash: &H256) -> Option<encoded::Block> {
|
||||
match (self.block_header_data(hash), self.block_body(hash)) {
|
||||
(Some(header), Some(body)) => {
|
||||
let mut block = RlpStream::new_list(3);
|
||||
let body_rlp = body.rlp();
|
||||
block.append_raw(header.rlp().as_raw(), 1);
|
||||
block.append_raw(body_rlp.at(0).as_raw(), 1);
|
||||
block.append_raw(body_rlp.at(1).as_raw(), 1);
|
||||
Some(encoded::Block::new(block.out()))
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
let header = self.block_header_data(hash)?;
|
||||
let body = self.block_body(hash)?;
|
||||
Some(encoded::Block::new_from_header_and_body(&header.view(), &body.view()))
|
||||
}
|
||||
|
||||
/// Get block header data
|
||||
@@ -259,36 +246,28 @@ impl BlockProvider for BlockChain {
|
||||
{
|
||||
let read = self.block_headers.read();
|
||||
if let Some(v) = read.get(hash) {
|
||||
return Some(encoded::Header::new(v.clone()));
|
||||
return Some(v.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// Check if it's the best block
|
||||
{
|
||||
let best_block = self.best_block.read();
|
||||
if &best_block.hash == hash {
|
||||
return Some(encoded::Header::new(
|
||||
Rlp::new(&best_block.block).at(0).as_raw().to_vec()
|
||||
))
|
||||
if &best_block.header.hash() == hash {
|
||||
return Some(best_block.header.encoded())
|
||||
}
|
||||
}
|
||||
|
||||
// Read from DB and populate cache
|
||||
let opt = self.db.get(db::COL_HEADERS, hash)
|
||||
.expect("Low level database error. Some issue with disk?");
|
||||
let b = self.db.get(db::COL_HEADERS, hash)
|
||||
.expect("Low level database error. Some issue with disk?")?;
|
||||
|
||||
let result = match opt {
|
||||
Some(b) => {
|
||||
let bytes = decompress(&b, blocks_swapper()).into_vec();
|
||||
let mut write = self.block_headers.write();
|
||||
write.insert(*hash, bytes.clone());
|
||||
Some(encoded::Header::new(bytes))
|
||||
},
|
||||
None => None
|
||||
};
|
||||
let header = encoded::Header::new(decompress(&b, blocks_swapper()).into_vec());
|
||||
let mut write = self.block_headers.write();
|
||||
write.insert(*hash, header.clone());
|
||||
|
||||
self.cache_man.lock().note_used(CacheId::BlockHeader(*hash));
|
||||
result
|
||||
Some(header)
|
||||
}
|
||||
|
||||
/// Get block body data
|
||||
@@ -297,63 +276,56 @@ impl BlockProvider for BlockChain {
|
||||
{
|
||||
let read = self.block_bodies.read();
|
||||
if let Some(v) = read.get(hash) {
|
||||
return Some(encoded::Body::new(v.clone()));
|
||||
return Some(v.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// Check if it's the best block
|
||||
{
|
||||
let best_block = self.best_block.read();
|
||||
if &best_block.hash == hash {
|
||||
return Some(encoded::Body::new(Self::block_to_body(&best_block.block)));
|
||||
if &best_block.header.hash() == hash {
|
||||
return Some(encoded::Body::new(Self::block_to_body(best_block.block.rlp().as_raw())));
|
||||
}
|
||||
}
|
||||
|
||||
// Read from DB and populate cache
|
||||
let opt = self.db.get(db::COL_BODIES, hash)
|
||||
.expect("Low level database error. Some issue with disk?");
|
||||
let b = self.db.get(db::COL_BODIES, hash)
|
||||
.expect("Low level database error. Some issue with disk?")?;
|
||||
|
||||
let result = match opt {
|
||||
Some(b) => {
|
||||
let bytes = decompress(&b, blocks_swapper()).into_vec();
|
||||
let mut write = self.block_bodies.write();
|
||||
write.insert(*hash, bytes.clone());
|
||||
Some(encoded::Body::new(bytes))
|
||||
},
|
||||
None => None
|
||||
};
|
||||
let body = encoded::Body::new(decompress(&b, blocks_swapper()).into_vec());
|
||||
let mut write = self.block_bodies.write();
|
||||
write.insert(*hash, body.clone());
|
||||
|
||||
self.cache_man.lock().note_used(CacheId::BlockBody(*hash));
|
||||
|
||||
result
|
||||
Some(body)
|
||||
}
|
||||
|
||||
/// Get the familial details concerning a block.
|
||||
fn block_details(&self, hash: &H256) -> Option<BlockDetails> {
|
||||
let result = self.db.read_with_cache(db::COL_EXTRA, &self.block_details, hash);
|
||||
let result = self.db.read_with_cache(db::COL_EXTRA, &self.block_details, hash)?;
|
||||
self.cache_man.lock().note_used(CacheId::BlockDetails(*hash));
|
||||
result
|
||||
Some(result)
|
||||
}
|
||||
|
||||
/// Get the hash of given block's number.
|
||||
fn block_hash(&self, index: BlockNumber) -> Option<H256> {
|
||||
let result = self.db.read_with_cache(db::COL_EXTRA, &self.block_hashes, &index);
|
||||
let result = self.db.read_with_cache(db::COL_EXTRA, &self.block_hashes, &index)?;
|
||||
self.cache_man.lock().note_used(CacheId::BlockHashes(index));
|
||||
result
|
||||
Some(result)
|
||||
}
|
||||
|
||||
/// Get the address of transaction with given hash.
|
||||
fn transaction_address(&self, hash: &H256) -> Option<TransactionAddress> {
|
||||
let result = self.db.read_with_cache(db::COL_EXTRA, &self.transaction_addresses, hash);
|
||||
let result = self.db.read_with_cache(db::COL_EXTRA, &self.transaction_addresses, hash)?;
|
||||
self.cache_man.lock().note_used(CacheId::TransactionAddresses(*hash));
|
||||
result
|
||||
Some(result)
|
||||
}
|
||||
|
||||
/// Get receipts of block with given hash.
|
||||
fn block_receipts(&self, hash: &H256) -> Option<BlockReceipts> {
|
||||
let result = self.db.read_with_cache(db::COL_EXTRA, &self.block_receipts, hash);
|
||||
let result = self.db.read_with_cache(db::COL_EXTRA, &self.block_receipts, hash)?;
|
||||
self.cache_man.lock().note_used(CacheId::BlockReceipts(*hash));
|
||||
result
|
||||
Some(result)
|
||||
}
|
||||
|
||||
/// Returns numbers of blocks containing given bloom.
|
||||
@@ -457,33 +429,31 @@ impl<'a> Iterator for EpochTransitionIter<'a> {
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
loop {
|
||||
match self.prefix_iter.next() {
|
||||
Some((key, val)) => {
|
||||
// iterator may continue beyond values beginning with this
|
||||
// prefix.
|
||||
if !key.starts_with(&EPOCH_KEY_PREFIX[..]) { return None }
|
||||
// some epochs never occurred on the main chain.
|
||||
let (key, val) = self.prefix_iter.next()?;
|
||||
|
||||
let transitions: EpochTransitions = ::rlp::decode(&val[..]);
|
||||
// iterator may continue beyond values beginning with this
|
||||
// prefix.
|
||||
if !key.starts_with(&EPOCH_KEY_PREFIX[..]) {
|
||||
return None
|
||||
}
|
||||
|
||||
// if there are multiple candidates, at most one will be on the
|
||||
// canon chain.
|
||||
for transition in transitions.candidates.into_iter() {
|
||||
let is_in_canon_chain = self.chain.block_hash(transition.block_number)
|
||||
.map_or(false, |hash| hash == transition.block_hash);
|
||||
let transitions: EpochTransitions = ::rlp::decode(&val[..]).expect("decode error: the db is corrupted or the data structure has changed");
|
||||
|
||||
// if the transition is within the block gap, there will only be
|
||||
// one candidate, and it will be from a snapshot restored from.
|
||||
let is_ancient = self.chain.first_block_number()
|
||||
.map_or(false, |first| first > transition.block_number);
|
||||
// if there are multiple candidates, at most one will be on the
|
||||
// canon chain.
|
||||
for transition in transitions.candidates.into_iter() {
|
||||
let is_in_canon_chain = self.chain.block_hash(transition.block_number)
|
||||
.map_or(false, |hash| hash == transition.block_hash);
|
||||
|
||||
if is_ancient || is_in_canon_chain {
|
||||
return Some((transitions.number, transition))
|
||||
}
|
||||
}
|
||||
// if the transition is within the block gap, there will only be
|
||||
// one candidate, and it will be from a snapshot restored from.
|
||||
let is_ancient = self.chain.first_block_number()
|
||||
.map_or(false, |first| first > transition.block_number);
|
||||
|
||||
// some epochs never occurred on the main chain.
|
||||
if is_ancient || is_in_canon_chain {
|
||||
return Some((transitions.number, transition))
|
||||
}
|
||||
None => return None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -492,7 +462,7 @@ impl<'a> Iterator for EpochTransitionIter<'a> {
|
||||
impl BlockChain {
|
||||
/// Create new instance of blockchain from given Genesis.
|
||||
pub fn new(config: Config, genesis: &[u8], db: Arc<KeyValueDB>) -> BlockChain {
|
||||
// 400 is the avarage size of the key
|
||||
// 400 is the average size of the key
|
||||
let cache_man = CacheManager::new(config.pref_cache_size, config.max_cache_size, 400);
|
||||
|
||||
let mut bc = BlockChain {
|
||||
@@ -501,7 +471,12 @@ impl BlockChain {
|
||||
elements_per_index: LOG_BLOOMS_ELEMENTS_PER_INDEX,
|
||||
},
|
||||
first_block: None,
|
||||
best_block: RwLock::new(BestBlock::default()),
|
||||
best_block: RwLock::new(BestBlock {
|
||||
// BestBlock will be overwritten anyway.
|
||||
header: Default::default(),
|
||||
total_difficulty: Default::default(),
|
||||
block: encoded::Block::new(genesis.into()),
|
||||
}),
|
||||
best_ancient_block: RwLock::new(None),
|
||||
block_headers: RwLock::new(HashMap::new()),
|
||||
block_bodies: RwLock::new(HashMap::new()),
|
||||
@@ -526,7 +501,7 @@ impl BlockChain {
|
||||
None => {
|
||||
// best block does not exist
|
||||
// we need to insert genesis into the cache
|
||||
let block = BlockView::new(genesis);
|
||||
let block = view!(BlockView, genesis);
|
||||
let header = block.header_view();
|
||||
let hash = block.hash();
|
||||
|
||||
@@ -552,11 +527,21 @@ impl BlockChain {
|
||||
|
||||
{
|
||||
// Fetch best block details
|
||||
let best_block_number = bc.block_number(&best_block_hash).unwrap();
|
||||
let best_block_total_difficulty = bc.block_details(&best_block_hash).unwrap().total_difficulty;
|
||||
let best_block_rlp = bc.block(&best_block_hash).unwrap().into_inner();
|
||||
let best_block_timestamp = BlockView::new(&best_block_rlp).header().timestamp();
|
||||
let best_block_rlp = bc.block(&best_block_hash).unwrap();
|
||||
|
||||
// and write them
|
||||
let mut best_block = bc.best_block.write();
|
||||
*best_block = BestBlock {
|
||||
total_difficulty: best_block_total_difficulty,
|
||||
header: best_block_rlp.decode_header(),
|
||||
block: best_block_rlp,
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
let best_block_number = bc.best_block.read().header.number();
|
||||
// Fetch first and best ancient block details
|
||||
let raw_first = bc.db.get(db::COL_EXTRA, b"first").unwrap().map(|v| v.into_vec());
|
||||
let mut best_ancient = bc.db.get(db::COL_EXTRA, b"ancient").unwrap().map(|h| H256::from_slice(&h));
|
||||
let best_ancient_number;
|
||||
@@ -599,15 +584,6 @@ impl BlockChain {
|
||||
}
|
||||
|
||||
// and write them
|
||||
let mut best_block = bc.best_block.write();
|
||||
*best_block = BestBlock {
|
||||
number: best_block_number,
|
||||
total_difficulty: best_block_total_difficulty,
|
||||
hash: best_block_hash,
|
||||
timestamp: best_block_timestamp,
|
||||
block: best_block_rlp,
|
||||
};
|
||||
|
||||
if let (Some(hash), Some(number)) = (best_ancient, best_ancient_number) {
|
||||
let mut best_ancient_block = bc.best_ancient_block.write();
|
||||
*best_ancient_block = Some(BestAncientBlock {
|
||||
@@ -727,7 +703,7 @@ impl BlockChain {
|
||||
/// Supply a dummy parent total difficulty when the parent block may not be in the chain.
|
||||
/// Returns true if the block is disconnected.
|
||||
pub fn insert_unordered_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec<Receipt>, parent_td: Option<U256>, is_best: bool, is_ancient: bool) -> bool {
|
||||
let block = BlockView::new(bytes);
|
||||
let block = view!(BlockView, bytes);
|
||||
let header = block.header_view();
|
||||
let hash = header.hash();
|
||||
|
||||
@@ -762,7 +738,6 @@ impl BlockChain {
|
||||
blocks_blooms: self.prepare_block_blooms_update(bytes, &info),
|
||||
transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
|
||||
info: info,
|
||||
timestamp: header.timestamp(),
|
||||
block: bytes
|
||||
}, is_best);
|
||||
|
||||
@@ -811,7 +786,6 @@ impl BlockChain {
|
||||
blocks_blooms: self.prepare_block_blooms_update(bytes, &info),
|
||||
transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
|
||||
info: info,
|
||||
timestamp: header.timestamp(),
|
||||
block: bytes,
|
||||
}, is_best);
|
||||
true
|
||||
@@ -915,7 +889,6 @@ impl BlockChain {
|
||||
let mut update = HashMap::new();
|
||||
update.insert(block_hash, parent_details);
|
||||
|
||||
|
||||
let mut write_details = self.block_details.write();
|
||||
batch.extend_with_cache(db::COL_EXTRA, &mut *write_details, update, CacheUpdatePolicy::Overwrite);
|
||||
|
||||
@@ -927,7 +900,7 @@ impl BlockChain {
|
||||
/// If the block is already known, does nothing.
|
||||
pub fn insert_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec<Receipt>) -> ImportRoute {
|
||||
// create views onto rlp
|
||||
let block = BlockView::new(bytes);
|
||||
let block = view!(BlockView, bytes);
|
||||
let header = block.header_view();
|
||||
let hash = header.hash();
|
||||
|
||||
@@ -962,7 +935,6 @@ impl BlockChain {
|
||||
blocks_blooms: self.prepare_block_blooms_update(bytes, &info),
|
||||
transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
|
||||
info: info.clone(),
|
||||
timestamp: header.timestamp(),
|
||||
block: bytes,
|
||||
}, true);
|
||||
|
||||
@@ -1054,12 +1026,11 @@ impl BlockChain {
|
||||
let mut best_block = self.pending_best_block.write();
|
||||
if is_best && update.info.location != BlockLocation::Branch {
|
||||
batch.put(db::COL_EXTRA, b"best", &update.info.hash);
|
||||
let block = encoded::Block::new(update.block.to_vec());
|
||||
*best_block = Some(BestBlock {
|
||||
hash: update.info.hash,
|
||||
number: update.info.number,
|
||||
total_difficulty: update.info.total_difficulty,
|
||||
timestamp: update.timestamp,
|
||||
block: update.block.to_vec(),
|
||||
header: block.decode_header(),
|
||||
block,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1131,19 +1102,19 @@ impl BlockChain {
|
||||
}
|
||||
|
||||
/// Given a block's `parent`, find every block header which represents a valid possible uncle.
|
||||
pub fn find_uncle_headers(&self, parent: &H256, uncle_generations: usize) -> Option<Vec<Header>> {
|
||||
self.find_uncle_hashes(parent, uncle_generations).map(|v| v.into_iter().filter_map(|h| self.block_header(&h)).collect())
|
||||
pub fn find_uncle_headers(&self, parent: &H256, uncle_generations: usize) -> Option<Vec<encoded::Header>> {
|
||||
self.find_uncle_hashes(parent, uncle_generations)
|
||||
.map(|v| v.into_iter().filter_map(|h| self.block_header_data(&h)).collect())
|
||||
}
|
||||
|
||||
/// Given a block's `parent`, find every block hash which represents a valid possible uncle.
|
||||
pub fn find_uncle_hashes(&self, parent: &H256, uncle_generations: usize) -> Option<Vec<H256>> {
|
||||
if !self.is_known(parent) { return None; }
|
||||
if !self.is_known(parent) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut excluded = HashSet::new();
|
||||
let ancestry = match self.ancestry_iter(parent.clone()) {
|
||||
Some(iter) => iter,
|
||||
None => return None,
|
||||
};
|
||||
let ancestry = self.ancestry_iter(parent.clone())?;
|
||||
|
||||
for a in ancestry.clone().take(uncle_generations) {
|
||||
if let Some(uncles) = self.uncle_hashes(&a) {
|
||||
@@ -1169,7 +1140,7 @@ impl BlockChain {
|
||||
/// This function returns modified block hashes.
|
||||
fn prepare_block_hashes_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap<BlockNumber, H256> {
|
||||
let mut block_hashes = HashMap::new();
|
||||
let block = BlockView::new(block_bytes);
|
||||
let block = view!(BlockView, block_bytes);
|
||||
let header = block.header_view();
|
||||
let number = header.number();
|
||||
|
||||
@@ -1196,7 +1167,7 @@ impl BlockChain {
|
||||
/// This function returns modified block details.
|
||||
/// Uses the given parent details or attempts to load them from the database.
|
||||
fn prepare_block_details_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap<H256, BlockDetails> {
|
||||
let block = BlockView::new(block_bytes);
|
||||
let block = view!(BlockView, block_bytes);
|
||||
let header = block.header_view();
|
||||
let parent_hash = header.parent_hash();
|
||||
|
||||
@@ -1228,7 +1199,7 @@ impl BlockChain {
|
||||
|
||||
/// This function returns modified transaction addresses.
|
||||
fn prepare_transaction_addresses_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap<H256, Option<TransactionAddress>> {
|
||||
let block = BlockView::new(block_bytes);
|
||||
let block = view!(BlockView, block_bytes);
|
||||
let transaction_hashes = block.transaction_hashes();
|
||||
|
||||
match info.location {
|
||||
@@ -1296,7 +1267,7 @@ impl BlockChain {
|
||||
/// to bloom location in database (BlocksBloomLocation).
|
||||
///
|
||||
fn prepare_block_blooms_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap<GroupPosition, BloomGroup> {
|
||||
let block = BlockView::new(block_bytes);
|
||||
let block = view!(BlockView, block_bytes);
|
||||
let header = block.header_view();
|
||||
|
||||
let log_blooms = match info.location {
|
||||
@@ -1334,17 +1305,17 @@ impl BlockChain {
|
||||
|
||||
/// Get best block hash.
|
||||
pub fn best_block_hash(&self) -> H256 {
|
||||
self.best_block.read().hash
|
||||
self.best_block.read().header.hash()
|
||||
}
|
||||
|
||||
/// Get best block number.
|
||||
pub fn best_block_number(&self) -> BlockNumber {
|
||||
self.best_block.read().number
|
||||
self.best_block.read().header.number()
|
||||
}
|
||||
|
||||
/// Get best block timestamp.
|
||||
pub fn best_block_timestamp(&self) -> u64 {
|
||||
self.best_block.read().timestamp
|
||||
self.best_block.read().header.timestamp()
|
||||
}
|
||||
|
||||
/// Get best block total difficulty.
|
||||
@@ -1353,10 +1324,8 @@ impl BlockChain {
|
||||
}
|
||||
|
||||
/// Get best block header
|
||||
pub fn best_block_header(&self) -> encoded::Header {
|
||||
let block = self.best_block.read();
|
||||
let raw = BlockView::new(&block.block).header_view().rlp().as_raw().to_vec();
|
||||
encoded::Header::new(raw)
|
||||
pub fn best_block_header(&self) -> Header {
|
||||
self.best_block.read().header.clone()
|
||||
}
|
||||
|
||||
/// Get current cache size.
|
||||
@@ -1417,26 +1386,32 @@ impl BlockChain {
|
||||
/// Create a block body from a block.
|
||||
pub fn block_to_body(block: &[u8]) -> Bytes {
|
||||
let mut body = RlpStream::new_list(2);
|
||||
let block_rlp = Rlp::new(block);
|
||||
body.append_raw(block_rlp.at(1).as_raw(), 1);
|
||||
body.append_raw(block_rlp.at(2).as_raw(), 1);
|
||||
let block_view = view!(BlockView, block);
|
||||
body.append_raw(block_view.transactions_rlp().as_raw(), 1);
|
||||
body.append_raw(block_view.uncles_rlp().as_raw(), 1);
|
||||
body.out()
|
||||
}
|
||||
|
||||
/// Returns general blockchain information
|
||||
pub fn chain_info(&self) -> BlockChainInfo {
|
||||
// Make sure to call internal methods first to avoid
|
||||
// recursive locking of `best_block`.
|
||||
let first_block_hash = self.first_block();
|
||||
let first_block_number = self.first_block_number().into();
|
||||
let genesis_hash = self.genesis_hash();
|
||||
|
||||
// ensure data consistencly by locking everything first
|
||||
let best_block = self.best_block.read();
|
||||
let best_ancient_block = self.best_ancient_block.read();
|
||||
BlockChainInfo {
|
||||
total_difficulty: best_block.total_difficulty.clone(),
|
||||
pending_total_difficulty: best_block.total_difficulty.clone(),
|
||||
genesis_hash: self.genesis_hash(),
|
||||
best_block_hash: best_block.hash,
|
||||
best_block_number: best_block.number,
|
||||
best_block_timestamp: best_block.timestamp,
|
||||
first_block_hash: self.first_block(),
|
||||
first_block_number: From::from(self.first_block_number()),
|
||||
total_difficulty: best_block.total_difficulty,
|
||||
pending_total_difficulty: best_block.total_difficulty,
|
||||
genesis_hash,
|
||||
best_block_hash: best_block.header.hash(),
|
||||
best_block_number: best_block.header.number(),
|
||||
best_block_timestamp: best_block.header.timestamp(),
|
||||
first_block_hash,
|
||||
first_block_number,
|
||||
ancient_block_hash: best_ancient_block.as_ref().map(|b| b.hash),
|
||||
ancient_block_number: best_ancient_block.as_ref().map(|b| b.number),
|
||||
}
|
||||
@@ -1454,7 +1429,10 @@ mod tests {
|
||||
use ethereum_types::*;
|
||||
use receipt::{Receipt, TransactionOutcome};
|
||||
use blockchain::{BlockProvider, BlockChain, Config, ImportRoute};
|
||||
use tests::helpers::*;
|
||||
use test_helpers::{
|
||||
generate_dummy_blockchain, generate_dummy_blockchain_with_extra,
|
||||
generate_dummy_empty_blockchain
|
||||
};
|
||||
use blockchain::generator::{BlockGenerator, BlockBuilder, BlockOptions};
|
||||
use blockchain::extras::TransactionAddress;
|
||||
use transaction::{Transaction, Action};
|
||||
@@ -1563,7 +1541,11 @@ mod tests {
|
||||
let b4b = b3a.add_block_with_difficulty(9);
|
||||
let b5b = b4a.add_block_with_difficulty(9);
|
||||
|
||||
let uncle_headers = vec![b4b.last().header(), b3b.last().header(), b2b.last().header()];
|
||||
let uncle_headers = vec![
|
||||
b4b.last().header().encoded(),
|
||||
b3b.last().header().encoded(),
|
||||
b2b.last().header().encoded(),
|
||||
];
|
||||
let b4a_hash = b4a.last().hash();
|
||||
|
||||
let generator = BlockGenerator::new(
|
||||
@@ -1886,10 +1868,10 @@ mod tests {
|
||||
|
||||
assert_eq!(bc.best_block_number(), 2999);
|
||||
let best_hash = bc.best_block_hash();
|
||||
let mut block_header = bc.block_header(&best_hash);
|
||||
let mut block_header = bc.block_header_data(&best_hash);
|
||||
|
||||
while !block_header.is_none() {
|
||||
block_header = bc.block_header(block_header.unwrap().parent_hash());
|
||||
block_header = bc.block_header_data(&block_header.unwrap().parent_hash());
|
||||
}
|
||||
assert!(bc.cache_size().blocks > 1024 * 1024);
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ impl Block {
|
||||
|
||||
#[inline]
|
||||
pub fn hash(&self) -> H256 {
|
||||
BlockView::new(&self.encoded()).header_view().hash()
|
||||
view!(BlockView, &self.encoded()).header_view().hash()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
@@ -20,7 +20,7 @@ use ethereum_types::H256;
|
||||
use blockchain::block_info::{BlockInfo, BlockLocation};
|
||||
|
||||
/// Import route for newly inserted block.
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct ImportRoute {
|
||||
/// Blocks that were invalidated by new block.
|
||||
pub retracted: Vec<H256>,
|
||||
|
||||
@@ -9,8 +9,6 @@ use blooms::{BloomGroup, GroupPosition};
|
||||
pub struct ExtrasUpdate<'a> {
|
||||
/// Block info.
|
||||
pub info: BlockInfo,
|
||||
/// Block timestamp.
|
||||
pub timestamp: u64,
|
||||
/// Current block uncompressed rlp bytes
|
||||
pub block: &'a [u8],
|
||||
/// Modified block hashes.
|
||||
|
||||
@@ -32,16 +32,16 @@ const HEAVY_VERIFY_RATE: f32 = 0.02;
|
||||
/// Ancient block verifier: import an ancient sequence of blocks in order from a starting
|
||||
/// epoch.
|
||||
pub struct AncientVerifier {
|
||||
cur_verifier: RwLock<Box<EpochVerifier<EthereumMachine>>>,
|
||||
cur_verifier: RwLock<Option<Box<EpochVerifier<EthereumMachine>>>>,
|
||||
engine: Arc<EthEngine>,
|
||||
}
|
||||
|
||||
impl AncientVerifier {
|
||||
/// Create a new ancient block verifier with the given engine and initial verifier.
|
||||
pub fn new(engine: Arc<EthEngine>, start_verifier: Box<EpochVerifier<EthereumMachine>>) -> Self {
|
||||
/// Create a new ancient block verifier with the given engine.
|
||||
pub fn new(engine: Arc<EthEngine>) -> Self {
|
||||
AncientVerifier {
|
||||
cur_verifier: RwLock::new(start_verifier),
|
||||
engine: engine,
|
||||
cur_verifier: RwLock::new(None),
|
||||
engine,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,17 +53,49 @@ impl AncientVerifier {
|
||||
header: &Header,
|
||||
chain: &BlockChain,
|
||||
) -> Result<(), ::error::Error> {
|
||||
match rng.gen::<f32>() <= HEAVY_VERIFY_RATE {
|
||||
true => self.cur_verifier.read().verify_heavy(header)?,
|
||||
false => self.cur_verifier.read().verify_light(header)?,
|
||||
// perform verification
|
||||
let verified = if let Some(ref cur_verifier) = *self.cur_verifier.read() {
|
||||
match rng.gen::<f32>() <= HEAVY_VERIFY_RATE {
|
||||
true => cur_verifier.verify_heavy(header)?,
|
||||
false => cur_verifier.verify_light(header)?,
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
// when there is no verifier initialize it.
|
||||
// We use a bool flag to avoid double locking in the happy case
|
||||
if !verified {
|
||||
{
|
||||
let mut cur_verifier = self.cur_verifier.write();
|
||||
if cur_verifier.is_none() {
|
||||
*cur_verifier = Some(self.initial_verifier(header, chain)?);
|
||||
}
|
||||
}
|
||||
// Call again to verify.
|
||||
return self.verify(rng, header, chain);
|
||||
}
|
||||
|
||||
// ancient import will only use transitions obtained from the snapshot.
|
||||
if let Some(transition) = chain.epoch_transition(header.number(), header.hash()) {
|
||||
let v = self.engine.epoch_verifier(&header, &transition.proof).known_confirmed()?;
|
||||
*self.cur_verifier.write() = v;
|
||||
*self.cur_verifier.write() = Some(v);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn initial_verifier(&self, header: &Header, chain: &BlockChain)
|
||||
-> Result<Box<EpochVerifier<EthereumMachine>>, ::error::Error>
|
||||
{
|
||||
trace!(target: "client", "Initializing ancient block restoration.");
|
||||
let current_epoch_data = chain.epoch_transitions()
|
||||
.take_while(|&(_, ref t)| t.block_number < header.number())
|
||||
.last()
|
||||
.map(|(_, t)| t.proof)
|
||||
.expect("At least one epoch entry (genesis) always stored; qed");
|
||||
|
||||
self.engine.epoch_verifier(&header, ¤t_epoch_data).known_confirmed()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,105 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use ethereum_types::H256;
|
||||
use bytes::Bytes;
|
||||
use ethereum_types::H256;
|
||||
use transaction::UnverifiedTransaction;
|
||||
use blockchain::ImportRoute;
|
||||
use std::time::Duration;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Messages to broadcast via chain
|
||||
pub enum ChainMessageType {
|
||||
/// Consensus message
|
||||
Consensus(Vec<u8>),
|
||||
/// Message with private transaction
|
||||
PrivateTransaction(Vec<u8>),
|
||||
/// Message with signed private transaction
|
||||
SignedPrivateTransaction(Vec<u8>),
|
||||
}
|
||||
|
||||
/// Route type to indicate whether it is enacted or retracted.
|
||||
#[derive(Clone)]
|
||||
pub enum ChainRouteType {
|
||||
/// Enacted block
|
||||
Enacted,
|
||||
/// Retracted block
|
||||
Retracted
|
||||
}
|
||||
|
||||
/// A complete chain enacted retracted route.
|
||||
#[derive(Default, Clone)]
|
||||
pub struct ChainRoute {
|
||||
route: Vec<(H256, ChainRouteType)>,
|
||||
enacted: Vec<H256>,
|
||||
retracted: Vec<H256>,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a [ImportRoute]> for ChainRoute {
|
||||
fn from(import_results: &'a [ImportRoute]) -> ChainRoute {
|
||||
ChainRoute::new(import_results.iter().flat_map(|route| {
|
||||
route.retracted.iter().map(|h| (*h, ChainRouteType::Retracted))
|
||||
.chain(route.enacted.iter().map(|h| (*h, ChainRouteType::Enacted)))
|
||||
}).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl ChainRoute {
|
||||
/// Create a new ChainRoute based on block hash and route type pairs.
|
||||
pub fn new(route: Vec<(H256, ChainRouteType)>) -> Self {
|
||||
let (enacted, retracted) = Self::to_enacted_retracted(&route);
|
||||
|
||||
Self { route, enacted, retracted }
|
||||
}
|
||||
|
||||
/// Gather all non-duplicate enacted and retracted blocks.
|
||||
fn to_enacted_retracted(route: &[(H256, ChainRouteType)]) -> (Vec<H256>, Vec<H256>) {
|
||||
fn map_to_vec(map: Vec<(H256, bool)>) -> Vec<H256> {
|
||||
map.into_iter().map(|(k, _v)| k).collect()
|
||||
}
|
||||
|
||||
// Because we are doing multiple inserts some of the blocks that were enacted in import `k`
|
||||
// could be retracted in import `k+1`. This is why to understand if after all inserts
|
||||
// the block is enacted or retracted we iterate over all routes and at the end final state
|
||||
// will be in the hashmap
|
||||
let map = route.iter().fold(HashMap::new(), |mut map, route| {
|
||||
match &route.1 {
|
||||
&ChainRouteType::Enacted => {
|
||||
map.insert(route.0, true);
|
||||
},
|
||||
&ChainRouteType::Retracted => {
|
||||
map.insert(route.0, false);
|
||||
},
|
||||
}
|
||||
map
|
||||
});
|
||||
|
||||
// Split to enacted retracted (using hashmap value)
|
||||
let (enacted, retracted) = map.into_iter().partition(|&(_k, v)| v);
|
||||
// And convert tuples to keys
|
||||
(map_to_vec(enacted), map_to_vec(retracted))
|
||||
}
|
||||
|
||||
/// Consume route and return the enacted retracted form.
|
||||
pub fn into_enacted_retracted(self) -> (Vec<H256>, Vec<H256>) {
|
||||
(self.enacted, self.retracted)
|
||||
}
|
||||
|
||||
/// All non-duplicate enacted blocks.
|
||||
pub fn enacted(&self) -> &[H256] {
|
||||
&self.enacted
|
||||
}
|
||||
|
||||
/// All non-duplicate retracted blocks.
|
||||
pub fn retracted(&self) -> &[H256] {
|
||||
&self.retracted
|
||||
}
|
||||
|
||||
/// All blocks in the route.
|
||||
pub fn route(&self) -> &[(H256, ChainRouteType)] {
|
||||
&self.route
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents what has to be handled by actor listening to chain events
|
||||
pub trait ChainNotify : Send + Sync {
|
||||
@@ -24,12 +121,11 @@ pub trait ChainNotify : Send + Sync {
|
||||
&self,
|
||||
_imported: Vec<H256>,
|
||||
_invalid: Vec<H256>,
|
||||
_enacted: Vec<H256>,
|
||||
_retracted: Vec<H256>,
|
||||
_route: ChainRoute,
|
||||
_sealed: Vec<H256>,
|
||||
// Block bytes.
|
||||
_proposed: Vec<Bytes>,
|
||||
_duration: u64,
|
||||
_duration: Duration,
|
||||
) {
|
||||
// does nothing by default
|
||||
}
|
||||
@@ -45,11 +141,11 @@ pub trait ChainNotify : Send + Sync {
|
||||
}
|
||||
|
||||
/// fires when chain broadcasts a message
|
||||
fn broadcast(&self, _data: Vec<u8>) {}
|
||||
fn broadcast(&self, _message_type: ChainMessageType) {}
|
||||
|
||||
/// fires when new transactions are received from a peer
|
||||
fn transactions_received(&self,
|
||||
_hashes: Vec<H256>,
|
||||
_txs: &[UnverifiedTransaction],
|
||||
_peer_id: usize,
|
||||
) {
|
||||
// does nothing by default
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user