Compare commits

...

95 Commits

Author SHA1 Message Date
arkpar
a65a556239 Disconnect peers on a fork 2016-12-10 16:32:10 +01:00
arkpar
268c6d15c0 v1.3.15 2016-12-10 10:50:49 +01:00
Gav Wood
88c3520563 Merge pull request #3616 from ethcore/stable-testing
Backporting to stable
2016-11-25 18:44:02 +01:00
Arkadiy Paronyan
1c45c910cc Fix panic on importing own invalid transaction (#3550) 2016-11-25 14:37:58 +01:00
arkpar
d6df25e871 --testnet set to ropset 2016-11-25 13:27:23 +01:00
Arkadiy Paronyan
036518d767 Ropsten network (#3539)
* Ropsten network

* Sorted premine

* Comas

* Removed trailing coma
2016-11-25 13:11:50 +01:00
arkpar
d8d7d9b2bc v1.3.14 2016-11-25 12:58:10 +01:00
arkpar
a50974e61b Better handle sync reorgs 2016-11-25 12:53:40 +01:00
Gav Wood
b669dbb390 Merge pull request #3521 from ethcore/stable-testing
[stable] Check tx signatures before adding to the queue.
2016-11-19 02:50:52 +08:00
Arkadiy Paronyan
45d8fc9bf1 Check transaction signature when adding to the queue (#3508) 2016-11-18 18:14:43 +01:00
arkpar
2981a23880 v1.3.13 2016-11-18 18:08:28 +01:00
kumavis
76952ff363 Fix Stable Docker Build (#3479)
* Dockerfile for ubuntu stable

Add Dockerfile for parity stable branch

* Update Dockerfile

add make
2016-11-16 22:19:42 +01:00
arkpar
1cd3e0f1cd Removed -Z orbit 2016-11-16 12:09:26 +01:00
Gav Wood
8d76dd3127 Merge pull request #3462 from ethcore/stable-testing
[stable] EIP-170
2016-11-16 11:22:50 +08:00
Arkadiy Paronyan
e09d99b94c Updated tests 2016-11-15 20:56:49 +01:00
arkpar
0cb2c866b9 fixed test 2016-11-15 20:44:26 +01:00
Gav Wood
b1fdafea3f Update max code size. 2016-11-15 20:43:21 +01:00
Gav Wood
116e18d2c6 Fix test. 2016-11-15 20:42:40 +01:00
Gav Wood
652bb6bd94 Introduce the actual max code size. 2016-11-15 20:42:01 +01:00
Gav Wood
08a6ce9642 Restrict max code size to 23999 bytes for EIP-150 and after. 2016-11-15 20:40:53 +01:00
arkpar
e4ab13b4fa update HF block number 2016-11-15 17:57:56 +01:00
arkpar
18939f7f69 update HF block number 2016-11-15 16:29:41 +01:00
arkpar
9442e6c26a v1.3.12 2016-11-15 16:27:34 +01:00
Arkadiy Paronyan
c2803d3d45 Merge pull request #3441 from ethcore/backport
#3035 Backport to stable
2016-11-15 13:35:09 +01:00
Tomasz Drwięga
45e0d28129 Fixing last hashes for ethcall (#3043) 2016-11-15 09:39:37 +01:00
Arkadiy Paronyan
080ec8043f [stable] Disable HF and UI (#3372)
* Disable the HF

* Disabled the UI

* v1.3.11
2016-11-11 16:54:25 +01:00
Arkadiy Paronyan
7972c27b61 EIP-155 update with Vitalik's new test vectors (#3166) (#3190)
* Vitalik's new test vectors.

* Update to latest EIP155 spec.

* Fix txs.

* Another fix.
2016-11-04 16:01:31 +01:00
Arkadiy Paronyan
17c133cd01 Version=stable (#3156) 2016-11-04 00:24:29 +01:00
Arkadiy Paronyan
6a4408cebc Backporting to beta (#3149)
* The front-end for each hard-fork, also EIP-160.

* Address EIP161 a/c

* Include EIP-161b

* EIP-161 part d.

* Fix test build.

* Fix one test, add another.

* Fix use of bloom & renaming.

* Fixed tests

* Initial groundwork for EIP-155

* Fix minor bug.

* Fix all tests finally.

* Rest of EIP-155.

* Add tests for EIP-155 algorithm.

Update transaction tests validation.

* Address grumbles.

* Remove unused code.

* Resolve IPC issues

* Fixed tests

* ipc backports

* Fixing random test failures (#2577)

* Fix SUICIDE gas mechanism and add consensus tests.

* Remove commented code.

* Set Frontier hardfork block number

* Transaction tests,

* Fixed tests

* Removed banning queue
2016-11-03 22:40:43 +01:00
Robert Habermeier
78d3f5fce9 apply post-consolidation migrations after consolidating (#3048) 2016-11-01 16:13:55 +01:00
Arkadiy Paronyan
93327e8c73 Fix the brainwallet functionality. (#2994) (#3005) 2016-10-31 14:07:55 +01:00
Tomasz Drwięga
54da6aef33 Bumping json-ipc-server (#2989) 2016-10-30 17:48:50 +01:00
Arkadiy Paronyan
22dc6e9ee9 Backports for 1.3.10 (#2987)
* Prevent database corruption on OOM (#2832)

* Prevent database corruption on OOM

* Renamed write_flushing

* v1.3.10
2016-10-30 14:56:34 +01:00
Denis S. Soldatov aka General-Beck
ee0f1250ac Update gitlab-ci
fix darwin md5
2016-10-27 23:12:48 +07:00
Denis S. Soldatov aka General-Beck
8c01766d90 Update deb-build.sh
change emai
2016-10-26 11:42:47 +07:00
Denis S. Soldatov aka General-Beck
eb15c82fff Update gtlab-ci
add build deb packages (amd64, arm64,armhh)
2016-10-26 10:53:37 +07:00
Denis S. Soldatov aka General-Beck
e9f4819640 Up 2016-10-25 13:33:53 +07:00
Denis S. Soldatov aka General-Beck
5618fa7a09 Update gitlab-ci
remove cd ..
[ci-skip]
2016-10-25 13:32:51 +07:00
Denis S. Soldatov aka General-Beck
2f2614e0eb Update gitlab-ci
build amd64
2016-10-25 13:06:53 +07:00
Denis S. Soldatov aka General-Beck
91903ac9e7 Update gitlab-ci
test deb build
2016-10-25 09:55:39 +07:00
Denis S. Soldatov aka General-Beck
3327dc9aef Update gitlab-ci
[skip-ci]
remove dpkg-deb
2016-10-25 09:46:16 +07:00
Denis S. Soldatov aka General-Beck
b80aa9c3e4 Update gitlab-ci
remove cp
[ci-skip]
2016-10-25 09:44:00 +07:00
Denis S. Soldatov aka General-Beck
d5ecd8f20f create deb-build.sh
initial build .deb packages
2016-10-25 10:39:14 +08:00
Arkadiy Paronyan
e9987c448e Resolve morden fork (#2776) 2016-10-21 12:05:37 +02:00
Arkadiy Paronyan
aac7815712 Fixing botched merge (#2767)
* Fix botched merge

* Test for 'exists'
2016-10-20 23:35:14 +02:00
Arkadiy Paronyan
b3097c8036 Backports for beta (#2764)
* v1.3.9

* Block import optimization (#2748)

* Block import optimization

* whitespace

[ci:none]

* Don't add empty accounts to bloom (#2753)

* Incrementally calculate verification queue heap size (#2749)

* incrementally calculate queue heap size

* query the correct queue sizes
2016-10-20 20:40:50 +02:00
Gav Wood
e5ae24dfb6 Introduce EIP150 hardfork block for ETC (#2736)
* Introduce EIP150 hardfork block for ETC

* Bumping json tests
2016-10-19 23:50:07 +02:00
Tomasz Drwięga
1b36a2cd87 fix issues with no test dir present (#2659) (#2724) 2016-10-19 18:33:04 +02:00
Tomasz Drwięga
b078d71293 Bumping jsonrpc-http-server (#2715) 2016-10-19 12:36:26 +02:00
Tomasz Drwięga
1df84a8e28 fix migration system, better errors (#2661) 2016-10-18 16:34:58 +02:00
Tomasz Drwięga
e0778fc069 [beta] EIP150.1c (#2599)
* EIP150.1c

Conflicts:
	ethcore/res/ethereum/expanse.json
	ethcore/res/ethereum/morden.json
	ethcore/res/ethereum/tests
	ethcore/src/blockchain/blockchain.rs
	ethcore/src/ethereum/ethash.rs
	ethcore/src/evm/interpreter/mod.rs
	json/src/spec/ethash.rs

* Update json test suite (#2574)

* update json test suite

* comment out the incomplete test

Conflicts:
	ethcore/res/ethereum/tests

* Updating tests

* Adding state tests

* Updating tests

* Updating HF block

* Removing flushln [ci:skip]

* Commenting out suicide test

* New tests.

* Switch to EIP tests.

* Rename some stuff, combine transition tests.

* Fix U256 overflows.

* Name cleanups and an effort to fix tests.

* Rename back for clarity.

* Fix non-EIP-150 OOG CALLs

* New transition block number & additional EIP150 tests

* Morden transition block set; Tests updated

* Added missing test
2016-10-15 15:16:26 +02:00
Arkadiy Paronyan
2ce43434f1 Revert "Bloom upgrade in beta" (#2635) 2016-10-15 13:15:45 +02:00
Arkadiy Paronyan
18062f11dc Remove count limit for local transactions (#2634) 2016-10-15 12:29:27 +02:00
Nikolay Volf
d66bd3c83a Bloom upgrade in beta (#2609)
* bloom expand & upgrade logic

* remove arc

* progress tracker

* comment about magic number

* progress tick initial
2016-10-14 17:27:47 +02:00
Arkadiy Paronyan
935e8dcf56 Backports to beta (#2628)
* v1.3.8

* mitigate refcell conflict in state diffing (#2601)

* mitigate refcell conflict in state diffing

Also uses RefCell::get_mut in a few places.

* Add test case

* Fixed stalled sync

* Fixed tx queue limit for local transactions (#2616)

* Fixed tx queue limit for local tx

* Fixing test

* Increas gas limit to 20x

* Additional logs when transactions is removed from queue (#2617)

* Database performance tweaks (#2619)
2016-10-14 17:26:35 +02:00
Arkadiy Paronyan
3c2c356f73 Tweak DB and mining defaults (#2598)
* Increase WAL size

* Decreased default work queue size
2016-10-12 20:44:25 +02:00
Arkadiy Paronyan
6b4d0cea6b Configurable history size in beta (#2587)
* Reduce DB history

* Configurable history size

* Set min history size

* Test

* Fixed a test and reduced the limit
2016-10-12 20:44:17 +02:00
Denis S. Soldatov aka General-Beck
13de1ebc8e Update gitlab-ci
remove arm builds from `master`
2016-10-13 00:20:33 +07:00
Arkadiy Paronyan
1fdb033db4 Backports to beta (#2592)
* TX queue gas limit config and allow local transactions over the gas limit (#2553)

* Gas limit config; Allow local transactions over the limit

* Fix typo

[ci:skip]

* v1.3.7
2016-10-12 17:33:59 +02:00
Denis S. Soldatov aka General-Beck
c1f0ea2016 Update gitlab-ci
installer.exe -> InstallParity.exe
2016-10-12 22:33:17 +07:00
Denis S. Soldatov aka General-Beck
964f556284 Update gitlab-ci
checksum -> parity.md5
2016-10-12 21:29:58 +07:00
Denis S. Soldatov aka General-Beck
8fba01a208 Update gitlab-ci
fix S3 path for win
2016-10-12 20:18:53 +07:00
Denis S. Soldatov aka General-Beck
77b49623ff Update gitlab-ci
fix win build
2016-10-12 19:55:21 +07:00
Denis S. Soldatov aka General-Beck
2a29d7a76f Update gitlab-ci
update windows biuld (add *.exe *.zip *.md5
2016-10-12 19:22:28 +07:00
Denis S. Soldatov aka General-Beck
66f684548d Update gitlab-ci
fix windows installer
2016-10-12 16:21:12 +07:00
Denis S. Soldatov aka General-Beck
ccebe473d0 Update gitlab-ci
fix errors in windows build
2016-10-12 13:27:22 +07:00
Denis S. Soldatov aka General-Beck
9707e61525 Update gitlab-ci
[ci:skip]
Deny warnings in windows build
2016-10-12 01:54:43 +07:00
Denis S. Soldatov aka General-Beck
039594de92 Update gitlab-ci
switch to curl in win build
2016-10-12 01:39:53 +07:00
Denis S. Soldatov aka General-Beck
69441b1322 Update gitlab-ci
add windows installer
2016-10-12 00:08:24 +07:00
Arkadiy Paronyan
8492e3e61d Backports to beta v1.3.6 (#2571)
* v1.3.6

* Print backtrace on panic (#2535)

* Don't activate peers on connect; Test (#2537)

* Removing unwarps from sync module (#2551)

* Remove unwrap from client module (#2554)

* remove unwraps in client

* imporve block hash expect message

* mining perf trace

* Fixed race condition in trace import (#2555)
2016-10-11 15:53:45 +02:00
Denis S. Soldatov aka General-Beck
4b7c97783b Update gitlab-ci
remove javascript tag
2016-10-08 10:51:42 +07:00
Arkadiy Paronyan
6d14c5458b Use global state cache when mining (#2529) 2016-10-08 02:00:06 +02:00
arkpar
9239a7cd9e v1.3.5 2016-10-08 01:02:41 +02:00
Arkadiy Paronyan
d27ecb6527 Transaction queue limited by gas (#2528) 2016-10-08 00:59:04 +02:00
Robert Habermeier
5502340dea Merge pull request #2521 from ethcore/update-appveyor-rustc-beta
Update appveyor rustc [beta]
2016-10-07 17:39:41 +02:00
Denis S. Soldatov aka General-Beck
2313f9b4f1 Update gitlab-ci
add javascript test
2016-10-07 22:31:09 +07:00
Robert Habermeier
324a5873d7 turn off MIR for windows builds 2016-10-07 16:07:01 +02:00
Robert Habermeier
b45e7f1c41 update rustc for appveyor to 1.12.0 2016-10-07 16:06:39 +02:00
Tomasz Drwięga
64af073bd4 Increase size of transaction queue by default (#2519)
Conflicts:
	ethcore/src/miner/miner.rs
	parity/cli/config.full.toml
	parity/cli/mod.rs
	parity/configuration.rs
2016-10-07 14:11:33 +01:00
Arkadiy Paronyan
fe83046198 Backport to beta (#2518)
* Handle reorganizations in the state cache

* Renamed and documented a few methods

* Basic test

* Renamed pending to buffered

* Caching optimizations

* Fixed a test

* Fixed a test
2016-10-07 14:09:52 +01:00
Tomasz Drwięga
8031910892 [beta] Fixing RPC Filter conversion to EthFilter (#2501)
* Fixing RPC Filter conversion to EthFilter

Conflicts:
	rpc/src/v1/impls/eth.rs
	rpc/src/v1/types/filter.rs

* Removing limit

* Fixing rpc tests
2016-10-07 12:16:09 +01:00
Tomasz Drwięga
73a3dac38c [beta] Using pending block only if is not old (#2515)
* Using pending block only if not old

Conflicts:
	ethcore/src/miner/miner.rs
	rpc/src/v1/impls/eth.rs
	rpc/src/v1/impls/eth_filter.rs

* Fixing compilation issues
2016-10-07 11:46:17 +01:00
Arkadiy Paronyan
bbaf5ed4f5 Backports into beta (#2512)
* RocksDB version bump

* Preserve cache on reverting the snapshot (#2488)

* Preserve cache on reverting the snapshot

* Renamed merge_with into replace_with

* Renamed and documented snapshotting methods

* Track dirty accounts in the state (#2461)

* State to track dirty accounts

* Removed clone_for_snapshot

* Renaming stuff

* Documentation and other minor fixes

* Replaced MaybeAccount with Option

* Adjustable stack size for EVM (#2483)

* stack size for io workers & evm threshold

* rust way to remember stack size

* right value

* 24kb size

* some stack reduction

* Fixed overflow panic in handshake_panic (#2495)
2016-10-07 10:49:48 +01:00
Tomasz Drwięga
9cf777510f CLI to specify queue ordering strategy (#2494)
* Alter gas priorities to include gas_price also

* CLI options and tests

* Adding ordering by gas

* whitespace

[ci:skip]
2016-10-07 09:04:13 +02:00
Nikolay Volf
9b398421ce Run inplace upgrades after version update (#2411)
* Update migration.rs

In highly unlikely scenario when the bloom update fails it will at least try again on the next run

* proper exchange
2016-10-07 09:03:49 +02:00
Tomasz Drwięga
a618dcaaf0 Fixing penalization in future (#2493) 2016-10-06 15:52:09 +01:00
Nikolay Volf
50021c7611 Fix ethstore opening all key files in the directory at once (BETA) (#2472)
* get rid of collects & zips

* not an option here!
2016-10-05 15:41:48 +02:00
Denis S. Soldatov aka General-Beck
f62d2e6ea8 Update gitlab-ci
fix windows
2016-10-05 10:54:01 +07:00
Denis S. Soldatov aka General-Beck
7da8e7926d Update gitlab-ci
set RUSTFLAGS=-Zorbit=off windows
2016-10-05 08:38:33 +07:00
Denis S. Soldatov aka General-Beck
5363e75f3a Update gitlab-ci
add RUSTFLAGS=-Zorbit=false in windows build
2016-10-05 08:04:56 +07:00
Arkadiy Paronyan
31d667a29a Merge pull request #2465 from ethcore/beta-staging
Beta backports
2016-10-05 00:24:13 +02:00
arkpar
ca2bc92dda Fixing tests 2016-10-04 23:24:16 +02:00
Marek Kotewicz
a0b71a9f52 fixed #2263, geth keys with ciphertext shorter than 32 bytes (#2318)
* fixed #2263, geth keys with ciphertext shorter than 32 bytes

* replace unwrap with more helpful expect

* tests for decrypting short secrets
2016-10-04 22:08:31 +02:00
arkpar
300c0c120b v1.3.4 2016-10-04 22:00:59 +02:00
Nikolay Volf
b228dc7b54 IPC-library dependency fork & bump for beta (#2455)
* bump json-ipc-server

* bump again
2016-10-04 18:18:07 +02:00
138 changed files with 4443 additions and 1992 deletions

2
.gitignore vendored
View File

@@ -30,3 +30,5 @@
# Build artifacts
out/
.vscode

View File

@@ -5,6 +5,7 @@ variables:
GIT_DEPTH: "3"
SIMPLECOV: "true"
RUST_BACKTRACE: "1"
RUSTFLAGS: "-D warnings"
cache:
key: "$CI_BUILD_NAME/$CI_BUILD_REF_NAME"
untracked: true
@@ -19,11 +20,18 @@ linux-stable:
script:
- cargo build --release --verbose
- strip target/release/parity
- md5sum target/release/parity >> checksum
- md5sum target/release/parity >> parity.md5
- sh scripts/deb-build.sh amd64
- cp target/release/parity deb/usr/bin/parity
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
- dpkg-deb -b deb "parity_"$VER"_amd64.deb"
- md5sum "parity_"$VER"_amd64.deb" >> "parity_"$VER"_amd64.deb.md5"
- aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/parity --body target/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/checksum --body checksum
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/parity.md5 --body parity.md5
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/"parity_"$VER"_amd64.deb" --body "parity_"$VER"_amd64.deb"
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/"parity_"$VER"_amd64.deb.md5" --body "parity_"$VER"_amd64.deb.md5"
tags:
- rust
- rust-stable
@@ -42,11 +50,18 @@ linux-stable-14.04:
script:
- cargo build --release --verbose
- strip target/release/parity
- md5sum target/release/parity >> checksum
- md5sum target/release/parity >> parity.md5
- sh scripts/deb-build.sh amd64
- cp target/release/parity deb/usr/bin/parity
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
- dpkg-deb -b deb "parity_"$VER"_amd64.deb"
- md5sum "parity_"$VER"_amd64.deb" >> "parity_"$VER"_amd64.deb.md5"
- aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-ubuntu_14_04-gnu/parity --body target/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-ubuntu_14_04-gnu/checksum --body checksum
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-ubuntu_14_04-gnu/parity.md5 --body parity.md5
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-ubuntu_14_04-gnu/"parity_"$VER"_amd64.deb" --body "parity_"$VER"_amd64.deb"
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-ubuntu_14_04-gnu/"parity_"$VER"_amd64.deb.md5" --body "parity_"$VER"_amd64.deb.md5"
tags:
- rust
- rust-14.04
@@ -105,11 +120,11 @@ linux-centos:
- export CC="gcc"
- cargo build --release --verbose
- strip target/release/parity
- md5sum target/release/parity >> checksum
- md5sum target/release/parity >> parity.md5
- aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/parity --body target/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/checksum --body checksum
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/parity.md5 --body parity.md5
tags:
- rust
- rust-centos
@@ -121,7 +136,6 @@ linux-armv7:
stage: build
image: ethcore/rust-armv7:latest
only:
- master
- beta
- tags
- stable
@@ -133,11 +147,18 @@ linux-armv7:
- cat .cargo/config
- cargo build --target armv7-unknown-linux-gnueabihf --release --verbose
- arm-linux-gnueabihf-strip target/armv7-unknown-linux-gnueabihf/release/parity
- md5sum target/armv7-unknown-linux-gnueabihf/release/parity >> checksum
- md5sum target/armv7-unknown-linux-gnueabihf/release/parity >> parity.md5
- sh scripts/deb-build.sh armhf
- cp target/armv7-unknown-linux-gnueabihf/release/parity deb/usr/bin/parity
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
- dpkg-deb -b deb "parity_"$VER"_armhf.deb"
- md5sum "parity_"$VER"_armhf.deb" >> "parity_"$VER"_armhf.deb.md5"
- aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/parity --body target/armv7-unknown-linux-gnueabihf/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/checksum --body checksum
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/parity.md5 --body parity.md5
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/"parity_"$VER"_armhf.deb" --body "parity_"$VER"_armhf.deb"
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/"parity_"$VER"_armhf.deb.md5" --body "parity_"$VER"_armhf.deb.md5"
tags:
- rust
- rust-arm
@@ -150,7 +171,6 @@ linux-arm:
stage: build
image: ethcore/rust-arm:latest
only:
- master
- beta
- tags
- stable
@@ -162,11 +182,18 @@ linux-arm:
- cat .cargo/config
- cargo build --target arm-unknown-linux-gnueabihf --release --verbose
- arm-linux-gnueabihf-strip target/arm-unknown-linux-gnueabihf/release/parity
- md5sum target/arm-unknown-linux-gnueabihf/release/parity >> checksum
- md5sum target/arm-unknown-linux-gnueabihf/release/parity >> parity.md5
- sh scripts/deb-build.sh armhf
- cp target/arm-unknown-linux-gnueabihf/release/parity deb/usr/bin/parity
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
- dpkg-deb -b deb "parity_"$VER"_armhf.deb"
- md5sum "parity_"$VER"_armhf.deb" >> "parity_"$VER"_armhf.deb.md5"
- aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/parity --body target/arm-unknown-linux-gnueabihf/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/checksum --body checksum
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/parity.md5 --body parity.md5
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/"parity_"$VER"_armhf.deb" --body "parity_"$VER"_armhf.deb"
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/"parity_"$VER"_armhf.deb.md5" --body "parity_"$VER"_armhf.deb.md5"
tags:
- rust
- rust-arm
@@ -179,7 +206,6 @@ linux-armv6:
stage: build
image: ethcore/rust-armv6:latest
only:
- master
- beta
- tags
- stable
@@ -191,11 +217,11 @@ linux-armv6:
- cat .cargo/config
- cargo build --target arm-unknown-linux-gnueabi --release --verbose
- arm-linux-gnueabi-strip target/arm-unknown-linux-gnueabi/release/parity
- md5sum target/arm-unknown-linux-gnueabi/release/parity >> checksum
- md5sum target/arm-unknown-linux-gnueabi/release/parity >> parity.md5
- aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabi/parity --body target/arm-unknown-linux-gnueabi/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabi/checksum --body checksum
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabi/parity.md5 --body parity.md5
tags:
- rust
- rust-arm
@@ -208,7 +234,6 @@ linux-aarch64:
stage: build
image: ethcore/rust-aarch64:latest
only:
- master
- beta
- tags
- stable
@@ -220,11 +245,18 @@ linux-aarch64:
- cat .cargo/config
- cargo build --target aarch64-unknown-linux-gnu --release --verbose
- aarch64-linux-gnu-strip target/aarch64-unknown-linux-gnu/release/parity
- md5sum target/aarch64-unknown-linux-gnu/release/parity >> checksum
- md5sum target/aarch64-unknown-linux-gnu/release/parity >> parity.md5
- sh scripts/deb-build.sh arm64
- cp target/aarch64-unknown-linux-gnu/release/parity deb/usr/bin/parity
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
- dpkg-deb -b deb "parity_"$VER"_arm64.deb"
- md5sum "parity_"$VER"_arm64.deb" >> "parity_"$VER"_arm64.deb.md5"
- aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/aarch64-unknown-linux-gnu/parity --body target/aarch64-unknown-linux-gnu/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/aarch64-unknown-linux-gnu/checksum --body checksum
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/aarch64-unknown-linux-gnu/parity.md5 --body parity.md5
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/aarch64-unknown-linux-gnu/"parity_"$VER"_arm64.deb" --body "parity_"$VER"_arm64.deb"
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/aarch64-unknown-linux-gnu/"parity_"$VER"_arm64.deb.md5" --body "parity_"$VER"_arm64.deb.md5"
tags:
- rust
- rust-arm
@@ -242,11 +274,12 @@ darwin:
- stable
script:
- cargo build --release --verbose
- md5sum target/release/parity >> checksum
- rm -rf parity.md5
- md5sum target/release/parity >> parity.md5
- aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-apple-darwin/parity --body target/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-apple-darwin/checksum --body checksum
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-apple-darwin/parity.md5 --body parity.md5
tags:
- osx
artifacts:
@@ -264,20 +297,42 @@ windows:
- set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include;C:\vs2015\VC\include;C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt
- set LIB=C:\vs2015\VC\lib;C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10240.0\ucrt\x64
- set RUST_BACKTRACE=1
- rustup default 1.11.0-x86_64-pc-windows-msvc
- set RUSTFLAGS=%RUSTFLAGS% -D warnings
- rustup default stable-x86_64-pc-windows-msvc
- cargo build --release --verbose
- md5sum target\release\parity >> checksum
- curl -sL --url "https://github.com/ethcore/win-build/raw/master/SimpleFC.dll" -o nsis\SimpleFC.dll
- curl -sL --url "https://github.com/ethcore/win-build/raw/master/vc_redist.x64.exe" -o nsis\vc_redist.x64.exe
- signtool sign /f %keyfile% /p %certpass% target\release\parity.exe
- cd nsis
- makensis.exe installer.nsi
- copy installer.exe InstallParity.exe
- signtool sign /f %keyfile% /p %certpass% InstallParity.exe
- md5sums InstallParity.exe > InstallParity.exe.md5
- zip win-installer.zip InstallParity.exe InstallParity.exe.md5
- md5sums win-installer.zip > win-installer.zip.md5
- cd ..\target\release\
- md5sums parity.exe parity.pdb > parity.md5
- md5sums parity.exe > parity.exe.md5
- zip parity.zip parity.exe parity.pdb parity.md5
- md5sums parity.zip > parity.zip.md5
- cd ..\..
- aws configure set aws_access_key_id %s3_key%
- aws configure set aws_secret_access_key %s3_secret%
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity --body target\release\parity.exe
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity --body target\release\parity.pdb
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/checksum --body checksum
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.exe --body target\release\parity.exe
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.exe.md5 --body target\release\parity.exe.md5
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.zip --body target\release\parity.zip
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.zip.md5 --body target\release\parity.zip.md5
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/InstallParity.exe --body nsis\InstallParity.exe
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/InstallParity.exe.md5 --body nsis\InstallParity.exe.md5
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/win-installer.zip --body nsis\win-installer.zip
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/win-installer.zip.md5 --body nsis\win-installer.zip.md5
tags:
- rust-windows
artifacts:
paths:
- target/release/parity.exe
- target/release/parity.pdb
- nsis/InstallParity.exe
name: "x86_64-pc-windows-msvc_parity"
test-linux:
stage: test

94
Cargo.lock generated
View File

@@ -1,12 +1,12 @@
[root]
name = "parity"
version = "1.3.3"
version = "1.3.15"
dependencies = [
"ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy 0.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"ctrlc 1.1.1 (git+https://github.com/ethcore/rust-ctrlc.git)",
"daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)",
"daemonize 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"docopt 0.6.86 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore 1.3.0",
"ethcore-dapps 1.3.0",
@@ -20,18 +20,18 @@ dependencies = [
"ethcore-logger 1.3.0",
"ethcore-rpc 1.3.0",
"ethcore-signer 1.3.0",
"ethcore-util 1.3.3",
"ethcore-util 1.3.15",
"ethsync 1.3.0",
"fdlimit 0.1.0",
"hyper 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"json-ipc-server 0.2.4 (git+https://github.com/ethcore/json-ipc-server.git)",
"json-ipc-server 0.2.4 (git+https://github.com/ethcore/json-ipc-server.git?branch=beta)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"number_prefix 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.68 (registry+https://github.com/rust-lang/crates.io-index)",
"rpassword 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rpassword 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -192,7 +192,7 @@ dependencies = [
[[package]]
name = "daemonize"
version = "0.2.2"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -208,12 +208,13 @@ dependencies = [
[[package]]
name = "docopt"
version = "0.6.80"
version = "0.6.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.68 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -236,7 +237,7 @@ version = "0.5.4"
source = "git+https://github.com/ethcore/rust-secp256k1#a9a0b1be1f39560ca86e8fc8e55e205a753ff25c"
dependencies = [
"arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -269,7 +270,7 @@ dependencies = [
"ethcore-ipc 1.3.0",
"ethcore-ipc-codegen 1.3.0",
"ethcore-ipc-nano 1.3.0",
"ethcore-util 1.3.3",
"ethcore-util 1.3.15",
"ethjson 0.1.0",
"ethstore 0.1.0",
"evmjit 1.3.0",
@@ -293,10 +294,10 @@ version = "1.3.0"
dependencies = [
"clippy 0.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-rpc 1.3.0",
"ethcore-util 1.3.3",
"ethcore-util 1.3.15",
"hyper 0.9.4 (git+https://github.com/ethcore/hyper)",
"jsonrpc-core 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-http-server 6.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)",
"jsonrpc-http-server 6.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git?branch=beta)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)",
@@ -335,7 +336,7 @@ name = "ethcore-ipc"
version = "1.3.0"
dependencies = [
"ethcore-devtools 1.3.0",
"ethcore-util 1.3.3",
"ethcore-util 1.3.15",
"nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)",
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -380,7 +381,7 @@ dependencies = [
"ethcore-ipc 1.3.0",
"ethcore-ipc-codegen 1.3.0",
"ethcore-ipc-nano 1.3.0",
"ethcore-util 1.3.3",
"ethcore-util 1.3.15",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)",
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -392,7 +393,7 @@ name = "ethcore-logger"
version = "1.3.0"
dependencies = [
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-util 1.3.3",
"ethcore-util 1.3.15",
"isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -407,7 +408,7 @@ dependencies = [
"ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-devtools 1.3.0",
"ethcore-io 1.3.0",
"ethcore-util 1.3.3",
"ethcore-util 1.3.15",
"igd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -431,12 +432,12 @@ dependencies = [
"ethcore-devtools 1.3.0",
"ethcore-io 1.3.0",
"ethcore-ipc 1.3.0",
"ethcore-util 1.3.3",
"ethcore-util 1.3.15",
"ethjson 0.1.0",
"ethsync 1.3.0",
"json-ipc-server 0.2.4 (git+https://github.com/ethcore/json-ipc-server.git)",
"json-ipc-server 0.2.4 (git+https://github.com/ethcore/json-ipc-server.git?branch=beta)",
"jsonrpc-core 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-http-server 6.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)",
"jsonrpc-http-server 6.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git?branch=beta)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -454,7 +455,7 @@ dependencies = [
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-io 1.3.0",
"ethcore-rpc 1.3.0",
"ethcore-util 1.3.3",
"ethcore-util 1.3.15",
"jsonrpc-core 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-dapps-signer 1.4.0 (git+https://github.com/ethcore/parity-ui.git)",
@@ -465,7 +466,7 @@ dependencies = [
[[package]]
name = "ethcore-util"
version = "1.3.3"
version = "1.3.15"
dependencies = [
"ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -498,7 +499,7 @@ dependencies = [
name = "ethjson"
version = "0.1.0"
dependencies = [
"ethcore-util 1.3.3",
"ethcore-util 1.3.15",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_codegen 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -546,7 +547,7 @@ dependencies = [
"ethcore-ipc-codegen 1.3.0",
"ethcore-ipc-nano 1.3.0",
"ethcore-network 1.3.0",
"ethcore-util 1.3.3",
"ethcore-util 1.3.15",
"heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -571,8 +572,11 @@ dependencies = [
[[package]]
name = "gcc"
version = "0.3.28"
version = "0.3.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rayon 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "glob"
@@ -706,7 +710,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "json-ipc-server"
version = "0.2.4"
source = "git+https://github.com/ethcore/json-ipc-server.git#56b6307130710ebc73cb9be087b6ed0b6c400bcf"
source = "git+https://github.com/ethcore/json-ipc-server.git?branch=beta#d9c0811fb0c4aaa5b8b98905b2d72d277675d60f"
dependencies = [
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -732,7 +736,7 @@ dependencies = [
[[package]]
name = "jsonrpc-http-server"
version = "6.1.0"
source = "git+https://github.com/ethcore/jsonrpc-http-server.git#4e3f93eb79125e91a46e04d77c25ff8885498b86"
source = "git+https://github.com/ethcore/jsonrpc-http-server.git?branch=beta#ab0e2cdc8856a4ee26f65c395583e69fd4609c88"
dependencies = [
"hyper 0.9.4 (git+https://github.com/ethcore/hyper)",
"jsonrpc-core 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -885,7 +889,7 @@ name = "nanomsg-sys"
version = "0.5.0"
source = "git+https://github.com/ethcore/nanomsg.rs.git#c40fe442c9afaea5b38009a3d992ca044dcceb00"
dependencies = [
"gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1012,7 +1016,7 @@ dependencies = [
[[package]]
name = "number_prefix"
version = "0.2.5"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1221,7 +1225,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rocksdb"
version = "0.4.5"
source = "git+https://github.com/ethcore/rust-rocksdb#485dd747a2c9a9f910fc8ac696fc9edf5fa22aa3"
source = "git+https://github.com/ethcore/rust-rocksdb#64c63ccbe1f62c2e2b39262486f9ba813793af58"
dependencies = [
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)",
@@ -1230,9 +1234,9 @@ dependencies = [
[[package]]
name = "rocksdb-sys"
version = "0.3.0"
source = "git+https://github.com/ethcore/rust-rocksdb#485dd747a2c9a9f910fc8ac696fc9edf5fa22aa3"
source = "git+https://github.com/ethcore/rust-rocksdb#64c63ccbe1f62c2e2b39262486f9ba813793af58"
dependencies = [
"gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1249,7 +1253,7 @@ dependencies = [
[[package]]
name = "rpassword"
version = "0.2.2"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1263,7 +1267,7 @@ name = "rust-crypto"
version = "0.2.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1331,7 +1335,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "sha3"
version = "0.1.0"
dependencies = [
"gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1375,7 +1379,7 @@ source = "git+https://github.com/carllerche/stable-heap?rev=3c5cd1ca47#3c5cd1ca4
[[package]]
name = "strsim"
version = "0.3.0"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -1641,13 +1645,13 @@ dependencies = [
"checksum cookie 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90266f45846f14a1e986c77d1e9c2626b8c342ed806fe60241ec38cc8697b245"
"checksum crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "fb974f835e90390c5f9dfac00f05b06dc117299f5ea4e85fbc7bb443af4911cc"
"checksum ctrlc 1.1.1 (git+https://github.com/ethcore/rust-ctrlc.git)" = "<none>"
"checksum daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "271ec51b7e0bee92f0d04601422c73eb76ececf197026711c97ad25038a010cf"
"checksum daemonize 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0239832c1b4ca406d5ec73728cf4c7336d25cf85dd32db9e047e9e706ee0e935"
"checksum deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1614659040e711785ed8ea24219140654da1729f3ec8a47a9719d041112fe7bf"
"checksum docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4cc0acb4ce0828c6a5a11d47baa432fe885881c27428c3a4e473e454ffe57a76"
"checksum docopt 0.6.86 (registry+https://github.com/rust-lang/crates.io-index)" = "4a7ef30445607f6fc8720f0a0a2c7442284b629cf0d049286860fae23e71c4d9"
"checksum elastic-array 0.4.0 (git+https://github.com/ethcore/elastic-array)" = "<none>"
"checksum env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aba65b63ffcc17ffacd6cf5aa843da7c5a25e3bd4bbe0b7def8b214e411250e5"
"checksum eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)" = "<none>"
"checksum gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)" = "3da3a2cbaeb01363c8e3704fd9fd0eb2ceb17c6f27abd4c1ef040fb57d20dc79"
"checksum gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "91ecd03771effb0c968fd6950b37e89476a578aaf1c70297d8e92b6516ec3312"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
"checksum hamming 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65043da274378d68241eb9a8f8f8aa54e349136f7b8e12f63e3ef44043cc30e1"
"checksum heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "abb306abb8d398e053cfb1b3e7b72c2f580be048b85745c52652954f8ad1439c"
@@ -1660,9 +1664,9 @@ dependencies = [
"checksum igd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c8c12b1795b8b168f577c45fa10379b3814dcb11b7ab702406001f0d63f40484"
"checksum isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7408a548dc0e406b7912d9f84c261cc533c1866e047644a811c133c56041ac0c"
"checksum itertools 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "086e1fa5fe48840b1cfdef3a20c7e3115599f8d5c4c87ef32a794a7cdd184d76"
"checksum json-ipc-server 0.2.4 (git+https://github.com/ethcore/json-ipc-server.git)" = "<none>"
"checksum json-ipc-server 0.2.4 (git+https://github.com/ethcore/json-ipc-server.git?branch=beta)" = "<none>"
"checksum jsonrpc-core 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ec4477e4e8218da23caa5dd31f4eb39999aa0ea9035660617eccfb19a23bf5ad"
"checksum jsonrpc-http-server 6.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)" = "<none>"
"checksum jsonrpc-http-server 6.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git?branch=beta)" = "<none>"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
"checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f"
@@ -1693,7 +1697,7 @@ dependencies = [
"checksum num-rational 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "48cdcc9ff4ae2a8296805ac15af88b3d88ce62128ded0cb74ffb63a587502a84"
"checksum num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "51eab148f171aefad295f8cece636fc488b9b392ef544da31ea4b8ef6b9e9c39"
"checksum num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "51fedae97a05f7353612fe017ab705a37e6db8f4d67c5c6fe739a9e70d6eed09"
"checksum number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "084d05f4bf60621a9ac9bde941a410df548f4de9545f06e5ee9d3aef4b97cd77"
"checksum number_prefix 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b09f7c223751819881e1b95670d36fb12cdaa89848147f2222f1a2b691d5f0a3"
"checksum odds 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "b28c06e81b0f789122d415d6394b5fe849bde8067469f4c2980d3cdc10c78ec1"
"checksum parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)" = "<none>"
"checksum parity-dapps-home 1.4.0 (git+https://github.com/ethcore/parity-ui.git)" = "<none>"
@@ -1721,7 +1725,7 @@ dependencies = [
"checksum rocksdb 0.4.5 (git+https://github.com/ethcore/rust-rocksdb)" = "<none>"
"checksum rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)" = "<none>"
"checksum rotor 0.6.3 (git+https://github.com/ethcore/rotor)" = "<none>"
"checksum rpassword 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5d3a99497c5c544e629cc8b359ae5ede321eba5fa8e5a8078f3ced727a976c3f"
"checksum rpassword 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "320da1dfcf5c570a6c07ff60bb7cd4cdc986d2ea89caea139f2247371ab6a1df"
"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
@@ -1738,7 +1742,7 @@ dependencies = [
"checksum solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "172382bac9424588d7840732b250faeeef88942e37b6e35317dce98cafdd75b2"
"checksum spmc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "93bdab61c1a413e591c4d17388ffa859eaff2df27f1e13a5ec8b716700605adf"
"checksum stable-heap 0.1.0 (git+https://github.com/carllerche/stable-heap?rev=3c5cd1ca47)" = "<none>"
"checksum strsim 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e4d73a2c36a4d095ed1a6df5cbeac159863173447f7a82b3f4757426844ab825"
"checksum strsim 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "50c069df92e4b01425a8bf3576d5d417943a6a7272fbabaf5bd80b1aaa76442e"
"checksum syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "393b6dd0889df2b064beeea954cfda6bc2571604ac460deeae0fed55a53988af"
"checksum syntex_syntax 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44bded3cabafc65c90b663b1071bd2d198a9ab7515e6ce729e4570aaf53c407e"
"checksum target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c63f48baada5c52e65a29eef93ab4f8982681b67f9e8d29c7b05abcfec2b9ffe"

View File

@@ -1,7 +1,7 @@
[package]
description = "Ethcore client."
name = "parity"
version = "1.3.3"
version = "1.3.15"
license = "GPL-3.0"
authors = ["Ethcore <admin@ethcore.io>"]
build = "build.rs"
@@ -39,7 +39,7 @@ ethcore-ipc-nano = { path = "ipc/nano" }
ethcore-ipc = { path = "ipc/rpc" }
ethcore-ipc-hypervisor = { path = "ipc/hypervisor" }
ethcore-logger = { path = "logger" }
json-ipc-server = { git = "https://github.com/ethcore/json-ipc-server.git" }
json-ipc-server = { git = "https://github.com/ethcore/json-ipc-server.git", branch = "beta" }
ethcore-dapps = { path = "dapps", optional = true }
clippy = { version = "0.0.80", optional = true}

View File

@@ -6,6 +6,7 @@ environment:
certpass:
secure: 0BgXJqxq9Ei34/hZ7121FQ==
keyfile: C:\users\appveyor\Certificates.p12
RUSTFLAGS: -Zorbit=off
branches:
only:
@@ -18,10 +19,10 @@ branches:
install:
- git submodule update --init --recursive
- ps: Install-Product node 6
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.10.0-x86_64-pc-windows-msvc.exe"
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.12.0-x86_64-pc-windows-msvc.exe"
- ps: Start-FileDownload "https://github.com/ethcore/win-build/raw/master/SimpleFC.dll" -FileName nsis\SimpleFC.dll
- ps: Start-FileDownload "https://github.com/ethcore/win-build/raw/master/vc_redist.x64.exe" -FileName nsis\vc_redist.x64.exe
- rust-1.10.0-x86_64-pc-windows-msvc.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
- rust-1.12.0-x86_64-pc-windows-msvc.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
- SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin;C:\Program Files (x86)\NSIS;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Bin
- rustc -V
- cargo -V

View File

@@ -11,7 +11,7 @@ build = "build.rs"
[dependencies]
log = "0.3"
jsonrpc-core = "2.1"
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc-http-server.git" }
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc-http-server.git", branch = "beta" }
hyper = { default-features = false, git = "https://github.com/ethcore/hyper" }
unicase = "1.3"
url = "1.0"

View File

@@ -0,0 +1,40 @@
FROM ubuntu:14.04
WORKDIR /build
# install tools and dependencies
RUN apt-get update && \
apt-get install -y \
g++ \
curl \
git \
file \
binutils \
make
# 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
RUN git clone https://github.com/ethcore/parity && \
cd parity && \
git checkout stable && \
git pull && \
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"]

View File

@@ -18,6 +18,6 @@ extern crate ethcore_ipc_codegen;
fn main() {
ethcore_ipc_codegen::derive_binary("src/types/mod.rs.in").unwrap();
ethcore_ipc_codegen::derive_ipc("src/client/traits.rs").unwrap();
ethcore_ipc_codegen::derive_ipc("src/client/chain_notify.rs").unwrap();
ethcore_ipc_codegen::derive_ipc_cond("src/client/traits.rs", cfg!(feature="ipc")).unwrap();
ethcore_ipc_codegen::derive_ipc_cond("src/client/chain_notify.rs", cfg!(feature="ipc")).unwrap();
}

View File

@@ -10,7 +10,12 @@
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0x118c30"
"homesteadTransition": "0x118c30",
"eip150Transition": "0x2625a0",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
}
}
},

View File

@@ -0,0 +1,47 @@
{
"name": "Homestead (Test)",
"engine": {
"Ethash": {
"params": {
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"homesteadTransition": "0x0",
"eip150Transition": "0x0",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
}
}
},
"params": {
"accountStartNonce": "0x00",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x1"
},
"genesis": {
"seal": {
"ethereum": {
"nonce": "0x0000000000000042",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x400000000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"gasLimit": "0x1388"
},
"accounts": {
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }
}
}

View File

@@ -0,0 +1,47 @@
{
"name": "Homestead (Test)",
"engine": {
"Ethash": {
"params": {
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"homesteadTransition": "0x0",
"eip150Transition": "0x0",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x0",
"eip161abcTransition": "0x0",
"eip161dTransition": "0x0"
}
}
},
"params": {
"accountStartNonce": "0x00",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x1"
},
"genesis": {
"seal": {
"ethereum": {
"nonce": "0x0000000000000042",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x400000000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"gasLimit": "0x1388"
},
"accounts": {
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }
}
}

View File

@@ -0,0 +1,74 @@
{
"name": "Expanse",
"forkName": "expanse",
"engine": {
"Ethash": {
"params": {
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"difficultyIncrementDivisor": "60",
"durationLimit": "0x3C",
"blockReward": "0x6f05b59d3b200000",
"registrar" : "0x6c221ca53705f3497ec90ca7b84c59ae7382fc21",
"homesteadTransition": "0x30d40",
"difficultyHardforkTransition": "0x59d9",
"difficultyHardforkBoundDivisor": "0x0200",
"bombDefuseTransition": "0x30d40",
"eip150Transition": "0x7fffffffffffffff",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
}
}
},
"params": {
"accountStartNonce": "0x00",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID": "0x1",
"subprotocolName": "exp"
},
"genesis": {
"seal": {
"ethereum": {
"nonce": "0x214652414e4b4f21",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x40000000",
"author": "0x93decab0cd745598860f782ac1e8f046cb99e898",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x4672616e6b6f497346726565646f6d",
"gasLimit": "0x1388"
},
"nodes": [
"enode://7f335a047654f3e70d6f91312a7cf89c39704011f1a584e2698250db3d63817e74b88e26b7854111e16b2c9d0c7173c05419aeee2d0321850227b126d8b1be3f@46.101.156.249:42786",
"enode://df872f81e25f72356152b44cab662caf1f2e57c3a156ecd20e9ac9246272af68a2031b4239a0bc831f2c6ab34733a041464d46b3ea36dce88d6c11714446e06b@178.62.208.109:42786",
"enode://96d3919b903e7f5ad59ac2f73c43be9172d9d27e2771355db03fd194732b795829a31fe2ea6de109d0804786c39a807e155f065b4b94c6fce167becd0ac02383@45.55.22.34:42786",
"enode://5f6c625bf287e3c08aad568de42d868781e961cbda805c8397cfb7be97e229419bef9a5a25a75f97632787106bba8a7caf9060fab3887ad2cfbeb182ab0f433f@46.101.182.53:42786",
"enode://d33a8d4c2c38a08971ed975b750f21d54c927c0bf7415931e214465a8d01651ecffe4401e1db913f398383381413c78105656d665d83f385244ab302d6138414@128.199.183.48:42786",
"enode://df872f81e25f72356152b44cab662caf1f2e57c3a156ecd20e9ac9246272af68a2031b4239a0bc831f2c6ab34733a041464d46b3ea36dce88d6c11714446e06b@178.62.208.109:42786",
"enode://f6f0d6b9b7d02ec9e8e4a16e38675f3621ea5e69860c739a65c1597ca28aefb3cec7a6d84e471ac927d42a1b64c1cbdefad75e7ce8872d57548ddcece20afdd1@159.203.64.95:42786"
],
"accounts": {
"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 } } } },
"bb94f0ceb32257275b2a7a9c094c13e469b4563e": {
"balance": "10000000000000000000000000"
},
"15656715068ab0dbdf0ab00748a8a19e40f28192": {
"balance": "1000000000000000000000000"
},
"c075fa11f85bda3aaba67106226aaf086ac16f4e": {
"balance": "100000000000000000000000"
},
"93decab0cd745598860f782ac1e8f046cb99e898": {
"balance": "10000000000000000000000"
}
}
}

View File

@@ -9,10 +9,10 @@
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0x118c30",
"homesteadTransition": "0x118c30",
"daoHardforkTransition": "0x1d4c00",
"daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754",
"daoHardforkAccounts": [
"daoHardforkAccounts": [
"0xd4fe7bc31cedb7bfb8a345f31e668033056b2728",
"0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425",
"0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f",
@@ -129,7 +129,13 @@
"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97",
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
]
],
"eip150Transition": "0x259518",
"eip155Transition": "0x28d138",
"eip160Transition": "0x28d138",
"eip161abcTransition": "0x28d138",
"eip161dTransition": "0x28d138",
"maxCodeSize": 24576
}
}
},
@@ -160,7 +166,7 @@
"enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303",
"enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303",
"enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303",
"enode://248f12bc8b18d5289358085520ac78cd8076485211e6d96ab0bc93d6cd25442db0ce3a937dc404f64f207b0b9aed50e25e98ce32af5ac7cb321ff285b97de485@zero.parity.io:30303"
"enode://4cd540b2c3292e17cff39922e864094bf8b0741fcc8c5dcea14957e389d7944c70278d872902e3d0345927f621547efa659013c400865485ab4bfa0c6596936f@138.201.144.135:30303"
],
"accounts": {
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },

View File

@@ -9,7 +9,7 @@
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0x118c30",
"homesteadTransition": "0x118c30",
"daoHardforkTransition": "0x1d4c00",
"daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754",
"daoHardforkAccounts": [
@@ -129,7 +129,12 @@
"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97",
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
]
],
"eip150Transition": "0x7fffffffffffffff",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
}
}
},

View File

@@ -9,7 +9,12 @@
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0xffffffffffffffff"
"homesteadTransition": "0x7fffffffffffffff",
"eip150Transition": "0x7fffffffffffffff",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
}
}
},

View File

@@ -9,7 +9,12 @@
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0x0"
"homesteadTransition": "0x0",
"eip150Transition": "0x7fffffffffffffff",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
}
}
},

View File

@@ -9,7 +9,12 @@
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar": "0x8e4e9b13d4b45cb0befc93c3061b1408f67316b2",
"frontierCompatibilityModeLimit": "0x789b0"
"homesteadTransition": "0x789b0",
"eip150Transition": "0x1b34d8",
"eip155Transition": "0x1cc348",
"eip160Transition": "0x1cc348",
"eip161abcTransition": "0x1cc348",
"eip161dTransition": "0x1cc348"
}
}
},
@@ -17,7 +22,9 @@
"accountStartNonce": "0x0100000",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x2"
"networkID" : "0x2",
"forkBlock": "0x1b34d8",
"forkCanonHash": "0xf376243aeff1f256d970714c3de9fd78fa4e63cf63e32a51fe1169e375d98145"
},
"genesis": {
"seal": {

View File

@@ -8,7 +8,13 @@
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x08",
"blockReward": "0x14D1120D7B160000",
"registrar": "5e70c0bbcd5636e0f9f9316e9f8633feb64d4050"
"registrar": "5e70c0bbcd5636e0f9f9316e9f8633feb64d4050",
"homesteadTransition": "0x7fffffffffffffff",
"eip150Transition": "0x7fffffffffffffff",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
}
}
},

View File

@@ -0,0 +1,304 @@
{
"name": "Ropsten",
"engine": {
"Ethash": {
"params": {
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar": "0x81a4b044831c4f12ba601adb9274516939e9b8a2",
"homesteadTransition": 0,
"eip150Transition": 0,
"eip155Transition": 10,
"eip160Transition": 10,
"eip161abcTransition": 10,
"eip161dTransition": 10
}
}
},
"params": {
"accountStartNonce": "0x0",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x3"
},
"genesis": {
"seal": {
"ethereum": {
"nonce": "0x0000000000000042",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x100000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x3535353535353535353535353535353535353535353535353535353535353535",
"gasLimit": "0x1000000"
},
"nodes": [
"enode://a22f0977ce02653bf95e38730106356342df48b5222e2c2a1a6f9ef34769bf593bae9ca0a888cf60839edd52efc1b6e393c63a57d76f4c4fe14e641f1f9e637e@128.199.55.137:30303",
"enode://012239fccf3ff1d92b036983a430cb6705c6528c96c0354413f8854802138e5135c084ab36e7c54efb621c46728df8c3a6f4c1db9bb48a1330efe3f82f2dd7a6@52.169.94.142:30303"
],
"accounts": {
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "0", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0000000000000000000000000000000000000002": { "balance": "1", "nonce": "0", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0000000000000000000000000000000000000003": { "balance": "1", "nonce": "0", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0000000000000000000000000000000000000004": { "balance": "1", "nonce": "0", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
"0000000000000000000000000000000000000000": { "balance": "1" },
"0000000000000000000000000000000000000005": { "balance": "1" },
"0000000000000000000000000000000000000006": { "balance": "1" },
"0000000000000000000000000000000000000007": { "balance": "1" },
"0000000000000000000000000000000000000008": { "balance": "1" },
"0000000000000000000000000000000000000009": { "balance": "1" },
"000000000000000000000000000000000000000a": { "balance": "0" },
"000000000000000000000000000000000000000b": { "balance": "0" },
"000000000000000000000000000000000000000c": { "balance": "0" },
"000000000000000000000000000000000000000d": { "balance": "0" },
"000000000000000000000000000000000000000e": { "balance": "0" },
"000000000000000000000000000000000000000f": { "balance": "0" },
"0000000000000000000000000000000000000010": { "balance": "0" },
"0000000000000000000000000000000000000011": { "balance": "0" },
"0000000000000000000000000000000000000012": { "balance": "0" },
"0000000000000000000000000000000000000013": { "balance": "0" },
"0000000000000000000000000000000000000014": { "balance": "0" },
"0000000000000000000000000000000000000015": { "balance": "0" },
"0000000000000000000000000000000000000016": { "balance": "0" },
"0000000000000000000000000000000000000017": { "balance": "0" },
"0000000000000000000000000000000000000018": { "balance": "0" },
"0000000000000000000000000000000000000019": { "balance": "0" },
"000000000000000000000000000000000000001a": { "balance": "0" },
"000000000000000000000000000000000000001b": { "balance": "0" },
"000000000000000000000000000000000000001c": { "balance": "0" },
"000000000000000000000000000000000000001d": { "balance": "0" },
"000000000000000000000000000000000000001e": { "balance": "0" },
"000000000000000000000000000000000000001f": { "balance": "0" },
"0000000000000000000000000000000000000020": { "balance": "0" },
"0000000000000000000000000000000000000021": { "balance": "0" },
"0000000000000000000000000000000000000022": { "balance": "0" },
"0000000000000000000000000000000000000023": { "balance": "0" },
"0000000000000000000000000000000000000024": { "balance": "0" },
"0000000000000000000000000000000000000025": { "balance": "0" },
"0000000000000000000000000000000000000026": { "balance": "0" },
"0000000000000000000000000000000000000027": { "balance": "0" },
"0000000000000000000000000000000000000028": { "balance": "0" },
"0000000000000000000000000000000000000029": { "balance": "0" },
"000000000000000000000000000000000000002a": { "balance": "0" },
"000000000000000000000000000000000000002b": { "balance": "0" },
"000000000000000000000000000000000000002c": { "balance": "0" },
"000000000000000000000000000000000000002d": { "balance": "0" },
"000000000000000000000000000000000000002e": { "balance": "0" },
"000000000000000000000000000000000000002f": { "balance": "0" },
"0000000000000000000000000000000000000030": { "balance": "0" },
"0000000000000000000000000000000000000031": { "balance": "0" },
"0000000000000000000000000000000000000032": { "balance": "0" },
"0000000000000000000000000000000000000033": { "balance": "0" },
"0000000000000000000000000000000000000034": { "balance": "0" },
"0000000000000000000000000000000000000035": { "balance": "0" },
"0000000000000000000000000000000000000036": { "balance": "0" },
"0000000000000000000000000000000000000037": { "balance": "0" },
"0000000000000000000000000000000000000038": { "balance": "0" },
"0000000000000000000000000000000000000039": { "balance": "0" },
"000000000000000000000000000000000000003a": { "balance": "0" },
"000000000000000000000000000000000000003b": { "balance": "0" },
"000000000000000000000000000000000000003c": { "balance": "0" },
"000000000000000000000000000000000000003d": { "balance": "0" },
"000000000000000000000000000000000000003e": { "balance": "0" },
"000000000000000000000000000000000000003f": { "balance": "0" },
"0000000000000000000000000000000000000040": { "balance": "0" },
"0000000000000000000000000000000000000041": { "balance": "0" },
"0000000000000000000000000000000000000042": { "balance": "0" },
"0000000000000000000000000000000000000043": { "balance": "0" },
"0000000000000000000000000000000000000044": { "balance": "0" },
"0000000000000000000000000000000000000045": { "balance": "0" },
"0000000000000000000000000000000000000046": { "balance": "0" },
"0000000000000000000000000000000000000047": { "balance": "0" },
"0000000000000000000000000000000000000048": { "balance": "0" },
"0000000000000000000000000000000000000049": { "balance": "0" },
"000000000000000000000000000000000000004a": { "balance": "0" },
"000000000000000000000000000000000000004b": { "balance": "0" },
"000000000000000000000000000000000000004c": { "balance": "0" },
"000000000000000000000000000000000000004d": { "balance": "0" },
"000000000000000000000000000000000000004e": { "balance": "0" },
"000000000000000000000000000000000000004f": { "balance": "0" },
"0000000000000000000000000000000000000050": { "balance": "0" },
"0000000000000000000000000000000000000051": { "balance": "0" },
"0000000000000000000000000000000000000052": { "balance": "0" },
"0000000000000000000000000000000000000053": { "balance": "0" },
"0000000000000000000000000000000000000054": { "balance": "0" },
"0000000000000000000000000000000000000055": { "balance": "0" },
"0000000000000000000000000000000000000056": { "balance": "0" },
"0000000000000000000000000000000000000057": { "balance": "0" },
"0000000000000000000000000000000000000058": { "balance": "0" },
"0000000000000000000000000000000000000059": { "balance": "0" },
"000000000000000000000000000000000000005a": { "balance": "0" },
"000000000000000000000000000000000000005b": { "balance": "0" },
"000000000000000000000000000000000000005c": { "balance": "0" },
"000000000000000000000000000000000000005d": { "balance": "0" },
"000000000000000000000000000000000000005e": { "balance": "0" },
"000000000000000000000000000000000000005f": { "balance": "0" },
"0000000000000000000000000000000000000060": { "balance": "0" },
"0000000000000000000000000000000000000061": { "balance": "0" },
"0000000000000000000000000000000000000062": { "balance": "0" },
"0000000000000000000000000000000000000063": { "balance": "0" },
"0000000000000000000000000000000000000064": { "balance": "0" },
"0000000000000000000000000000000000000065": { "balance": "0" },
"0000000000000000000000000000000000000066": { "balance": "0" },
"0000000000000000000000000000000000000067": { "balance": "0" },
"0000000000000000000000000000000000000068": { "balance": "0" },
"0000000000000000000000000000000000000069": { "balance": "0" },
"000000000000000000000000000000000000006a": { "balance": "0" },
"000000000000000000000000000000000000006b": { "balance": "0" },
"000000000000000000000000000000000000006c": { "balance": "0" },
"000000000000000000000000000000000000006d": { "balance": "0" },
"000000000000000000000000000000000000006e": { "balance": "0" },
"000000000000000000000000000000000000006f": { "balance": "0" },
"0000000000000000000000000000000000000070": { "balance": "0" },
"0000000000000000000000000000000000000071": { "balance": "0" },
"0000000000000000000000000000000000000072": { "balance": "0" },
"0000000000000000000000000000000000000073": { "balance": "0" },
"0000000000000000000000000000000000000074": { "balance": "0" },
"0000000000000000000000000000000000000075": { "balance": "0" },
"0000000000000000000000000000000000000076": { "balance": "0" },
"0000000000000000000000000000000000000077": { "balance": "0" },
"0000000000000000000000000000000000000078": { "balance": "0" },
"0000000000000000000000000000000000000079": { "balance": "0" },
"000000000000000000000000000000000000007a": { "balance": "0" },
"000000000000000000000000000000000000007b": { "balance": "0" },
"000000000000000000000000000000000000007c": { "balance": "0" },
"000000000000000000000000000000000000007d": { "balance": "0" },
"000000000000000000000000000000000000007e": { "balance": "0" },
"000000000000000000000000000000000000007f": { "balance": "0" },
"0000000000000000000000000000000000000080": { "balance": "0" },
"0000000000000000000000000000000000000081": { "balance": "0" },
"0000000000000000000000000000000000000082": { "balance": "0" },
"0000000000000000000000000000000000000083": { "balance": "0" },
"0000000000000000000000000000000000000084": { "balance": "0" },
"0000000000000000000000000000000000000085": { "balance": "0" },
"0000000000000000000000000000000000000086": { "balance": "0" },
"0000000000000000000000000000000000000087": { "balance": "0" },
"0000000000000000000000000000000000000088": { "balance": "0" },
"0000000000000000000000000000000000000089": { "balance": "0" },
"000000000000000000000000000000000000008a": { "balance": "0" },
"000000000000000000000000000000000000008b": { "balance": "0" },
"000000000000000000000000000000000000008c": { "balance": "0" },
"000000000000000000000000000000000000008d": { "balance": "0" },
"000000000000000000000000000000000000008e": { "balance": "0" },
"000000000000000000000000000000000000008f": { "balance": "0" },
"0000000000000000000000000000000000000090": { "balance": "0" },
"0000000000000000000000000000000000000091": { "balance": "0" },
"0000000000000000000000000000000000000092": { "balance": "0" },
"0000000000000000000000000000000000000093": { "balance": "0" },
"0000000000000000000000000000000000000094": { "balance": "0" },
"0000000000000000000000000000000000000095": { "balance": "0" },
"0000000000000000000000000000000000000096": { "balance": "0" },
"0000000000000000000000000000000000000097": { "balance": "0" },
"0000000000000000000000000000000000000098": { "balance": "0" },
"0000000000000000000000000000000000000099": { "balance": "0" },
"000000000000000000000000000000000000009a": { "balance": "0" },
"000000000000000000000000000000000000009b": { "balance": "0" },
"000000000000000000000000000000000000009c": { "balance": "0" },
"000000000000000000000000000000000000009d": { "balance": "0" },
"000000000000000000000000000000000000009e": { "balance": "0" },
"000000000000000000000000000000000000009f": { "balance": "0" },
"00000000000000000000000000000000000000a0": { "balance": "0" },
"00000000000000000000000000000000000000a1": { "balance": "0" },
"00000000000000000000000000000000000000a2": { "balance": "0" },
"00000000000000000000000000000000000000a3": { "balance": "0" },
"00000000000000000000000000000000000000a4": { "balance": "0" },
"00000000000000000000000000000000000000a5": { "balance": "0" },
"00000000000000000000000000000000000000a6": { "balance": "0" },
"00000000000000000000000000000000000000a7": { "balance": "0" },
"00000000000000000000000000000000000000a8": { "balance": "0" },
"00000000000000000000000000000000000000a9": { "balance": "0" },
"00000000000000000000000000000000000000aa": { "balance": "0" },
"00000000000000000000000000000000000000ab": { "balance": "0" },
"00000000000000000000000000000000000000ac": { "balance": "0" },
"00000000000000000000000000000000000000ad": { "balance": "0" },
"00000000000000000000000000000000000000ae": { "balance": "0" },
"00000000000000000000000000000000000000af": { "balance": "0" },
"00000000000000000000000000000000000000b0": { "balance": "0" },
"00000000000000000000000000000000000000b1": { "balance": "0" },
"00000000000000000000000000000000000000b2": { "balance": "0" },
"00000000000000000000000000000000000000b3": { "balance": "0" },
"00000000000000000000000000000000000000b4": { "balance": "0" },
"00000000000000000000000000000000000000b5": { "balance": "0" },
"00000000000000000000000000000000000000b6": { "balance": "0" },
"00000000000000000000000000000000000000b7": { "balance": "0" },
"00000000000000000000000000000000000000b8": { "balance": "0" },
"00000000000000000000000000000000000000b9": { "balance": "0" },
"00000000000000000000000000000000000000ba": { "balance": "0" },
"00000000000000000000000000000000000000bb": { "balance": "0" },
"00000000000000000000000000000000000000bc": { "balance": "0" },
"00000000000000000000000000000000000000bd": { "balance": "0" },
"00000000000000000000000000000000000000be": { "balance": "0" },
"00000000000000000000000000000000000000bf": { "balance": "0" },
"00000000000000000000000000000000000000c0": { "balance": "0" },
"00000000000000000000000000000000000000c1": { "balance": "0" },
"00000000000000000000000000000000000000c2": { "balance": "0" },
"00000000000000000000000000000000000000c3": { "balance": "0" },
"00000000000000000000000000000000000000c4": { "balance": "0" },
"00000000000000000000000000000000000000c5": { "balance": "0" },
"00000000000000000000000000000000000000c6": { "balance": "0" },
"00000000000000000000000000000000000000c7": { "balance": "0" },
"00000000000000000000000000000000000000c8": { "balance": "0" },
"00000000000000000000000000000000000000c9": { "balance": "0" },
"00000000000000000000000000000000000000ca": { "balance": "0" },
"00000000000000000000000000000000000000cb": { "balance": "0" },
"00000000000000000000000000000000000000cc": { "balance": "0" },
"00000000000000000000000000000000000000cd": { "balance": "0" },
"00000000000000000000000000000000000000ce": { "balance": "0" },
"00000000000000000000000000000000000000cf": { "balance": "0" },
"00000000000000000000000000000000000000d0": { "balance": "0" },
"00000000000000000000000000000000000000d1": { "balance": "0" },
"00000000000000000000000000000000000000d2": { "balance": "0" },
"00000000000000000000000000000000000000d3": { "balance": "0" },
"00000000000000000000000000000000000000d4": { "balance": "0" },
"00000000000000000000000000000000000000d5": { "balance": "0" },
"00000000000000000000000000000000000000d6": { "balance": "0" },
"00000000000000000000000000000000000000d7": { "balance": "0" },
"00000000000000000000000000000000000000d8": { "balance": "0" },
"00000000000000000000000000000000000000d9": { "balance": "0" },
"00000000000000000000000000000000000000da": { "balance": "0" },
"00000000000000000000000000000000000000db": { "balance": "0" },
"00000000000000000000000000000000000000dc": { "balance": "0" },
"00000000000000000000000000000000000000dd": { "balance": "0" },
"00000000000000000000000000000000000000de": { "balance": "0" },
"00000000000000000000000000000000000000df": { "balance": "0" },
"00000000000000000000000000000000000000e0": { "balance": "0" },
"00000000000000000000000000000000000000e1": { "balance": "0" },
"00000000000000000000000000000000000000e2": { "balance": "0" },
"00000000000000000000000000000000000000e3": { "balance": "0" },
"00000000000000000000000000000000000000e4": { "balance": "0" },
"00000000000000000000000000000000000000e5": { "balance": "0" },
"00000000000000000000000000000000000000e6": { "balance": "0" },
"00000000000000000000000000000000000000e7": { "balance": "0" },
"00000000000000000000000000000000000000e8": { "balance": "0" },
"00000000000000000000000000000000000000e9": { "balance": "0" },
"00000000000000000000000000000000000000ea": { "balance": "0" },
"00000000000000000000000000000000000000eb": { "balance": "0" },
"00000000000000000000000000000000000000ec": { "balance": "0" },
"00000000000000000000000000000000000000ed": { "balance": "0" },
"00000000000000000000000000000000000000ee": { "balance": "0" },
"00000000000000000000000000000000000000ef": { "balance": "0" },
"00000000000000000000000000000000000000f0": { "balance": "0" },
"00000000000000000000000000000000000000f1": { "balance": "0" },
"00000000000000000000000000000000000000f2": { "balance": "0" },
"00000000000000000000000000000000000000f3": { "balance": "0" },
"00000000000000000000000000000000000000f4": { "balance": "0" },
"00000000000000000000000000000000000000f5": { "balance": "0" },
"00000000000000000000000000000000000000f6": { "balance": "0" },
"00000000000000000000000000000000000000f7": { "balance": "0" },
"00000000000000000000000000000000000000f8": { "balance": "0" },
"00000000000000000000000000000000000000f9": { "balance": "0" },
"00000000000000000000000000000000000000fa": { "balance": "0" },
"00000000000000000000000000000000000000fb": { "balance": "0" },
"00000000000000000000000000000000000000fc": { "balance": "0" },
"00000000000000000000000000000000000000fd": { "balance": "0" },
"00000000000000000000000000000000000000fe": { "balance": "0" },
"00000000000000000000000000000000000000ff": { "balance": "0" },
"874b54a8bd152966d63f706bae1ffeb0411921e5": { "balance": "1000000000000000000000000000000" }
}
}

View File

@@ -1,5 +1,5 @@
{
"name": "DAO hard-fork consensus test",
"name": "EIP150.1b hard-fork consensus test",
"engine": {
"Ethash": {
"params": {
@@ -9,7 +9,7 @@
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0x5",
"homesteadTransition": "0x5",
"daoHardforkTransition": "0x8",
"daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754",
"daoHardforkAccounts": [
@@ -129,7 +129,12 @@
"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97",
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
]
],
"eip150Transition": "0xa",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
}
}
},

View File

@@ -16,7 +16,6 @@
//! Single account in the system.
use std::collections::hash_map::Entry;
use util::*;
use pod_account::*;
use account_db::*;
@@ -24,9 +23,11 @@ use lru_cache::LruCache;
use std::cell::{RefCell, Cell};
const STORAGE_CACHE_ITEMS: usize = 4096;
const STORAGE_CACHE_ITEMS: usize = 8192;
/// Single account in the system.
/// Keeps track of changes to the code and storage.
/// The changes are applied in `commit_storage` and `commit_code`
pub struct Account {
// Balance of the account.
balance: U256,
@@ -46,8 +47,6 @@ pub struct Account {
code_size: Option<u64>,
// Code cache of the account.
code_cache: Arc<Bytes>,
// Account is new or has been modified.
filth: Filth,
// Account code new or has been modified.
code_filth: Filth,
// Cached address hash.
@@ -67,7 +66,6 @@ impl Account {
code_hash: code.sha3(),
code_size: Some(code.len() as u64),
code_cache: Arc::new(code),
filth: Filth::Dirty,
code_filth: Filth::Dirty,
address_hash: Cell::new(None),
}
@@ -89,7 +87,6 @@ impl Account {
code_filth: Filth::Dirty,
code_size: Some(pod.code.as_ref().map_or(0, |c| c.len() as u64)),
code_cache: Arc::new(pod.code.map_or_else(|| { warn!("POD account with unknown code is being created! Assuming no code."); vec![] }, |c| c)),
filth: Filth::Dirty,
address_hash: Cell::new(None),
}
}
@@ -105,7 +102,6 @@ impl Account {
code_hash: SHA3_EMPTY,
code_cache: Arc::new(vec![]),
code_size: Some(0),
filth: Filth::Dirty,
code_filth: Filth::Clean,
address_hash: Cell::new(None),
}
@@ -123,7 +119,6 @@ impl Account {
code_hash: r.val_at(3),
code_cache: Arc::new(vec![]),
code_size: None,
filth: Filth::Clean,
code_filth: Filth::Clean,
address_hash: Cell::new(None),
}
@@ -141,7 +136,6 @@ impl Account {
code_hash: SHA3_EMPTY,
code_cache: Arc::new(vec![]),
code_size: None,
filth: Filth::Dirty,
code_filth: Filth::Clean,
address_hash: Cell::new(None),
}
@@ -153,7 +147,6 @@ impl Account {
self.code_hash = code.sha3();
self.code_cache = Arc::new(code);
self.code_size = Some(self.code_cache.len() as u64);
self.filth = Filth::Dirty;
self.code_filth = Filth::Dirty;
}
@@ -164,17 +157,7 @@ impl Account {
/// Set (and cache) the contents of the trie's storage at `key` to `value`.
pub fn set_storage(&mut self, key: H256, value: H256) {
match self.storage_changes.entry(key) {
Entry::Occupied(ref mut entry) if entry.get() != &value => {
entry.insert(value);
self.filth = Filth::Dirty;
},
Entry::Vacant(entry) => {
entry.insert(value);
self.filth = Filth::Dirty;
},
_ => {},
}
self.storage_changes.insert(key, value);
}
/// Get (and cache) the contents of the trie's storage at `key`.
@@ -263,17 +246,6 @@ impl Account {
!self.code_cache.is_empty() || (self.code_cache.is_empty() && self.code_hash == SHA3_EMPTY)
}
/// Is this a new or modified account?
pub fn is_dirty(&self) -> bool {
self.filth == Filth::Dirty || self.code_filth == Filth::Dirty || !self.storage_is_clean()
}
/// Mark account as clean.
pub fn set_clean(&mut self) {
assert!(self.storage_is_clean());
self.filth = Filth::Clean
}
/// Provide a database to get `code_hash`. Should not be called if it is a contract without code.
pub fn cache_code(&mut self, db: &AccountDB) -> bool {
// TODO: fill out self.code_cache;
@@ -316,6 +288,21 @@ impl Account {
/// Determine whether there are any un-`commit()`-ed storage-setting operations.
pub fn storage_is_clean(&self) -> bool { self.storage_changes.is_empty() }
/// Check if account has zero nonce, balance, no code and no storage.
///
/// NOTE: Will panic if `!self.storage_is_clean()`
pub fn is_empty(&self) -> bool {
assert!(self.storage_is_clean(), "Account::is_empty() may only legally be called when storage is clean.");
self.is_null() && self.storage_root == SHA3_NULL_RLP
}
/// Check if account has zero nonce, balance, no code.
pub fn is_null(&self) -> bool {
self.balance.is_zero() &&
self.nonce.is_zero() &&
self.code_hash == SHA3_EMPTY
}
#[cfg(test)]
/// return the storage root associated with this account or None if it has been altered via the overlay.
pub fn storage_root(&self) -> Option<&H256> { if self.storage_is_clean() {Some(&self.storage_root)} else {None} }
@@ -326,25 +313,18 @@ impl Account {
/// Increment the nonce of the account by one.
pub fn inc_nonce(&mut self) {
self.nonce = self.nonce + U256::from(1u8);
self.filth = Filth::Dirty;
}
/// Increment the nonce of the account by one.
/// Increase account balance.
pub fn add_balance(&mut self, x: &U256) {
if !x.is_zero() {
self.balance = self.balance + *x;
self.filth = Filth::Dirty;
}
self.balance = self.balance + *x;
}
/// Increment the nonce of the account by one.
/// Decrease account balance.
/// Panics if balance is less than `x`
pub fn sub_balance(&mut self, x: &U256) {
if !x.is_zero() {
assert!(self.balance >= *x);
self.balance = self.balance - *x;
self.filth = Filth::Dirty;
}
assert!(self.balance >= *x);
self.balance = self.balance - *x;
}
/// Commit the `storage_changes` to the backing DB and update `storage_root`.
@@ -406,7 +386,6 @@ impl Account {
code_hash: self.code_hash.clone(),
code_size: self.code_size.clone(),
code_cache: self.code_cache.clone(),
filth: self.filth,
code_filth: self.code_filth,
address_hash: self.address_hash.clone(),
}
@@ -427,10 +406,10 @@ impl Account {
account
}
/// Replace self with the data from other account merging storage cache
pub fn merge_with(&mut self, other: Account) {
assert!(self.storage_is_clean());
assert!(other.storage_is_clean());
/// Replace self with the data from other account merging storage cache.
/// Basic account data and all modifications are overwritten
/// with new values.
pub fn overwrite_with(&mut self, other: Account) {
self.balance = other.balance;
self.nonce = other.nonce;
self.storage_root = other.storage_root;
@@ -443,6 +422,7 @@ impl Account {
for (k, v) in other.storage_cache.into_inner().into_iter() {
cache.insert(k.clone() , v.clone()); //TODO: cloning should not be required here
}
self.storage_changes = other.storage_changes;
}
}

View File

@@ -395,6 +395,10 @@ impl<'x> OpenBlock<'x> {
uncle_bytes: uncle_bytes,
}
}
#[cfg(test)]
/// Return mutable block reference. To be used in tests only.
pub fn block_mut (&mut self) -> &mut ExecutedBlock { &mut self.block }
}
impl<'x> IsBlock for OpenBlock<'x> {

View File

@@ -17,7 +17,7 @@
//! A queue of blocks. Sits between network or other I/O and the `BlockChain`.
//! Sorts them ready for blockchain insertion.
use std::thread::{JoinHandle, self};
use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering as AtomicOrdering};
use std::sync::{Condvar as SCondvar, Mutex as SMutex};
use util::*;
use io::*;
@@ -76,6 +76,13 @@ impl BlockQueueInfo {
}
}
// the internal queue sizes.
struct Sizes {
unverified: AtomicUsize,
verifying: AtomicUsize,
verified: AtomicUsize,
}
/// A queue of blocks. Sits between network or other I/O and the `BlockChain`.
/// Sorts them ready for blockchain insertion.
pub struct BlockQueue {
@@ -110,7 +117,21 @@ struct QueueSignal {
impl QueueSignal {
#[cfg_attr(feature="dev", allow(bool_comparison))]
fn set(&self) {
fn set_sync(&self) {
// Do not signal when we are about to close
if self.deleting.load(AtomicOrdering::Relaxed) {
return;
}
if self.signalled.compare_and_swap(false, true, AtomicOrdering::Relaxed) == false {
if let Err(e) = self.message_channel.send_sync(ClientIoMessage::BlockVerified) {
debug!("Error sending BlockVerified message: {:?}", e);
}
}
}
#[cfg_attr(feature="dev", allow(bool_comparison))]
fn set_async(&self) {
// Do not signal when we are about to close
if self.deleting.load(AtomicOrdering::Relaxed) {
return;
@@ -131,11 +152,12 @@ impl QueueSignal {
struct Verification {
// All locks must be captured in the order declared here.
unverified: Mutex<VecDeque<UnverifiedBlock>>,
verified: Mutex<VecDeque<PreverifiedBlock>>,
verifying: Mutex<VecDeque<VerifyingBlock>>,
verified: Mutex<VecDeque<PreverifiedBlock>>,
bad: Mutex<HashSet<H256>>,
more_to_verify: SMutex<()>,
empty: SMutex<()>,
sizes: Sizes,
}
impl BlockQueue {
@@ -143,12 +165,16 @@ impl BlockQueue {
pub fn new(config: BlockQueueConfig, engine: Arc<Engine>, message_channel: IoChannel<ClientIoMessage>) -> BlockQueue {
let verification = Arc::new(Verification {
unverified: Mutex::new(VecDeque::new()),
verified: Mutex::new(VecDeque::new()),
verifying: Mutex::new(VecDeque::new()),
verified: Mutex::new(VecDeque::new()),
bad: Mutex::new(HashSet::new()),
more_to_verify: SMutex::new(()),
empty: SMutex::new(()),
sizes: Sizes {
unverified: AtomicUsize::new(0),
verifying: AtomicUsize::new(0),
verified: AtomicUsize::new(0),
}
});
let more_to_verify = Arc::new(SCondvar::new());
let deleting = Arc::new(AtomicBool::new(false));
@@ -221,16 +247,18 @@ impl BlockQueue {
}
let mut verifying = verification.verifying.lock();
let block = unverified.pop_front().unwrap();
verification.sizes.unverified.fetch_sub(block.heap_size_of_children(), AtomicOrdering::SeqCst);
verifying.push_back(VerifyingBlock{ hash: block.header.hash(), block: None });
block
};
let block_hash = block.header.hash();
match verify_block_unordered(block.header, block.bytes, &*engine) {
let is_ready = match verify_block_unordered(block.header, block.bytes, &*engine) {
Ok(verified) => {
let mut verifying = verification.verifying.lock();
for e in verifying.iter_mut() {
if e.hash == block_hash {
verification.sizes.verifying.fetch_add(verified.heap_size_of_children(), AtomicOrdering::SeqCst);
e.block = Some(verified);
break;
}
@@ -239,8 +267,10 @@ impl BlockQueue {
// we're next!
let mut verified = verification.verified.lock();
let mut bad = verification.bad.lock();
BlockQueue::drain_verifying(&mut verifying, &mut verified, &mut bad);
ready.set();
BlockQueue::drain_verifying(&mut verifying, &mut verified, &mut bad, &verification.sizes);
true
} else {
false
}
},
Err(err) => {
@@ -250,23 +280,39 @@ impl BlockQueue {
warn!(target: "client", "Stage 2 block verification failed for {}\nError: {:?}", block_hash, err);
bad.insert(block_hash.clone());
verifying.retain(|e| e.hash != block_hash);
BlockQueue::drain_verifying(&mut verifying, &mut verified, &mut bad);
ready.set();
if !verifying.is_empty() && verifying.front().unwrap().hash == block_hash {
BlockQueue::drain_verifying(&mut verifying, &mut verified, &mut bad, &verification.sizes);
true
} else {
false
}
}
};
if is_ready {
// Import the block immediately
ready.set_sync();
}
}
}
fn drain_verifying(verifying: &mut VecDeque<VerifyingBlock>, verified: &mut VecDeque<PreverifiedBlock>, bad: &mut HashSet<H256>) {
fn drain_verifying(verifying: &mut VecDeque<VerifyingBlock>, verified: &mut VecDeque<PreverifiedBlock>, bad: &mut HashSet<H256>, sizes: &Sizes) {
let mut removed_size = 0;
let mut inserted_size = 0;
while !verifying.is_empty() && verifying.front().unwrap().block.is_some() {
let block = verifying.pop_front().unwrap().block.unwrap();
if bad.contains(&block.header.parent_hash) {
let size = block.heap_size_of_children();
removed_size += size;
if bad.contains(&block.header.parent_hash()) {
bad.insert(block.header.hash());
}
else {
} else {
inserted_size += size;
verified.push_back(block);
}
}
sizes.verifying.fetch_sub(removed_size, AtomicOrdering::SeqCst);
sizes.verified.fetch_add(inserted_size, AtomicOrdering::SeqCst);
}
/// Clear the queue and stop verification activity.
@@ -277,6 +323,12 @@ impl BlockQueue {
unverified.clear();
verifying.clear();
verified.clear();
let sizes = &self.verification.sizes;
sizes.unverified.store(0, AtomicOrdering::Release);
sizes.verifying.store(0, AtomicOrdering::Release);
sizes.verified.store(0, AtomicOrdering::Release);
self.processing.write().clear();
}
@@ -322,7 +374,9 @@ impl BlockQueue {
match verify_block_basic(&header, &bytes, &*self.engine) {
Ok(()) => {
self.processing.write().insert(h.clone());
self.verification.unverified.lock().push_back(UnverifiedBlock { header: header, bytes: bytes });
let block = UnverifiedBlock { header: header, bytes: bytes };
self.verification.sizes.unverified.fetch_add(block.heap_size_of_children(), AtomicOrdering::SeqCst);
self.verification.unverified.lock().push_back(block);
self.more_to_verify.notify_all();
Ok(h)
},
@@ -350,26 +404,32 @@ impl BlockQueue {
}
let mut new_verified = VecDeque::new();
let mut removed_size = 0;
for block in verified.drain(..) {
if bad.contains(&block.header.parent_hash) {
removed_size += block.heap_size_of_children();
bad.insert(block.header.hash());
processing.remove(&block.header.hash());
} else {
new_verified.push_back(block);
}
}
self.verification.sizes.verified.fetch_sub(removed_size, AtomicOrdering::SeqCst);
*verified = new_verified;
}
/// Mark given block as processed
pub fn mark_as_good(&self, block_hashes: &[H256]) {
if block_hashes.is_empty() {
return;
/// Mark given item as processed.
/// Returns true if the queue becomes empty.
pub fn mark_as_good(&self, hashes: &[H256]) -> bool {
if hashes.is_empty() {
return self.processing.read().is_empty();
}
let mut processing = self.processing.write();
for hash in block_hashes {
for hash in hashes {
processing.remove(hash);
}
processing.is_empty()
}
/// Removes up to `max` verified blocks from the queue
@@ -379,28 +439,34 @@ impl BlockQueue {
let mut result = Vec::with_capacity(count);
for _ in 0..count {
let block = verified.pop_front().unwrap();
self.verification.sizes.verified.fetch_sub(block.heap_size_of_children(), AtomicOrdering::SeqCst);
result.push(block);
}
self.ready_signal.reset();
if !verified.is_empty() {
self.ready_signal.set();
self.ready_signal.set_async();
}
result
}
/// Get queue status.
pub fn queue_info(&self) -> BlockQueueInfo {
use std::mem::size_of;
let (unverified_len, unverified_bytes) = {
let v = self.verification.unverified.lock();
(v.len(), v.heap_size_of_children())
let len = self.verification.unverified.lock().len();
let size = self.verification.sizes.unverified.load(AtomicOrdering::Acquire);
(len, size + len * size_of::<UnverifiedBlock>())
};
let (verifying_len, verifying_bytes) = {
let v = self.verification.verifying.lock();
(v.len(), v.heap_size_of_children())
let len = self.verification.verifying.lock().len();
let size = self.verification.sizes.verifying.load(AtomicOrdering::Acquire);
(len, size + len * size_of::<VerifyingBlock>())
};
let (verified_len, verified_bytes) = {
let v = self.verification.verified.lock();
(v.len(), v.heap_size_of_children())
let len = self.verification.verified.lock().len();
let size = self.verification.sizes.verified.load(AtomicOrdering::Acquire);
(len, size + len * size_of::<PreverifiedBlock>())
};
BlockQueueInfo {
unverified_queue_size: unverified_len,
@@ -408,12 +474,9 @@ impl BlockQueue {
verified_queue_size: verified_len,
max_queue_size: self.max_queue_size,
max_mem_use: self.max_mem_use,
mem_used:
unverified_bytes
+ verifying_bytes
+ verified_bytes
// TODO: https://github.com/servo/heapsize/pull/50
//+ self.processing.read().heap_size_of_children(),
mem_used: unverified_bytes
+ verifying_bytes
+ verified_bytes
}
}

View File

@@ -1279,7 +1279,7 @@ mod tests {
action: Action::Create,
value: 100.into(),
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
}.sign(&"".sha3());
}.sign(&"".sha3(), None);
let b1a = canon_chain
@@ -1343,7 +1343,7 @@ mod tests {
action: Action::Create,
value: 100.into(),
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
}.sign(&"".sha3());
}.sign(&"".sha3(), None);
let t2 = Transaction {
nonce: 1.into(),
@@ -1352,7 +1352,7 @@ mod tests {
action: Action::Create,
value: 100.into(),
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
}.sign(&"".sha3());
}.sign(&"".sha3(), None);
let t3 = Transaction {
nonce: 2.into(),
@@ -1361,7 +1361,7 @@ mod tests {
action: Action::Create,
value: 100.into(),
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
}.sign(&"".sha3());
}.sign(&"".sha3(), None);
let b1a = canon_chain
.with_transaction(t1.clone())

View File

@@ -15,12 +15,10 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use util::numbers::*;
use ipc::{IpcConfig, BinaryConvertError};
use std::collections::VecDeque;
use std::mem;
use ipc::{IpcConfig};
/// Represents what has to be handled by actor listening to chain events
#[derive(Ipc)]
#[ipc]
pub trait ChainNotify : Send + Sync {
/// fires when chain has new blocks
fn new_blocks(&self,

View File

@@ -17,6 +17,7 @@ use std::collections::{HashSet, HashMap, BTreeMap, VecDeque};
use std::sync::{Arc, Weak};
use std::path::{Path};
use std::fmt;
use std::cmp;
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering};
use std::time::{Instant};
use time::precise_time_ns;
@@ -33,7 +34,7 @@ use io::*;
use views::{BlockView, HeaderView, BodyView};
use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult};
use header::BlockNumber;
use state::State;
use state::{State, CleanupMode};
use spec::Spec;
use basic_types::Seal;
use engines::Engine;
@@ -73,6 +74,7 @@ pub use blockchain::CacheSize as BlockChainCacheSize;
const MAX_TX_QUEUE_SIZE: usize = 4096;
const MAX_QUEUE_SIZE_TO_SLEEP_ON: usize = 2;
const MIN_HISTORY_SIZE: u64 = 8;
impl fmt::Display for BlockChainInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -139,10 +141,9 @@ pub struct Client {
notify: RwLock<Vec<Weak<ChainNotify>>>,
queue_transactions: AtomicUsize,
last_hashes: RwLock<VecDeque<H256>>,
history: u64,
}
const HISTORY: u64 = 1200;
// database columns
/// Column for State
pub const DB_COL_STATE: Option<u32> = Some(0);
@@ -159,13 +160,6 @@ pub const DB_COL_ACCOUNT_BLOOM: Option<u32> = Some(5);
/// Number of columns in DB
pub const DB_NO_OF_COLUMNS: Option<u32> = Some(6);
/// Append a path element to the given path and return the string.
pub fn append_path<P>(path: P, item: &str) -> String where P: AsRef<Path> {
let mut p = path.as_ref().to_path_buf();
p.push(item);
p.to_str().unwrap().to_owned()
}
impl Client {
/// Create a new client with given spec and DB path and custom verifier.
pub fn new(
@@ -182,7 +176,7 @@ impl Client {
db_config.compaction = config.db_compaction.compaction_profile();
db_config.wal = config.db_wal;
let db = Arc::new(try!(Database::open(&db_config, &path.to_str().unwrap()).map_err(ClientError::Database)));
let db = Arc::new(try!(Database::open(&db_config, &path.to_str().expect("DB path could not be converted to string.")).map_err(ClientError::Database)));
let chain = Arc::new(BlockChain::new(config.blockchain, &gb, db.clone()));
let tracedb = Arc::new(try!(TraceDB::new(config.tracing, db.clone(), chain.clone())));
@@ -194,6 +188,19 @@ impl Client {
try!(db.write(batch).map_err(ClientError::Database));
}
trace!("Cleanup journal: DB Earliest = {:?}, Latest = {:?}", state_db.journal_db().earliest_era(), state_db.journal_db().latest_era());
let history = cmp::max(MIN_HISTORY_SIZE, config.history);
if let (Some(earliest), Some(latest)) = (state_db.journal_db().earliest_era(), state_db.journal_db().latest_era()) {
if latest > earliest && latest - earliest > history {
for era in earliest..(latest - history + 1) {
trace!("Removing era {}", era);
let batch = DBTransaction::new(&db);
try!(state_db.journal_db_mut().commit_old(&batch, era, &chain.block_hash(era).expect("Old block not found in the database")));
try!(db.write(batch).map_err(ClientError::Database));
}
}
}
if !chain.block_header(&chain.best_block_hash()).map_or(true, |h| state_db.journal_db().contains(h.state_root())) {
warn!("State root not found for block #{} ({})", chain.best_block_number(), chain.best_block_hash().hex());
}
@@ -226,6 +233,7 @@ impl Client {
notify: RwLock::new(Vec::new()),
queue_transactions: AtomicUsize::new(0),
last_hashes: RwLock::new(VecDeque::new()),
history: history,
};
Ok(Arc::new(client))
}
@@ -251,6 +259,22 @@ impl Client {
}
}
/// The env info as of the best block.
fn latest_env_info(&self) -> EnvInfo {
let header_data = self.best_block_header();
let view = HeaderView::new(&header_data);
EnvInfo {
number: view.number(),
author: view.author(),
timestamp: view.timestamp(),
difficulty: view.difficulty(),
last_hashes: self.build_last_hashes(view.hash()),
gas_used: U256::default(),
gas_limit: view.gas_limit(),
}
}
fn build_last_hashes(&self, parent_hash: H256) -> Arc<LastHashes> {
{
let hashes = self.last_hashes.read();
@@ -282,7 +306,7 @@ impl Client {
// Check the block isn't so old we won't be able to enact it.
let best_block_number = self.chain.best_block_number();
if best_block_number >= HISTORY && header.number() <= best_block_number - HISTORY {
if best_block_number >= self.history && header.number() <= best_block_number - self.history {
warn!(target: "client", "Block import failed for #{} ({})\nBlock is ancient (current best block: #{}).", header.number(), header.hash(), best_block_number);
return Err(());
}
@@ -295,32 +319,28 @@ impl Client {
};
// Check if Parent is in chain
let chain_has_parent = self.chain.block_header(&header.parent_hash);
if let None = chain_has_parent {
warn!(target: "client", "Block import failed for #{} ({}): Parent not found ({}) ", header.number(), header.hash(), header.parent_hash);
return Err(());
};
let chain_has_parent = self.chain.block_header(header.parent_hash());
if let Some(parent) = chain_has_parent {
// Enact Verified Block
let last_hashes = self.build_last_hashes(header.parent_hash().clone());
let db = self.state_db.lock().boxed_clone_canon(&header.parent_hash());
// Enact Verified Block
let parent = chain_has_parent.unwrap();
let last_hashes = self.build_last_hashes(header.parent_hash.clone());
let is_canon = header.parent_hash == self.chain.best_block_hash();
let db = if is_canon { self.state_db.lock().boxed_clone_canon() } else { self.state_db.lock().boxed_clone() };
let enact_result = enact_verified(block, engine, self.tracedb.tracing_enabled(), db, &parent, last_hashes, &self.vm_factory, self.trie_factory.clone());
let locked_block = try!(enact_result.map_err(|e| {
warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
}));
let enact_result = enact_verified(block, engine, self.tracedb.tracing_enabled(), db, &parent, last_hashes, &self.vm_factory, self.trie_factory.clone());
if let Err(e) = enact_result {
warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
return Err(());
};
// Final Verification
if let Err(e) = self.verifier.verify_block_final(header, locked_block.block().header()) {
warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
return Err(());
}
// Final Verification
let locked_block = enact_result.unwrap();
if let Err(e) = self.verifier.verify_block_final(header, locked_block.block().header()) {
warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
return Err(());
Ok(locked_block)
} else {
warn!(target: "client", "Block import failed for #{} ({}): Parent not found ({}) ", header.number(), header.hash(), header.parent_hash());
Err(())
}
Ok(locked_block)
}
fn calculate_enacted_retracted(&self, import_results: &[ImportRoute]) -> (Vec<H256>, Vec<H256>) {
@@ -351,16 +371,19 @@ impl Client {
/// This is triggered by a message coming from a block queue when the block is ready for insertion
pub fn import_verified_blocks(&self) -> usize {
let max_blocks_to_import = 64;
let (imported_blocks, import_results, invalid_blocks, imported, duration) = {
let max_blocks_to_import = 4;
let (imported_blocks, import_results, invalid_blocks, imported, duration, is_empty) = {
let mut imported_blocks = Vec::with_capacity(max_blocks_to_import);
let mut invalid_blocks = HashSet::new();
let mut import_results = Vec::with_capacity(max_blocks_to_import);
let _import_lock = self.import_lock.lock();
let blocks = self.block_queue.drain(max_blocks_to_import);
if blocks.is_empty() {
return 0;
}
let _timer = PerfTimer::new("import_verified_blocks");
let start = precise_time_ns();
let blocks = self.block_queue.drain(max_blocks_to_import);
for block in blocks {
let header = &block.header;
@@ -373,36 +396,35 @@ impl Client {
invalid_blocks.insert(header.hash());
continue;
}
let is_invalid = invalid_blocks.contains(header.parent_hash());
if let (false, Ok(closed_block)) = (is_invalid, self.check_and_close_block(&block)) {
imported_blocks.push(header.hash());
let closed_block = closed_block.unwrap();
imported_blocks.push(header.hash());
let route = self.commit_block(closed_block, &header.hash(), &block.bytes);
import_results.push(route);
let route = self.commit_block(closed_block, &header.hash(), &block.bytes);
import_results.push(route);
self.report.write().accrue_block(&block);
self.report.write().accrue_block(&block);
} else {
invalid_blocks.insert(header.hash());
}
}
let imported = imported_blocks.len();
let invalid_blocks = invalid_blocks.into_iter().collect::<Vec<H256>>();
{
if !invalid_blocks.is_empty() {
self.block_queue.mark_as_bad(&invalid_blocks);
}
if !imported_blocks.is_empty() {
self.block_queue.mark_as_good(&imported_blocks);
}
if !invalid_blocks.is_empty() {
self.block_queue.mark_as_bad(&invalid_blocks);
}
let is_empty = self.block_queue.mark_as_good(&imported_blocks);
let duration_ns = precise_time_ns() - start;
(imported_blocks, import_results, invalid_blocks, imported, duration_ns)
(imported_blocks, import_results, invalid_blocks, imported, duration_ns, is_empty)
};
{
if !imported_blocks.is_empty() && self.block_queue.queue_info().is_empty() {
if !imported_blocks.is_empty() && is_empty {
let (enacted, retracted) = self.calculate_enacted_retracted(&import_results);
if self.queue_info().is_empty() {
if is_empty {
self.miner.chain_new_blocks(self, &imported_blocks, &invalid_blocks, &enacted, &retracted);
}
@@ -427,9 +449,9 @@ impl Client {
let number = block.header().number();
let parent = block.header().parent_hash().clone();
// Are we committing an era?
let ancient = if number >= HISTORY {
let n = number - HISTORY;
Some((n, self.chain.block_hash(n).unwrap()))
let ancient = if number >= self.history {
let n = number - self.history;
Some((n, self.chain.block_hash(n).expect("only verified blocks can be commited; verified block has hash; qed")))
} else {
None
};
@@ -442,7 +464,6 @@ impl Client {
.collect();
//let traces = From::from(block.traces().clone().unwrap_or_else(Vec::new));
let batch = DBTransaction::new(&self.db);
// CHECK! I *think* this is fine, even if the state_root is equal to another
// already-imported block of the same number.
@@ -458,6 +479,8 @@ impl Client {
enacted: route.enacted.clone(),
retracted: route.retracted.len()
});
let is_canon = route.enacted.last().map_or(false, |h| h == hash);
state.sync_cache(&route.enacted, &route.retracted, is_canon);
// Final commit to the DB
self.db.write_buffered(batch).expect("DB write failed.");
self.chain.commit();
@@ -505,7 +528,7 @@ impl Client {
let db = self.state_db.lock().boxed_clone();
// early exit for pruned blocks
if db.is_pruned() && self.chain.best_block_number() >= block_number + HISTORY {
if db.is_pruned() && self.chain.best_block_number() >= block_number + self.history {
return None;
}
@@ -532,9 +555,11 @@ impl Client {
/// Get a copy of the best block's state.
pub fn state(&self) -> State {
let header = self.best_block_header();
let header = HeaderView::new(&header);
State::from_existing(
self.state_db.lock().boxed_clone(),
HeaderView::new(&self.best_block_header()).state_root(),
self.state_db.lock().boxed_clone_canon(&header.hash()),
header.state_root(),
self.engine.account_start_nonce(),
self.trie_factory.clone())
.expect("State root of best block header always valid.")
@@ -608,7 +633,7 @@ impl Client {
let best_block_number = self.chain_info().best_block_number;
let block_number = try!(self.block_number(at).ok_or(snapshot::Error::InvalidStartingBlock(at)));
if best_block_number > HISTORY + block_number && db.is_pruned() {
if best_block_number > self.history + block_number && db.is_pruned() {
return Err(snapshot::Error::OldBlockPrunedDB.into());
}
@@ -620,8 +645,10 @@ impl Client {
0
};
self.block_hash(BlockID::Number(start_num))
.expect("blocks within HISTORY are always stored.")
match self.block_hash(BlockID::Number(start_num)) {
Some(h) => h,
None => return Err(snapshot::Error::InvalidStartingBlock(at).into()),
}
}
_ => match self.block_hash(at) {
Some(hash) => hash,
@@ -681,7 +708,7 @@ impl BlockChainClient for Client {
fn call(&self, t: &SignedTransaction, block: BlockID, analytics: CallAnalytics) -> Result<Executed, CallError> {
let header = try!(self.block_header(block).ok_or(CallError::StatePruned));
let view = HeaderView::new(&header);
let last_hashes = self.build_last_hashes(view.hash());
let last_hashes = self.build_last_hashes(view.parent_hash());
let env_info = EnvInfo {
number: view.number(),
author: view.author(),
@@ -703,7 +730,7 @@ impl BlockChainClient for Client {
let needed_balance = t.value + t.gas * t.gas_price;
if balance < needed_balance {
// give the sender a sufficient balance
state.add_balance(&sender, &(needed_balance - balance));
state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty);
}
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
let mut ret = try!(Executive::new(&mut state, &env_info, &*self.engine, &self.vm_factory).transact(t, options));
@@ -833,8 +860,9 @@ impl BlockChainClient for Client {
let t = self.chain.block_body(&address.block_hash)
.and_then(|block| BodyView::new(&block).localized_transaction_at(&address.block_hash, block_number, address.index));
match (t, self.chain.transaction_receipt(&address)) {
(Some(tx), Some(receipt)) => {
let tx_and_sender = t.and_then(|tx| tx.sender().ok().map(|sender| (tx, sender)));
match (tx_and_sender, self.chain.transaction_receipt(&address)) {
(Some((tx, sender)), Some(receipt)) => {
let block_hash = tx.block_hash.clone();
let block_number = tx.block_number.clone();
let transaction_hash = tx.hash();
@@ -856,7 +884,7 @@ impl BlockChainClient for Client {
gas_used: receipt.gas_used - prior_gas_used,
contract_address: match tx.action {
Action::Call(_) => None,
Action::Create => Some(contract_address(&tx.sender().unwrap(), &tx.nonce))
Action::Create => Some(contract_address(&sender, &tx.nonce))
},
logs: receipt.logs.into_iter().enumerate().map(|(i, log)| LocalizedLogEntry {
entry: log,
@@ -979,17 +1007,18 @@ impl BlockChainClient for Client {
let start = self.block_number(filter.range.start);
let end = self.block_number(filter.range.end);
if start.is_some() && end.is_some() {
let filter = trace::Filter {
range: start.unwrap() as usize..end.unwrap() as usize,
from_address: From::from(filter.from_address),
to_address: From::from(filter.to_address),
};
match (start, end) {
(Some(s), Some(e)) => {
let filter = trace::Filter {
range: s as usize..e as usize,
from_address: From::from(filter.from_address),
to_address: From::from(filter.to_address),
};
let traces = self.tracedb.filter(&filter);
Some(traces)
} else {
None
let traces = self.tracedb.filter(&filter);
Some(traces)
},
_ => None,
}
}
@@ -1036,7 +1065,11 @@ impl BlockChainClient for Client {
}
fn pending_transactions(&self) -> Vec<SignedTransaction> {
self.miner.pending_transactions()
self.miner.pending_transactions(self.chain.best_block_number())
}
fn signing_network_id(&self) -> Option<u8> {
self.engine.signing_network_id(&self.latest_env_info())
}
}
@@ -1050,7 +1083,7 @@ impl MiningBlockChainClient for Client {
&self.vm_factory,
self.trie_factory.clone(),
false, // TODO: this will need to be parameterised once we want to do immediate mining insertion.
self.state_db.lock().boxed_clone(),
self.state_db.lock().boxed_clone_canon(&h),
&self.chain.block_header(&h).expect("h is best block hash: so its header must exist: qed"),
self.build_last_hashes(h.clone()),
author,
@@ -1061,11 +1094,15 @@ impl MiningBlockChainClient for Client {
// Add uncles
self.chain
.find_uncle_headers(&h, engine.maximum_uncle_age())
.unwrap()
.unwrap_or_else(Vec::new)
.into_iter()
.take(engine.maximum_uncle_count())
.foreach(|h| {
open_block.push_uncle(h).unwrap();
open_block.push_uncle(h).expect("pushing maximum_uncle_count;
open_block was just created;
push_uncle is not ok only if more than maximum_uncle_count is pushed;
so all push_uncle are Ok;
qed");
});
open_block
@@ -1085,9 +1122,9 @@ impl MiningBlockChainClient for Client {
let block_data = block.rlp_bytes();
// Clear canonical state cache
self.state_db.lock().clear_cache();
let route = self.commit_block(block, &h, &block_data);
trace!(target: "client", "Imported sealed block #{} ({})", number, h);
self.state_db.lock().sync_cache(&route.enacted, &route.retracted, false);
let (enacted, retracted) = self.calculate_enacted_retracted(&[route]);
self.miner.chain_new_blocks(self, &[h.clone()], &[], &enacted, &retracted);

View File

@@ -107,6 +107,8 @@ pub struct ClientConfig {
pub mode: Mode,
/// Type of block verifier used by client.
pub verifier_type: VerifierType,
/// State pruning history size.
pub history: u64,
}
#[cfg(test)]

View File

@@ -30,13 +30,17 @@ pub use self::test_client::{TestBlockChainClient, EachBlockWith};
pub use types::trace_filter::Filter as TraceFilter;
pub use executive::{Executed, Executive, TransactOptions};
pub use env_info::{LastHashes, EnvInfo};
pub use self::chain_notify::{ChainNotify, ChainNotifyClient};
pub use self::chain_notify::ChainNotify;
#[cfg(feature="ipc")]
pub use self::chain_notify::ChainNotifyClient;
#[cfg(feature="ipc")]
pub use self::traits::RemoteClient;
pub use types::call_analytics::CallAnalytics;
pub use block_import_error::BlockImportError;
pub use transaction_import::TransactionImportResult;
pub use transaction_import::TransactionImportError;
pub use self::traits::{BlockChainClient, MiningBlockChainClient, RemoteClient};
pub use self::traits::{BlockChainClient, MiningBlockChainClient};
mod traits {
#![allow(dead_code, unused_assignments, unused_variables, missing_docs)] // codegen issues

View File

@@ -53,6 +53,8 @@ pub struct TestBlockChainClient {
pub genesis_hash: H256,
/// Last block hash.
pub last_hash: RwLock<H256>,
/// Extra data do set for each block
pub extra_data: Bytes,
/// Difficulty.
pub difficulty: RwLock<U256>,
/// Balances.
@@ -99,11 +101,17 @@ impl Default for TestBlockChainClient {
impl TestBlockChainClient {
/// Creates new test client.
pub fn new() -> Self {
Self::new_with_extra_data(Bytes::new())
}
/// Creates new test client with specified extra data for each block
pub fn new_with_extra_data(extra_data: Bytes) -> Self {
let spec = Spec::new_test();
let mut client = TestBlockChainClient {
blocks: RwLock::new(HashMap::new()),
numbers: RwLock::new(HashMap::new()),
genesis_hash: H256::new(),
extra_data: extra_data,
last_hash: RwLock::new(H256::new()),
difficulty: RwLock::new(From::from(0)),
balances: RwLock::new(HashMap::new()),
@@ -121,7 +129,7 @@ impl TestBlockChainClient {
client.genesis_hash = client.last_hash.read().clone();
client
}
/// Set the transaction receipt result
pub fn set_transaction_receipt(&self, id: TransactionID, receipt: LocalizedReceipt) {
self.receipts.write().insert(id, receipt);
@@ -166,6 +174,7 @@ impl TestBlockChainClient {
header.parent_hash = self.last_hash.read().clone();
header.number = n as BlockNumber;
header.gas_limit = U256::from(1_000_000);
header.extra_data = self.extra_data.clone();
let uncles = match with {
EachBlockWith::Uncle | EachBlockWith::UncleAndTransaction => {
let mut uncles = RlpStream::new_list(1);
@@ -193,7 +202,7 @@ impl TestBlockChainClient {
gas_price: U256::one(),
nonce: U256::zero()
};
let signed_tx = tx.sign(keypair.secret());
let signed_tx = tx.sign(keypair.secret(), None);
txs.append(&signed_tx);
txs.out()
},
@@ -558,6 +567,8 @@ impl BlockChainClient for TestBlockChainClient {
}
fn pending_transactions(&self) -> Vec<SignedTransaction> {
self.miner.pending_transactions()
self.miner.pending_transactions(self.chain_info().best_block_number)
}
fn signing_network_id(&self) -> Option<u8> { None }
}

View File

@@ -37,13 +37,10 @@ use executive::Executed;
use env_info::LastHashes;
use types::call_analytics::CallAnalytics;
use block_import_error::BlockImportError;
use std::mem;
use std::collections::VecDeque;
use ipc::{IpcConfig, BinaryConvertError};
use ipc::{IpcConfig};
use types::blockchain_info::BlockChainInfo;
use types::block_status::BlockStatus;
#[derive(Ipc)]
#[ipc(client_ident="RemoteClient")]
/// Blockchain database client. Owns and manages a blockchain and a block queue.
pub trait BlockChainClient : Sync + Send {
@@ -215,6 +212,9 @@ pub trait BlockChainClient : Sync + Send {
Err(())
}
}
/// Get the preferred network ID to sign on
fn signing_network_id(&self) -> Option<u8> { None }
}
/// Extended client interface used for mining

View File

@@ -55,7 +55,7 @@ impl Engine for InstantSeal {
}
fn schedule(&self, _env_info: &EnvInfo) -> Schedule {
Schedule::new_homestead()
Schedule::new_post_eip150(usize::max_value(), false, false, false)
}
fn generate_seal(&self, _block: &ExecutedBlock, _accounts: Option<&AccountProvider>) -> Option<Vec<Bytes>> {

View File

@@ -98,6 +98,9 @@ pub trait Engine : Sync + Send {
/// Verify a particular transaction is valid.
fn verify_transaction(&self, _t: &SignedTransaction, _header: &Header) -> Result<(), Error> { Ok(()) }
/// The network ID that transactions should be signed with.
fn signing_network_id(&self, _env_info: &EnvInfo) -> Option<u8> { None }
/// Verify the seal of a block. This is an auxilliary method that actually just calls other `verify_` methods
/// to get the job done. By default it must pass `verify_basic` and `verify_block_unordered`. If more or fewer
/// methods are needed for an Engine, this may be overridden.

View File

@@ -62,6 +62,8 @@ pub enum TransactionError {
},
/// Transaction's gas limit (aka gas) is invalid.
InvalidGasLimit(OutOfBounds<U256>),
/// Invalid network ID given.
InvalidNetworkId,
}
impl fmt::Display for TransactionError {
@@ -80,6 +82,7 @@ impl fmt::Display for TransactionError {
GasLimitExceeded { limit, got } =>
format!("Gas limit exceeded. Limit={}, Given={}", limit, got),
InvalidGasLimit(ref err) => format!("Invalid gas limit. {}", err),
InvalidNetworkId => "Transaction of this network ID is not allowed on this chain.".into(),
};
f.write_fmt(format_args!("Transaction error ({})", msg))

View File

@@ -17,6 +17,7 @@
use ethash::{quick_get_difficulty, EthashManager, H256 as EH256};
use common::*;
use block::*;
use state::CleanupMode;
use spec::CommonParams;
use engines::Engine;
use evm::Schedule;
@@ -38,13 +39,31 @@ pub struct EthashParams {
/// Namereg contract address.
pub registrar: Address,
/// Homestead transition block number.
pub frontier_compatibility_mode_limit: u64,
pub homestead_transition: u64,
/// DAO hard-fork transition block (X).
pub dao_hardfork_transition: u64,
/// DAO hard-fork refund contract address (C).
pub dao_hardfork_beneficiary: Address,
/// DAO hard-fork DAO accounts list (L)
pub dao_hardfork_accounts: Vec<Address>,
/// Transition block for a change of difficulty params (currently just bound_divisor).
pub difficulty_hardfork_transition: u64,
/// Difficulty param after the difficulty transition.
pub difficulty_hardfork_bound_divisor: U256,
/// Block on which there is no additional difficulty from the exponential bomb.
pub bomb_defuse_transition: u64,
/// Number of first block where EIP-150 rules begin.
pub eip150_transition: u64,
/// Number of first block where EIP-155 rules begin.
pub eip155_transition: u64,
/// Number of first block where EIP-160 rules begin.
pub eip160_transition: u64,
/// Number of first block where EIP-161.abc begin.
pub eip161abc_transition: u64,
/// Number of first block where EIP-161.d begins.
pub eip161d_transition: u64,
/// Maximum amount of code that can be deploying into a contract.
pub max_code_size: u64,
}
impl From<ethjson::spec::EthashParams> for EthashParams {
@@ -56,10 +75,19 @@ impl From<ethjson::spec::EthashParams> for EthashParams {
duration_limit: p.duration_limit.into(),
block_reward: p.block_reward.into(),
registrar: p.registrar.map_or_else(Address::new, Into::into),
frontier_compatibility_mode_limit: p.frontier_compatibility_mode_limit.map_or(0, Into::into),
dao_hardfork_transition: p.dao_hardfork_transition.map_or(0x7fffffffffffffff, Into::into),
homestead_transition: p.homestead_transition.map_or(0, Into::into),
dao_hardfork_transition: p.dao_hardfork_transition.map_or(u64::max_value(), Into::into),
dao_hardfork_beneficiary: p.dao_hardfork_beneficiary.map_or_else(Address::new, Into::into),
dao_hardfork_accounts: p.dao_hardfork_accounts.unwrap_or_else(Vec::new).into_iter().map(Into::into).collect(),
difficulty_hardfork_transition: p.difficulty_hardfork_transition.map_or(u64::max_value(), Into::into),
difficulty_hardfork_bound_divisor: p.difficulty_hardfork_bound_divisor.map_or(p.difficulty_bound_divisor.into(), Into::into),
bomb_defuse_transition: p.bomb_defuse_transition.map_or(u64::max_value(), Into::into),
eip150_transition: p.eip150_transition.map_or(0, Into::into),
eip155_transition: p.eip155_transition.map_or(0, Into::into),
eip160_transition: p.eip160_transition.map_or(0, Into::into),
eip161abc_transition: p.eip161abc_transition.map_or(0, Into::into),
eip161d_transition: p.eip161d_transition.map_or(u64::max_value(), Into::into),
max_code_size: p.max_code_size.map_or(u64::max_value(), Into::into),
}
}
}
@@ -104,12 +132,27 @@ impl Engine for Ethash {
}
fn schedule(&self, env_info: &EnvInfo) -> Schedule {
trace!(target: "client", "Creating schedule. fCML={}", self.ethash_params.frontier_compatibility_mode_limit);
trace!(target: "client", "Creating schedule. fCML={}, bGCML={}", self.ethash_params.homestead_transition, self.ethash_params.eip150_transition);
if env_info.number < self.ethash_params.frontier_compatibility_mode_limit {
if env_info.number < self.ethash_params.homestead_transition {
Schedule::new_frontier()
} else {
} else if env_info.number < self.ethash_params.eip150_transition {
Schedule::new_homestead()
} else {
Schedule::new_post_eip150(
self.ethash_params.max_code_size as usize,
env_info.number >= self.ethash_params.eip160_transition,
env_info.number >= self.ethash_params.eip161abc_transition,
env_info.number >= self.ethash_params.eip161d_transition
)
}
}
fn signing_network_id(&self, env_info: &EnvInfo) -> Option<u8> {
if env_info.number >= self.ethash_params.eip155_transition && self.params().network_id < 127 {
Some(self.params().network_id as u8)
} else {
None
}
}
@@ -144,7 +187,7 @@ impl Engine for Ethash {
let mut state = block.fields_mut().state;
for child in &self.ethash_params.dao_hardfork_accounts {
let b = state.balance(child);
state.transfer_balance(child, &self.ethash_params.dao_hardfork_beneficiary, &b);
state.transfer_balance(child, &self.ethash_params.dao_hardfork_beneficiary, &b, CleanupMode::NoEmpty);
}
// }
}
@@ -157,12 +200,12 @@ impl Engine for Ethash {
let fields = block.fields_mut();
// Bestow block reward
fields.state.add_balance(&fields.header.author, &(reward + reward / U256::from(32) * U256::from(fields.uncles.len())));
fields.state.add_balance(&fields.header.author, &(reward + reward / U256::from(32) * U256::from(fields.uncles.len())), CleanupMode::NoEmpty);
// Bestow uncle rewards
let current_number = fields.header.number();
for u in fields.uncles.iter() {
fields.state.add_balance(u.author(), &(reward * U256::from(8 + u.number() - current_number) / U256::from(8)));
fields.state.add_balance(u.author(), &(reward * U256::from(8 + u.number() - current_number) / U256::from(8)), CleanupMode::NoEmpty);
}
if let Err(e) = fields.state.commit() {
warn!("Encountered error on state commit: {}", e);
@@ -246,9 +289,16 @@ impl Engine for Ethash {
}
fn verify_transaction_basic(&self, t: &SignedTransaction, header: &Header) -> result::Result<(), Error> {
if header.number() >= self.ethash_params.frontier_compatibility_mode_limit {
if header.number() >= self.ethash_params.homestead_transition {
try!(t.check_low_s());
}
if let Some(n) = t.network_id() {
if header.number() < self.ethash_params.eip155_transition || n as usize != self.params().network_id {
return Err(TransactionError::InvalidNetworkId.into())
}
}
Ok(())
}
@@ -268,7 +318,7 @@ impl Ethash {
let min_difficulty = self.ethash_params.minimum_difficulty;
let difficulty_bound_divisor = self.ethash_params.difficulty_bound_divisor;
let duration_limit = self.ethash_params.duration_limit;
let frontier_limit = self.ethash_params.frontier_compatibility_mode_limit;
let frontier_limit = self.ethash_params.homestead_transition;
let mut target = if header.number < frontier_limit {
if header.timestamp >= parent.timestamp + duration_limit {

View File

@@ -44,12 +44,21 @@ pub fn new_frontier_test() -> Spec { Spec::load(include_bytes!("../../res/ethere
/// Create a new Homestead chain spec as though it never changed from Frontier.
pub fn new_homestead_test() -> Spec { Spec::load(include_bytes!("../../res/ethereum/homestead_test.json")) }
/// Create a new Homestead-EIP150 chain spec as though it never changed from Homestead/Frontier.
pub fn new_eip150_test() -> Spec { Spec::load(include_bytes!("../../res/ethereum/eip150_test.json")) }
/// Create a new Homestead-EIP150 chain spec as though it never changed from Homestead/Frontier.
pub fn new_eip161_test() -> Spec { Spec::load(include_bytes!("../../res/ethereum/eip161_test.json")) }
/// Create a new Frontier/Homestead/DAO chain spec with transition points at #5 and #8.
pub fn new_daohardfork_test() -> Spec { Spec::load(include_bytes!("../../res/ethereum/daohardfork_test.json")) }
pub fn new_transition_test() -> Spec { Spec::load(include_bytes!("../../res/ethereum/transition_test.json")) }
/// Create a new Frontier main net chain spec without genesis accounts.
pub fn new_mainnet_like() -> Spec { Spec::load(include_bytes!("../../res/ethereum/frontier_like_test.json")) }
/// Create a new Ropsten chain spec.
pub fn new_ropsten() -> Spec { Spec::load(include_bytes!("../../res/ethereum/ropsten.json")) }
/// Create a new Morden chain spec.
pub fn new_morden() -> Spec { Spec::load(include_bytes!("../../res/ethereum/morden.json")) }

View File

@@ -52,6 +52,12 @@ pub trait Ext {
/// Determine whether an account exists.
fn exists(&self, address: &Address) -> bool;
/// Determine whether an account exists and is not null (zero balance/nonce, no code).
fn exists_and_not_null(&self, address: &Address) -> bool;
/// Balance of the origin account.
fn origin_balance(&self) -> U256;
/// Returns address balance.
fn balance(&self, address: &Address) -> U256;

View File

@@ -19,6 +19,7 @@ use super::u256_to_address;
use evm::{self, CostType};
use evm::instructions::{self, Instruction, InstructionInfo};
use evm::interpreter::stack::Stack;
use evm::schedule::Schedule;
macro_rules! overflowing {
($x: expr) => {{
@@ -31,7 +32,7 @@ macro_rules! overflowing {
#[cfg_attr(feature="dev", allow(enum_variant_names))]
enum InstructionCost<Cost: CostType> {
Gas(Cost),
GasMem(Cost, Cost),
GasMem(Cost, Cost, Option<Cost>),
GasMemCopy(Cost, Cost, Cost)
}
@@ -56,7 +57,37 @@ impl<Gas: CostType> Gasometer<Gas> {
}
}
/// How much gas is provided to a CALL/CREATE, given that we need to deduct `needed` for this operation
/// and that we `requested` some.
pub fn gas_provided(&self, schedule: &Schedule, needed: Gas, requested: Option<evm::Result<Gas>>) -> evm::Result<Gas> {
match schedule.sub_gas_cap_divisor {
Some(cap_divisor) if self.current_gas >= needed => {
let gas_remaining = self.current_gas - needed;
let max_gas_provided = gas_remaining - gas_remaining / Gas::from(cap_divisor);
if let Some(Ok(r)) = requested {
Ok(min(r, max_gas_provided))
} else {
Ok(max_gas_provided)
}
},
_ => {
if let Some(r) = requested {
r
} else if self.current_gas >= needed {
Ok(self.current_gas - needed)
} else {
Ok(0.into())
}
}
}
}
#[cfg_attr(feature="dev", allow(cyclomatic_complexity))]
/// Determine how much gas is used by the given instruction, given the machine's state.
///
/// We guarantee that the final element of the returned tuple (`provided`) will be `Some`
/// iff the `instruction` is one of `CREATE`, or any of the `CALL` variants. In this case,
/// it will be the amount of gas that the current context provides to the child context.
pub fn get_gas_cost_mem(
&mut self,
ext: &evm::Ext,
@@ -64,7 +95,7 @@ impl<Gas: CostType> Gasometer<Gas> {
info: &InstructionInfo,
stack: &Stack<U256>,
current_mem_size: usize,
) -> evm::Result<(Gas, Gas, usize)> {
) -> evm::Result<(Gas, Gas, usize, Option<Gas>)> {
let schedule = ext.schedule();
let tier = instructions::get_tier_idx(info.tier);
let default_gas = Gas::from(schedule.tier_step_gas[tier]);
@@ -90,26 +121,47 @@ impl<Gas: CostType> Gasometer<Gas> {
instructions::SLOAD => {
InstructionCost::Gas(Gas::from(schedule.sload_gas))
},
instructions::BALANCE => {
InstructionCost::Gas(Gas::from(schedule.balance_gas))
},
instructions::EXTCODESIZE => {
InstructionCost::Gas(Gas::from(schedule.extcodesize_gas))
},
instructions::SUICIDE => {
let mut gas = Gas::from(schedule.suicide_gas);
let is_value_transfer = !ext.origin_balance().is_zero();
let address = u256_to_address(stack.peek(0));
if (
!schedule.no_empty && !ext.exists(&address)
) || (
schedule.no_empty && is_value_transfer && !ext.exists_and_not_null(&address)
) {
gas = overflowing!(gas.overflow_add(schedule.suicide_to_new_account_cost.into()));
}
InstructionCost::Gas(gas)
},
instructions::MSTORE | instructions::MLOAD => {
InstructionCost::GasMem(default_gas, try!(mem_needed_const(stack.peek(0), 32)))
InstructionCost::GasMem(default_gas, try!(mem_needed_const(stack.peek(0), 32)), None)
},
instructions::MSTORE8 => {
InstructionCost::GasMem(default_gas, try!(mem_needed_const(stack.peek(0), 1)))
InstructionCost::GasMem(default_gas, try!(mem_needed_const(stack.peek(0), 1)), None)
},
instructions::RETURN => {
InstructionCost::GasMem(default_gas, try!(mem_needed(stack.peek(0), stack.peek(1))))
InstructionCost::GasMem(default_gas, try!(mem_needed(stack.peek(0), stack.peek(1))), None)
},
instructions::SHA3 => {
let w = overflowing!(add_gas_usize(try!(Gas::from_u256(*stack.peek(1))), 31));
let words = w >> 5;
let gas = Gas::from(schedule.sha3_gas) + (Gas::from(schedule.sha3_word_gas) * words);
InstructionCost::GasMem(gas, try!(mem_needed(stack.peek(0), stack.peek(1))))
InstructionCost::GasMem(gas, try!(mem_needed(stack.peek(0), stack.peek(1))), None)
},
instructions::CALLDATACOPY | instructions::CODECOPY => {
InstructionCost::GasMemCopy(default_gas, try!(mem_needed(stack.peek(0), stack.peek(2))), try!(Gas::from_u256(*stack.peek(2))))
},
instructions::EXTCODECOPY => {
InstructionCost::GasMemCopy(default_gas, try!(mem_needed(stack.peek(1), stack.peek(3))), try!(Gas::from_u256(*stack.peek(3))))
InstructionCost::GasMemCopy(schedule.extcodecopy_base_gas.into(), try!(mem_needed(stack.peek(1), stack.peek(3))), try!(Gas::from_u256(*stack.peek(3))))
},
instructions::LOG0...instructions::LOG4 => {
let no_of_topics = instructions::get_log_topics(instruction);
@@ -117,39 +169,68 @@ impl<Gas: CostType> Gasometer<Gas> {
let data_gas = overflowing!(try!(Gas::from_u256(*stack.peek(1))).overflow_mul(Gas::from(schedule.log_data_gas)));
let gas = overflowing!(data_gas.overflow_add(Gas::from(log_gas)));
InstructionCost::GasMem(gas, try!(mem_needed(stack.peek(0), stack.peek(1))))
InstructionCost::GasMem(gas, try!(mem_needed(stack.peek(0), stack.peek(1))), None)
},
instructions::CALL | instructions::CALLCODE => {
let mut gas = overflowing!(add_gas_usize(try!(Gas::from_u256(*stack.peek(0))), schedule.call_gas));
let mut gas = Gas::from(schedule.call_gas);
let mem = cmp::max(
try!(mem_needed(stack.peek(5), stack.peek(6))),
try!(mem_needed(stack.peek(3), stack.peek(4)))
);
let address = u256_to_address(stack.peek(1));
let is_value_transfer = !stack.peek(2).is_zero();
if instruction == instructions::CALL && !ext.exists(&address) {
gas = overflowing!(gas.overflow_add(Gas::from(schedule.call_new_account_gas)));
if instruction == instructions::CALL {
if (
!schedule.no_empty && !ext.exists(&address)
) || (
schedule.no_empty && is_value_transfer && !ext.exists_and_not_null(&address)
) {
gas = overflowing!(gas.overflow_add(schedule.call_new_account_gas.into()));
}
};
if !stack.peek(2).is_zero() {
gas = overflowing!(gas.overflow_add(Gas::from(schedule.call_value_transfer_gas)));
if is_value_transfer {
gas = overflowing!(gas.overflow_add(schedule.call_value_transfer_gas.into()));
};
InstructionCost::GasMem(gas,mem)
// TODO: refactor to avoid duplicate calculation here and later on.
let (mem_gas_cost, _, _) = try!(self.mem_gas_cost(schedule, current_mem_size, &mem));
let cost_so_far = overflowing!(gas.overflow_add(mem_gas_cost.into()));
let requested = Gas::from_u256(*stack.peek(0));
let provided = try!(self.gas_provided(schedule, cost_so_far, Some(requested)));
gas = overflowing!(gas.overflow_add(provided));
InstructionCost::GasMem(gas, mem, Some(provided))
},
instructions::DELEGATECALL => {
let gas = overflowing!(add_gas_usize(try!(Gas::from_u256(*stack.peek(0))), schedule.call_gas));
let mut gas = Gas::from(schedule.call_gas);
let mem = cmp::max(
try!(mem_needed(stack.peek(4), stack.peek(5))),
try!(mem_needed(stack.peek(2), stack.peek(3)))
);
InstructionCost::GasMem(gas, mem)
// TODO: refactor to avoid duplicate calculation here and later on.
let (mem_gas_cost, _, _) = try!(self.mem_gas_cost(schedule, current_mem_size, &mem));
let cost_so_far = overflowing!(gas.overflow_add(mem_gas_cost.into()));
let requested = Gas::from_u256(*stack.peek(0));
let provided = try!(self.gas_provided(schedule, cost_so_far, Some(requested)));
gas = overflowing!(gas.overflow_add(provided));
InstructionCost::GasMem(gas, mem, Some(provided))
},
instructions::CREATE => {
let gas = Gas::from(schedule.create_gas);
let mut gas = Gas::from(schedule.create_gas);
let mem = try!(mem_needed(stack.peek(1), stack.peek(2)));
InstructionCost::GasMem(gas, mem)
// TODO: refactor to avoid duplicate calculation here and later on.
let (mem_gas_cost, _, _) = try!(self.mem_gas_cost(schedule, current_mem_size, &mem));
let cost_so_far = overflowing!(gas.overflow_add(mem_gas_cost.into()));
let provided = try!(self.gas_provided(schedule, cost_so_far, None));
gas = overflowing!(gas.overflow_add(provided));
InstructionCost::GasMem(gas, mem, Some(provided))
},
instructions::EXP => {
let expon = stack.peek(1);
@@ -157,17 +238,17 @@ impl<Gas: CostType> Gasometer<Gas> {
let gas = Gas::from(schedule.exp_gas + schedule.exp_byte_gas * bytes);
InstructionCost::Gas(gas)
},
_ => InstructionCost::Gas(default_gas)
_ => InstructionCost::Gas(default_gas),
};
match cost {
InstructionCost::Gas(gas) => {
Ok((gas, self.current_mem_gas, 0))
Ok((gas, self.current_mem_gas, 0, None))
},
InstructionCost::GasMem(gas, mem_size) => {
InstructionCost::GasMem(gas, mem_size, provided) => {
let (mem_gas_cost, new_mem_gas, new_mem_size) = try!(self.mem_gas_cost(schedule, current_mem_size, &mem_size));
let gas = overflowing!(gas.overflow_add(mem_gas_cost));
Ok((gas, new_mem_gas, new_mem_size))
Ok((gas, new_mem_gas, new_mem_size, provided))
},
InstructionCost::GasMemCopy(gas, mem_size, copy) => {
let (mem_gas_cost, new_mem_gas, new_mem_size) = try!(self.mem_gas_cost(schedule, current_mem_size, &mem_size));
@@ -175,7 +256,7 @@ impl<Gas: CostType> Gasometer<Gas> {
let copy_gas = Gas::from(schedule.copy_gas) * copy;
let gas = overflowing!(gas.overflow_add(copy_gas));
let gas = overflowing!(gas.overflow_add(mem_gas_cost));
Ok((gas, new_mem_gas, new_mem_size))
Ok((gas, new_mem_gas, new_mem_size, None))
}
}
}

View File

@@ -89,8 +89,6 @@ impl<'a> CodeReader<'a> {
enum InstructionResult<Gas> {
Ok,
UseAllGas,
GasLeft(Gas),
UnusedGas(Gas),
JumpToPosition(U256),
// gas left, init_orf, init_size
@@ -129,7 +127,7 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
try!(self.verify_instruction(ext, instruction, &info, &stack));
// Calculate gas cost
let (gas_cost, mem_gas, mem_size) = try!(gasometer.get_gas_cost_mem(ext, instruction, &info, &stack, self.mem.size()));
let (gas_cost, mem_gas, mem_size, provided) = try!(gasometer.get_gas_cost_mem(ext, instruction, &info, &stack, self.mem.size()));
// TODO: make compile-time removable if too much of a performance hit.
let trace_executed = ext.trace_prepare_execute(reader.position - 1, instruction, &gas_cost.as_u256());
@@ -155,25 +153,19 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
// Execute instruction
let result = try!(self.exec_instruction(
gasometer.current_gas, &params, ext, instruction, &mut reader, &mut stack
gasometer.current_gas, &params, ext, instruction, &mut reader, &mut stack, provided
));
if let InstructionResult::UnusedGas(ref gas) = result {
gasometer.current_gas = gasometer.current_gas + *gas;
}
if trace_executed {
ext.trace_executed(gasometer.current_gas.as_u256(), stack.peek_top(info.ret), mem_written.map(|(o, s)| (o, &(self.mem[o..(o + s)]))), store_written);
}
// Advance
match result {
InstructionResult::Ok => {},
InstructionResult::UnusedGas(gas) => {
gasometer.current_gas = gasometer.current_gas + gas;
},
InstructionResult::UseAllGas => {
gasometer.current_gas = Cost::from(0);
},
InstructionResult::GasLeft(gas_left) => {
gasometer.current_gas = gas_left;
},
InstructionResult::JumpToPosition(position) => {
let pos = try!(self.verify_jump(position, &valid_jump_destinations));
reader.position = pos;
@@ -182,6 +174,7 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
return Ok(GasLeft::NeedsReturn(gas.as_u256(), self.mem.read_slice(off, size)));
},
InstructionResult::StopExecution => break,
_ => {},
}
}
@@ -264,7 +257,8 @@ impl<Cost: CostType> Interpreter<Cost> {
ext: &mut evm::Ext,
instruction: Instruction,
code: &mut CodeReader,
stack: &mut Stack<U256>
stack: &mut Stack<U256>,
provided: Option<Cost>
) -> evm::Result<InstructionResult<Cost>> {
match instruction {
instructions::JUMP => {
@@ -289,31 +283,32 @@ impl<Cost: CostType> Interpreter<Cost> {
let endowment = stack.pop_back();
let init_off = stack.pop_back();
let init_size = stack.pop_back();
let create_gas = provided.expect("`provided` comes through Self::exec from `Gasometer::get_gas_cost_mem`; `gas_gas_mem_cost` guarantees `Some` when instruction is `CALL`/`CALLCODE`/`DELEGATECALL`/`CREATE`; this is `CREATE`; qed");
let contract_code = self.mem.read_slice(init_off, init_size);
let can_create = ext.balance(&params.address) >= endowment && ext.depth() < ext.schedule().max_depth;
if !can_create {
stack.push(U256::zero());
return Ok(InstructionResult::Ok);
return Ok(InstructionResult::UnusedGas(create_gas));
}
let create_result = ext.create(&gas.as_u256(), &endowment, contract_code);
let create_result = ext.create(&create_gas.as_u256(), &endowment, contract_code);
return match create_result {
ContractCreateResult::Created(address, gas_left) => {
stack.push(address_to_u256(address));
Ok(InstructionResult::GasLeft(Cost::from_u256(gas_left).expect("Gas left cannot be greater.")))
Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater.")))
},
ContractCreateResult::Failed => {
stack.push(U256::zero());
// TODO [todr] Should we just StopExecution here?
Ok(InstructionResult::UseAllGas)
Ok(InstructionResult::Ok)
}
};
},
instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL => {
assert!(ext.schedule().call_value_transfer_gas > ext.schedule().call_stipend, "overflow possible");
let call_gas = Cost::from_u256(stack.pop_back()).expect("Gas is already validated.");
stack.pop_back();
let call_gas = provided.expect("`provided` comes through Self::exec from `Gasometer::get_gas_cost_mem`; `gas_gas_mem_cost` guarantees `Some` when instruction is `CALL`/`CALLCODE`/`DELEGATECALL`/`CREATE`; this is one of `CALL`/`CALLCODE`/`DELEGATECALL`; qed");
let code_address = stack.pop_back();
let code_address = u256_to_address(&code_address);
@@ -331,7 +326,7 @@ impl<Cost: CostType> Interpreter<Cost> {
// Add stipend (only CALL|CALLCODE when value > 0)
let call_gas = call_gas + value.map_or_else(|| Cost::from(0), |val| match val.is_zero() {
false => Cost::from(ext.schedule().call_stipend),
true => Cost::from(0)
true => Cost::from(0),
});
// Get sender & receive addresses, check if we have balance

View File

@@ -21,7 +21,7 @@ use util::sha3::*;
use bit_set::BitSet;
use super::super::instructions;
const CACHE_CODE_ITEMS: usize = 4096;
const CACHE_CODE_ITEMS: usize = 65536;
/// GLobal cache for EVM interpreter
pub struct SharedCache {

View File

@@ -70,6 +70,8 @@ pub struct Schedule {
pub quad_coeff_div: usize,
/// Cost for contract length when executing `CREATE`
pub create_data_gas: usize,
/// Maximum code size when creating a contract.
pub create_data_limit: usize,
/// Transaction cost
pub tx_gas: usize,
/// `CREATE` transaction cost
@@ -80,6 +82,23 @@ pub struct Schedule {
pub tx_data_non_zero_gas: usize,
/// Gas price for copying memory
pub copy_gas: usize,
/// Price of EXTCODESIZE
pub extcodesize_gas: usize,
/// Base price of EXTCODECOPY
pub extcodecopy_base_gas: usize,
/// Price of BALANCE
pub balance_gas: usize,
/// Price of SUICIDE
pub suicide_gas: usize,
/// Amount of additional gas to pay when SUICIDE credits a non-existant account
pub suicide_to_new_account_cost: usize,
/// If Some(x): let limit = GAS * (x - 1) / x; let CALL's gas = min(requested, limit). let CREATE's gas = limit.
/// If None: let CALL's gas = (requested > GAS ? [OOG] : GAS). let CREATE's gas = GAS
pub sub_gas_cap_divisor: Option<usize>,
/// Don't ever make empty accounts; contracts start with nonce=1. Also, don't charge 25k when sending/suicide zero-value.
pub no_empty: bool,
/// Kill empty accounts if touched.
pub kill_empty: bool,
}
impl Schedule {
@@ -93,8 +112,54 @@ impl Schedule {
Self::new(true, true, 53000)
}
/// Schedule for the post-EIP-150-era of the Ethereum main net.
pub fn new_post_eip150(max_code_size: usize, fix_exp: bool, no_empty: bool, kill_empty: bool) -> Schedule {
Schedule {
exceptional_failed_code_deposit: true,
have_delegate_call: true,
stack_limit: 1024,
max_depth: 1024,
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
exp_gas: 10,
exp_byte_gas: if fix_exp {50} else {10},
sha3_gas: 30,
sha3_word_gas: 6,
sload_gas: 200,
sstore_set_gas: 20000,
sstore_reset_gas: 5000,
sstore_refund_gas: 15000,
jumpdest_gas: 1,
log_gas: 375,
log_data_gas: 8,
log_topic_gas: 375,
create_gas: 32000,
call_gas: 700,
call_stipend: 2300,
call_value_transfer_gas: 9000,
call_new_account_gas: 25000,
suicide_refund_gas: 24000,
memory_gas: 3,
quad_coeff_div: 512,
create_data_gas: 200,
create_data_limit: max_code_size,
tx_gas: 21000,
tx_create_gas: 53000,
tx_data_zero_gas: 4,
tx_data_non_zero_gas: 68,
copy_gas: 3,
extcodesize_gas: 700,
extcodecopy_base_gas: 700,
balance_gas: 400,
suicide_gas: 5000,
suicide_to_new_account_cost: 25000,
sub_gas_cap_divisor: Some(64),
no_empty: no_empty,
kill_empty: kill_empty,
}
}
fn new(efcd: bool, hdc: bool, tcg: usize) -> Schedule {
Schedule{
Schedule {
exceptional_failed_code_deposit: efcd,
have_delegate_call: hdc,
stack_limit: 1024,
@@ -121,11 +186,20 @@ impl Schedule {
memory_gas: 3,
quad_coeff_div: 512,
create_data_gas: 200,
create_data_limit: usize::max_value(),
tx_gas: 21000,
tx_create_gas: tcg,
tx_data_zero_gas: 4,
tx_data_non_zero_gas: 68,
copy_gas: 3,
extcodesize_gas: 20,
extcodecopy_base_gas: 20,
balance_gas: 20,
suicide_gas: 0,
suicide_to_new_account_cost: 0,
sub_gas_cap_divisor: None,
no_empty: false,
kill_empty: false,
}
}
}

View File

@@ -92,6 +92,14 @@ impl Ext for FakeExt {
self.balances.contains_key(address)
}
fn exists_and_not_null(&self, address: &Address) -> bool {
self.balances.get(address).map_or(false, |b| !b.is_zero())
}
fn origin_balance(&self) -> U256 {
unimplemented!()
}
fn balance(&self, address: &Address) -> U256 {
*self.balances.get(address).unwrap()
}

View File

@@ -16,7 +16,7 @@
//! Transaction Execution environment.
use common::*;
use state::*;
use state::{State, CleanupMode};
use engines::Engine;
use types::executed::CallType;
use evm::{self, Ext, Factory, Finalize};
@@ -26,10 +26,10 @@ use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, E
use crossbeam;
pub use types::executed::{Executed, ExecutionResult};
/// Max depth to avoid stack overflow (when it's reached we start a new thread with VM)
/// Roughly estimate what stack size each level of evm depth will use
/// TODO [todr] We probably need some more sophisticated calculations here (limit on my machine 132)
/// Maybe something like here: `https://github.com/ethereum/libethereum/blob/4db169b8504f2b87f7d5a481819cfb959fc65f6c/libethereum/ExtVM.cpp`
const MAX_VM_DEPTH_FOR_THREAD: usize = 64;
const STACK_SIZE_PER_DEPTH: usize = 24*1024;
/// Returns new address created from address and given nonce.
pub fn contract_address(address: &Address, nonce: &U256) -> Address {
@@ -148,12 +148,13 @@ impl<'a> Executive<'a> {
// TODO: we might need bigints here, or at least check overflows.
let balance = self.state.balance(&sender);
let gas_cost = U512::from(t.gas) * U512::from(t.gas_price);
let gas_cost = t.gas.full_mul(t.gas_price);
let total_cost = U512::from(t.value) + gas_cost;
// avoid unaffordable transactions
if U512::from(balance) < total_cost {
return Err(From::from(ExecutionError::NotEnoughCash { required: total_cost, got: U512::from(balance) }));
let balance512 = U512::from(balance);
if balance512 < total_cost {
return Err(From::from(ExecutionError::NotEnoughCash { required: total_cost, got: balance512 }));
}
// NOTE: there can be no invalid transactions from this point.
@@ -212,8 +213,11 @@ impl<'a> Executive<'a> {
tracer: &mut T,
vm_tracer: &mut V
) -> evm::Result<U256> where T: Tracer, V: VMTracer {
let depth_threshold = ::io::LOCAL_STACK_SIZE.with(|sz| sz.get() / STACK_SIZE_PER_DEPTH);
// Ordinary execution - keep VM in same thread
if (self.depth + 1) % MAX_VM_DEPTH_FOR_THREAD != 0 {
if (self.depth + 1) % depth_threshold != 0 {
let vm_factory = self.vm_factory;
let mut ext = self.as_externalities(OriginInfo::from(&params), unconfirmed_substate, output_policy, tracer, vm_tracer);
trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call);
@@ -248,9 +252,11 @@ impl<'a> Executive<'a> {
// backup used in case of running out of gas
self.state.snapshot();
let schedule = self.engine.schedule(self.info);
// at first, transfer value to destination
if let ActionValue::Transfer(val) = params.value {
self.state.transfer_balance(&params.sender, &params.address, &val);
self.state.transfer_balance(&params.sender, &params.address, &val, substate.to_cleanup_mode(&schedule));
}
trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info);
@@ -265,7 +271,7 @@ impl<'a> Executive<'a> {
let cost = self.engine.cost_of_builtin(&params.code_address, data);
if cost <= params.gas {
self.engine.execute_builtin(&params.code_address, data, &mut output);
self.state.clear_snapshot();
self.state.discard_snapshot();
// trace only top level calls to builtins to avoid DDoS attacks
if self.depth == 0 {
@@ -285,7 +291,7 @@ impl<'a> Executive<'a> {
Ok(params.gas - cost)
} else {
// just drain the whole gas
self.state.revert_snapshot();
self.state.revert_to_snapshot();
tracer.trace_failed_call(trace_info, vec![]);
@@ -331,7 +337,7 @@ impl<'a> Executive<'a> {
res
} else {
// otherwise it's just a basic transaction, only do tracing, if necessary.
self.state.clear_snapshot();
self.state.discard_snapshot();
tracer.trace_call(trace_info, U256::zero(), trace_output, vec![]);
Ok(params.gas)
@@ -356,12 +362,14 @@ impl<'a> Executive<'a> {
let mut unconfirmed_substate = Substate::new();
// create contract and transfer value to it if necessary
let schedule = self.engine.schedule(self.info);
let nonce_offset = if schedule.no_empty {1} else {0}.into();
let prev_bal = self.state.balance(&params.address);
if let ActionValue::Transfer(val) = params.value {
self.state.sub_balance(&params.sender, &val);
self.state.new_contract(&params.address, val + prev_bal);
self.state.new_contract(&params.address, val + prev_bal, nonce_offset);
} else {
self.state.new_contract(&params.address, prev_bal);
self.state.new_contract(&params.address, prev_bal, nonce_offset);
}
let trace_info = tracer.prepare_trace_create(&params);
@@ -397,7 +405,7 @@ impl<'a> Executive<'a> {
fn finalize(
&mut self,
t: &SignedTransaction,
substate: Substate,
mut substate: Substate,
result: evm::Result<U256>,
output: Bytes,
trace: Vec<FlatTrace>,
@@ -413,7 +421,7 @@ impl<'a> Executive<'a> {
// real ammount to refund
let gas_left_prerefund = match result { Ok(x) => x, _ => 0.into() };
let refunded = cmp::min(refunds_bound, (t.gas - gas_left_prerefund) / U256::from(2));
let refunded = cmp::min(refunds_bound, (t.gas - gas_left_prerefund) >> 1);
let gas_left = gas_left_prerefund + refunded;
let gas_used = t.gas - gas_left;
@@ -423,16 +431,32 @@ impl<'a> Executive<'a> {
trace!("exec::finalize: t.gas={}, sstore_refunds={}, suicide_refunds={}, refunds_bound={}, gas_left_prerefund={}, refunded={}, gas_left={}, gas_used={}, refund_value={}, fees_value={}\n",
t.gas, sstore_refunds, suicide_refunds, refunds_bound, gas_left_prerefund, refunded, gas_left, gas_used, refund_value, fees_value);
trace!("exec::finalize: Refunding refund_value={}, sender={}\n", refund_value, t.sender().unwrap());
self.state.add_balance(&t.sender().unwrap(), &refund_value);
let sender = match t.sender() {
Ok(sender) => sender,
Err(e) => {
debug!(target: "executive", "attempted to finalize transaction without sender: {}", e);
return Err(ExecutionError::Internal);
}
};
trace!("exec::finalize: Refunding refund_value={}, sender={}\n", refund_value, sender);
// Below: NoEmpty is safe since the sender must already be non-null to have sent this transaction
self.state.add_balance(&sender, &refund_value, CleanupMode::NoEmpty);
trace!("exec::finalize: Compensating author: fees_value={}, author={}\n", fees_value, &self.info.author);
self.state.add_balance(&self.info.author, &fees_value);
self.state.add_balance(&self.info.author, &fees_value, substate.to_cleanup_mode(&schedule));
// perform suicides
for address in &substate.suicides {
self.state.kill_account(address);
}
// perform garbage-collection
for address in &substate.garbage {
if self.state.exists(address) && !self.state.exists_and_not_null(address) {
self.state.kill_account(address);
}
}
match result {
Err(evm::Error::Internal) => Err(ExecutionError::Internal),
Err(_) => {
@@ -473,10 +497,10 @@ impl<'a> Executive<'a> {
| Err(evm::Error::BadInstruction {.. })
| Err(evm::Error::StackUnderflow {..})
| Err(evm::Error::OutOfStack {..}) => {
self.state.revert_snapshot();
self.state.revert_to_snapshot();
},
Ok(_) | Err(evm::Error::Internal) => {
self.state.clear_snapshot();
self.state.discard_snapshot();
substate.accrue(un_substate);
}
}
@@ -495,6 +519,7 @@ mod tests {
use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer};
use trace::{VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, VMTracer, NoopVMTracer, ExecutiveVMTracer};
use types::executed::CallType;
use state::{CleanupMode};
#[test]
fn test_contract_address() {
@@ -516,7 +541,7 @@ mod tests {
params.value = ActionValue::Transfer(U256::from(0x7));
let mut state_result = get_temp_state();
let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from(0x100u64));
state.add_balance(&sender, &U256::from(0x100u64), CleanupMode::NoEmpty);
let info = EnvInfo::default();
let engine = TestEngine::new(0);
let mut substate = Substate::new();
@@ -575,7 +600,7 @@ mod tests {
params.value = ActionValue::Transfer(U256::from(100));
let mut state_result = get_temp_state();
let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from(100));
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty);
let info = EnvInfo::default();
let engine = TestEngine::new(0);
let mut substate = Substate::new();
@@ -631,7 +656,7 @@ mod tests {
params.call_type = CallType::Call;
let mut state_result = get_temp_state();
let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from(100));
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty);
let info = EnvInfo::default();
let engine = TestEngine::new(5);
let mut substate = Substate::new();
@@ -689,7 +714,7 @@ mod tests {
VMOperation { pc: 33, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99985.into(), stack_push: vec_into![29], mem_diff: None, store_diff: None }) },
VMOperation { pc: 35, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99982.into(), stack_push: vec_into![3], mem_diff: None, store_diff: None }) },
VMOperation { pc: 37, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99979.into(), stack_push: vec_into![23], mem_diff: None, store_diff: None }) },
VMOperation { pc: 39, instruction: 240, gas_cost: 32000.into(), executed: Some(VMExecutedOperation { gas_used: 67979.into(), stack_push: vec_into![U256::from_dec_str("1135198453258042933984631383966629874710669425204").unwrap()], mem_diff: None, store_diff: None }) },
VMOperation { pc: 39, instruction: 240, gas_cost: 99979.into(), executed: Some(VMExecutedOperation { gas_used: 64755.into(), stack_push: vec_into![U256::from_dec_str("1135198453258042933984631383966629874710669425204").unwrap()], mem_diff: None, store_diff: None }) },
VMOperation { pc: 40, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 64752.into(), stack_push: vec_into![0], mem_diff: None, store_diff: None }) },
VMOperation { pc: 42, instruction: 85, gas_cost: 20000.into(), executed: Some(VMExecutedOperation { gas_used: 44752.into(), stack_push: vec_into![], mem_diff: None, store_diff: Some(StorageDiff { location: 0.into(), value: U256::from_dec_str("1135198453258042933984631383966629874710669425204").unwrap() }) }) }
],
@@ -740,7 +765,7 @@ mod tests {
params.value = ActionValue::Transfer(100.into());
let mut state_result = get_temp_state();
let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from(100));
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty);
let info = EnvInfo::default();
let engine = TestEngine::new(5);
let mut substate = Substate::new();
@@ -828,7 +853,7 @@ mod tests {
params.value = ActionValue::Transfer(U256::from(100));
let mut state_result = get_temp_state();
let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from(100));
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty);
let info = EnvInfo::default();
let engine = TestEngine::new(0);
let mut substate = Substate::new();
@@ -880,7 +905,7 @@ mod tests {
params.value = ActionValue::Transfer(U256::from(100));
let mut state_result = get_temp_state();
let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from(100));
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty);
let info = EnvInfo::default();
let engine = TestEngine::new(1024);
let mut substate = Substate::new();
@@ -940,7 +965,7 @@ mod tests {
let mut state = state_result.reference_mut();
state.init_code(&address_a, code_a.clone());
state.init_code(&address_b, code_b.clone());
state.add_balance(&sender, &U256::from(100_000));
state.add_balance(&sender, &U256::from(100_000), CleanupMode::NoEmpty);
let info = EnvInfo::default();
let engine = TestEngine::new(0);
@@ -1013,13 +1038,13 @@ mod tests {
gas: U256::from(100_000),
gas_price: U256::zero(),
nonce: U256::zero()
}.sign(keypair.secret());
}.sign(keypair.secret(), None);
let sender = t.sender().unwrap();
let contract = contract_address(&sender, &U256::zero());
let mut state_result = get_temp_state();
let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from(18));
state.add_balance(&sender, &U256::from(18), CleanupMode::NoEmpty);
let mut info = EnvInfo::default();
info.gas_limit = U256::from(100_000);
let engine = TestEngine::new(0);
@@ -1080,12 +1105,12 @@ mod tests {
gas: U256::from(100_000),
gas_price: U256::zero(),
nonce: U256::one()
}.sign(keypair.secret());
}.sign(keypair.secret(), None);
let sender = t.sender().unwrap();
let mut state_result = get_temp_state();
let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from(17));
state.add_balance(&sender, &U256::from(17), CleanupMode::NoEmpty);
let mut info = EnvInfo::default();
info.gas_limit = U256::from(100_000);
let engine = TestEngine::new(0);
@@ -1113,12 +1138,12 @@ mod tests {
gas: U256::from(80_001),
gas_price: U256::zero(),
nonce: U256::zero()
}.sign(keypair.secret());
}.sign(keypair.secret(), None);
let sender = t.sender().unwrap();
let mut state_result = get_temp_state();
let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from(17));
state.add_balance(&sender, &U256::from(17), CleanupMode::NoEmpty);
let mut info = EnvInfo::default();
info.gas_used = U256::from(20_000);
info.gas_limit = U256::from(100_000);
@@ -1148,12 +1173,12 @@ mod tests {
gas: U256::from(100_000),
gas_price: U256::one(),
nonce: U256::zero()
}.sign(keypair.secret());
}.sign(keypair.secret(), None);
let sender = t.sender().unwrap();
let mut state_result = get_temp_state();
let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from(100_017));
state.add_balance(&sender, &U256::from(100_017), CleanupMode::NoEmpty);
let mut info = EnvInfo::default();
info.gas_limit = U256::from(100_000);
let engine = TestEngine::new(0);
@@ -1188,7 +1213,7 @@ mod tests {
params.value = ActionValue::Transfer(U256::from_str("0de0b6b3a7640000").unwrap());
let mut state_result = get_temp_state();
let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap());
state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap(), CleanupMode::NoEmpty);
let info = EnvInfo::default();
let engine = TestEngine::new(0);
let mut substate = Substate::new();

View File

@@ -113,6 +113,12 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
self.state.exists(address)
}
fn exists_and_not_null(&self, address: &Address) -> bool {
self.state.exists_and_not_null(address)
}
fn origin_balance(&self) -> U256 { self.balance(&self.origin_info.address) }
fn balance(&self, address: &Address) -> U256 {
self.state.balance(address)
}
@@ -235,7 +241,7 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
},
OutputPolicy::InitContract(ref mut copy) => {
let return_cost = U256::from(data.len()) * U256::from(self.schedule.create_data_gas);
if return_cost > *gas {
if return_cost > *gas || data.len() > self.schedule.create_data_limit {
return match self.schedule.exceptional_failed_code_deposit {
true => Err(evm::Error::OutOfGas),
false => Ok(*gas)
@@ -266,11 +272,11 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
let address = self.origin_info.address.clone();
let balance = self.balance(&address);
if &address == refund_address {
// TODO [todr] To be consisted with CPP client we set balance to 0 in that case.
// TODO [todr] To be consistent with CPP client we set balance to 0 in that case.
self.state.sub_balance(&address, &balance);
} else {
trace!("Suiciding {} -> {} (xfer: {})", address, refund_address, balance);
self.state.transfer_balance(&address, refund_address, &balance);
trace!(target: "ext", "Suiciding {} -> {} (xfer: {})", address, refund_address, balance);
self.state.transfer_balance(&address, refund_address, &balance, self.substate.to_cleanup_mode(&self.schedule));
}
self.tracer.trace_suicide(address, balance, refund_address.clone());

View File

@@ -48,7 +48,9 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
let mut spec = match era {
ChainEra::Frontier => ethereum::new_frontier_test(),
ChainEra::Homestead => ethereum::new_homestead_test(),
ChainEra::DaoHardfork => ethereum::new_daohardfork_test(),
ChainEra::Eip150 => ethereum::new_eip150_test(),
ChainEra::Eip161 => ethereum::new_eip161_test(),
ChainEra::TransitionTest => ethereum::new_transition_test(),
};
spec.set_genesis_state(state);
spec.overwrite_genesis_params(genesis);
@@ -114,14 +116,38 @@ mod frontier_era_tests {
declare_test!{BlockchainTests_RandomTests_bl201507071825GO, "BlockchainTests/RandomTests/bl201507071825GO"}
}
mod daohardfork_tests {
mod transition_tests {
use tests::helpers::*;
use super::json_chain_test;
fn do_json_test(json_data: &[u8]) -> Vec<String> {
json_chain_test(json_data, ChainEra::DaoHardfork)
json_chain_test(json_data, ChainEra::TransitionTest)
}
declare_test!{BlockchainTests_TestNetwork_bcSimpleTransitionTest, "BlockchainTests/TestNetwork/bcSimpleTransitionTest"}
declare_test!{BlockchainTests_TestNetwork_bcTheDaoTest, "BlockchainTests/TestNetwork/bcTheDaoTest"}
declare_test!{BlockchainTests_TestNetwork_bcEIP150Test, "BlockchainTests/TestNetwork/bcEIP150Test"}
}
mod eip150_blockchain_tests {
use tests::helpers::*;
use super::json_chain_test;
fn do_json_test(json_data: &[u8]) -> Vec<String> {
json_chain_test(json_data, ChainEra::Eip150)
}
declare_test!{BlockchainTests_EIP150_bcBlockGasLimitTest, "BlockchainTests/EIP150/bcBlockGasLimitTest"}
declare_test!{BlockchainTests_EIP150_bcForkStressTest, "BlockchainTests/EIP150/bcForkStressTest"}
declare_test!{BlockchainTests_EIP150_bcGasPricerTest, "BlockchainTests/EIP150/bcGasPricerTest"}
declare_test!{BlockchainTests_EIP150_bcInvalidHeaderTest, "BlockchainTests/EIP150/bcInvalidHeaderTest"}
declare_test!{BlockchainTests_EIP150_bcInvalidRLPTest, "BlockchainTests/EIP150/bcInvalidRLPTest"}
declare_test!{BlockchainTests_EIP150_bcMultiChainTest, "BlockchainTests/EIP150/bcMultiChainTest"}
declare_test!{BlockchainTests_EIP150_bcRPC_API_Test, "BlockchainTests/EIP150/bcRPC_API_Test"}
declare_test!{BlockchainTests_EIP150_bcStateTest, "BlockchainTests/EIP150/bcStateTest"}
declare_test!{BlockchainTests_EIP150_bcTotalDifficultyTest, "BlockchainTests/EIP150/bcTotalDifficultyTest"}
declare_test!{BlockchainTests_EIP150_bcUncleHeaderValiditiy, "BlockchainTests/EIP150/bcUncleHeaderValiditiy"}
declare_test!{BlockchainTests_EIP150_bcUncleTest, "BlockchainTests/EIP150/bcUncleTest"}
declare_test!{BlockchainTests_EIP150_bcValidBlockTest, "BlockchainTests/EIP150/bcValidBlockTest"}
declare_test!{BlockchainTests_EIP150_bcWalletTest, "BlockchainTests/EIP150/bcWalletTest"}
}

View File

@@ -0,0 +1,43 @@
// Copyright 2015, 2016 Ethcore (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 super::test_common::*;
use tests::helpers::*;
use super::state::json_chain_test;
fn do_json_test(json_data: &[u8]) -> Vec<String> {
json_chain_test(json_data, ChainEra::Eip150)
}
declare_test!{StateTests_EIP150_stEIPSpecificTest, "StateTests/EIP150/stEIPSpecificTest"}
declare_test!{StateTests_EIP150_stEIPsingleCodeGasPrices, "StateTests/EIP150/stEIPsingleCodeGasPrices"}
declare_test!{StateTests_EIP150_stMemExpandingEIPCalls, "StateTests/EIP150/stMemExpandingEIPCalls"}
declare_test!{StateTests_EIP150_stCallCodes, "StateTests/EIP150/Homestead/stCallCodes"}
declare_test!{StateTests_EIP150_stCallCreateCallCodeTest, "StateTests/EIP150/Homestead/stCallCreateCallCodeTest"}
declare_test!{StateTests_EIP150_stDelegatecallTest, "StateTests/EIP150/Homestead/stDelegatecallTest"}
declare_test!{StateTests_EIP150_stInitCodeTest, "StateTests/EIP150/Homestead/stInitCodeTest"}
declare_test!{StateTests_EIP150_stLogTests, "StateTests/EIP150/Homestead/stLogTests"}
declare_test!{heavy => StateTests_EIP150_stMemoryStressTest, "StateTests/EIP150/Homestead/stMemoryStressTest"}
declare_test!{heavy => StateTests_EIP150_stMemoryTest, "StateTests/EIP150/Homestead/stMemoryTest"}
declare_test!{StateTests_EIP150_stPreCompiledContracts, "StateTests/EIP150/Homestead/stPreCompiledContracts"}
declare_test!{heavy => StateTests_EIP150_stQuadraticComplexityTest, "StateTests/EIP150/Homestead/stQuadraticComplexityTest"}
declare_test!{StateTests_EIP150_stRecursiveCreate, "StateTests/EIP150/Homestead/stRecursiveCreate"}
declare_test!{StateTests_EIP150_stRefundTest, "StateTests/EIP150/Homestead/stRefundTest"}
declare_test!{StateTests_EIP150_stSpecialTest, "StateTests/EIP150/Homestead/stSpecialTest"}
declare_test!{StateTests_EIP150_stSystemOperationsTest, "StateTests/EIP150/Homestead/stSystemOperationsTest"}
declare_test!{StateTests_EIP150_stTransactionTest, "StateTests/EIP150/Homestead/stTransactionTest"}
declare_test!{StateTests_EIP150_stWalletTest, "StateTests/EIP150/Homestead/stWalletTest"}

View File

@@ -0,0 +1,51 @@
// Copyright 2015, 2016 Ethcore (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 super::test_common::*;
use tests::helpers::*;
use super::state::json_chain_test;
fn do_json_test(json_data: &[u8]) -> Vec<String> {
json_chain_test(json_data, ChainEra::Eip161)
}
declare_test!{StateTests_EIP158_stEIP158SpecificTest, "StateTests/EIP158/stEIP158SpecificTest"}
declare_test!{StateTests_EIP158_stNonZeroCallsTest, "StateTests/EIP158/stNonZeroCallsTest"}
declare_test!{StateTests_EIP158_stZeroCallsTest, "StateTests/EIP158/stZeroCallsTest"}
declare_test!{StateTests_EIP158_EIP150_stMemExpandingEIPCalls, "StateTests/EIP158/EIP150/stMemExpandingEIPCalls"}
declare_test!{StateTests_EIP158_EIP150_stEIPSpecificTest, "StateTests/EIP158/EIP150/stEIPSpecificTest"}
declare_test!{StateTests_EIP158_EIP150_stEIPsingleCodeGasPrices, "StateTests/EIP158/EIP150/stEIPsingleCodeGasPrices"}
declare_test!{StateTests_EIP158_EIP150_stChangedTests, "StateTests/EIP158/EIP150/stChangedTests"}
declare_test!{StateTests_EIP158_Homestead_stBoundsTest, "StateTests/EIP158/Homestead/stBoundsTest"}
declare_test!{StateTests_EIP158_Homestead_stCallCodes, "StateTests/EIP158/Homestead/stCallCodes"}
declare_test!{StateTests_EIP158_Homestead_stCallCreateCallCodeTest, "StateTests/EIP158/Homestead/stCallCreateCallCodeTest"}
declare_test!{StateTests_EIP158_Homestead_stCallDelegateCodes, "StateTests/EIP158/Homestead/stCallDelegateCodes"}
declare_test!{StateTests_EIP158_Homestead_stCallDelegateCodesCallCode, "StateTests/EIP158/Homestead/stCallDelegateCodesCallCode"}
declare_test!{StateTests_EIP158_Homestead_stDelegatecallTest, "StateTests/EIP158/Homestead/stDelegatecallTest"}
declare_test!{StateTests_EIP158_Homestead_stHomeSteadSpecific, "StateTests/EIP158/Homestead/stHomeSteadSpecific"}
declare_test!{StateTests_EIP158_Homestead_stInitCodeTest, "StateTests/EIP158/Homestead/stInitCodeTest"}
declare_test!{StateTests_EIP158_Homestead_stLogTests, "StateTests/EIP158/Homestead/stLogTests"}
declare_test!{heavy => StateTests_EIP158_Homestead_stMemoryTest, "StateTests/EIP158/Homestead/stMemoryTest"}
declare_test!{StateTests_EIP158_Homestead_stPreCompiledContracts, "StateTests/EIP158/Homestead/stPreCompiledContracts"}
declare_test!{heavy => StateTests_EIP158_Homestead_stQuadraticComplexityTest, "StateTests/EIP158/Homestead/stQuadraticComplexityTest"}
declare_test!{StateTests_EIP158_Homestead_stRecursiveCreate, "StateTests/EIP158/Homestead/stRecursiveCreate"}
declare_test!{StateTests_EIP158_Homestead_stRefundTest, "StateTests/EIP158/Homestead/stRefundTest"}
declare_test!{StateTests_EIP158_Homestead_stSpecialTest, "StateTests/EIP158/Homestead/stSpecialTest"}
declare_test!{StateTests_EIP158_Homestead_stSystemOperationsTest, "StateTests/EIP158/Homestead/stSystemOperationsTest"}
declare_test!{StateTests_EIP158_Homestead_stTransactionTest, "StateTests/EIP158/Homestead/stTransactionTest"}
declare_test!{StateTests_EIP158_Homestead_stWalletTest, "StateTests/EIP158/Homestead/stWalletTest"}

View File

@@ -91,10 +91,18 @@ impl<'a, T, V> Ext for TestExt<'a, T, V> where T: Tracer, V: VMTracer {
self.ext.exists(address)
}
fn exists_and_not_null(&self, address: &Address) -> bool {
self.ext.exists_and_not_null(address)
}
fn balance(&self, address: &Address) -> U256 {
self.ext.balance(address)
}
fn origin_balance(&self) -> U256 {
self.ext.origin_balance()
}
fn blockhash(&self, number: &U256) -> H256 {
self.ext.blockhash(number)
}

View File

@@ -36,3 +36,6 @@ declare_test!{BlockchainTests_Homestead_bcUncleHeaderValiditiy, "BlockchainTests
declare_test!{BlockchainTests_Homestead_bcUncleTest, "BlockchainTests/Homestead/bcUncleTest"}
declare_test!{BlockchainTests_Homestead_bcValidBlockTest, "BlockchainTests/Homestead/bcValidBlockTest"}
declare_test!{BlockchainTests_Homestead_bcWalletTest, "BlockchainTests/Homestead/bcWalletTest"}
declare_test!{BlockchainTests_Homestead_bcShanghaiLove, "BlockchainTests/Homestead/bcShanghaiLove"}
// declare_test!{BlockchainTests_Homestead_bcSuicideIssue, "BlockchainTests/Homestead/bcSuicideIssue"}
declare_test!{BlockchainTests_Homestead_bcExploitTest, "BlockchainTests/Homestead/bcExploitTest"}

View File

@@ -23,4 +23,6 @@ mod state;
mod chain;
mod homestead_state;
mod homestead_chain;
mod eip150_state;
mod eip161_state;
mod trie;

File diff suppressed because it is too large Load Diff

View File

@@ -33,17 +33,24 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
Some(x) if x < 1_150_000 => &old_schedule,
Some(_) => &new_schedule
};
let allow_network_id_of_one = number.map_or(false, |n| n > 2600000);
let rlp: Vec<u8> = test.rlp.into();
let res = UntrustedRlp::new(&rlp)
.as_val()
.map_err(From::from)
.and_then(|t: SignedTransaction| t.validate(schedule, schedule.have_delegate_call));
.and_then(|t: SignedTransaction| t.validate(schedule, schedule.have_delegate_call, allow_network_id_of_one));
fail_unless(test.transaction.is_none() == res.is_err());
if let (Some(tx), Some(sender)) = (test.transaction, test.sender) {
let t = res.unwrap();
fail_unless(t.sender().unwrap() == sender.into());
let is_acceptable_network_id = match t.network_id() {
None => true,
Some(1) if allow_network_id_of_one => true,
_ => false,
};
fail_unless(is_acceptable_network_id);
let data: Vec<u8> = tx.data.into();
fail_unless(t.data == data);
fail_unless(t.gas_price == tx.gas_price.into());

View File

@@ -21,16 +21,18 @@ use util::*;
use util::using_queue::{UsingQueue, GetAction};
use account_provider::AccountProvider;
use views::{BlockView, HeaderView};
use state::State;
use header::Header;
use state::{State, CleanupMode};
use client::{MiningBlockChainClient, Executive, Executed, EnvInfo, TransactOptions, BlockID, CallAnalytics};
use executive::contract_address;
use block::{ClosedBlock, IsBlock, Block};
use header::BlockNumber;
use error::*;
use transaction::{Action, SignedTransaction};
use receipt::{Receipt, RichReceipt};
use spec::Spec;
use engines::Engine;
use miner::{MinerService, MinerStatus, TransactionQueue, AccountDetails, TransactionOrigin};
use miner::{MinerService, MinerStatus, TransactionQueue, PrioritizationStrategy, AccountDetails, TransactionOrigin};
use miner::work_notify::WorkPoster;
use client::TransactionImportResult;
use miner::price_info::PriceInfo;
@@ -47,6 +49,17 @@ pub enum PendingSet {
SealingOrElseQueue,
}
/// Type of the gas limit to apply to the transaction queue.
#[derive(Debug, PartialEq)]
pub enum GasLimit {
/// Depends on the block gas limit and is updated with every block.
Auto,
/// No limit.
None,
/// Set to a fixed gas value.
Fixed(U256),
}
/// Configures the behaviour of the miner.
#[derive(Debug, PartialEq)]
pub struct MinerOptions {
@@ -64,12 +77,16 @@ pub struct MinerOptions {
pub tx_gas_limit: U256,
/// Maximum size of the transaction queue.
pub tx_queue_size: usize,
/// Strategy to use for prioritizing transactions in the queue.
pub tx_queue_strategy: PrioritizationStrategy,
/// Whether we should fallback to providing all the queue's transactions or just pending.
pub pending_set: PendingSet,
/// How many historical work packages can we store before running out?
pub work_queue_size: usize,
/// Can we submit two different solutions for the same block and expect both to result in an import?
pub enable_resubmission: bool,
/// Global gas limit for all transaction in the queue except for local and retracted.
pub tx_queue_gas_limit: GasLimit,
}
impl Default for MinerOptions {
@@ -80,11 +97,13 @@ impl Default for MinerOptions {
reseal_on_external_tx: false,
reseal_on_own_tx: true,
tx_gas_limit: !U256::zero(),
tx_queue_size: 1024,
tx_queue_size: 2048,
tx_queue_strategy: PrioritizationStrategy::GasFactorAndGasPrice,
pending_set: PendingSet::AlwaysQueue,
reseal_min_period: Duration::from_secs(2),
work_queue_size: 20,
work_queue_size: 5,
enable_resubmission: true,
tx_queue_gas_limit: GasLimit::Auto,
}
}
}
@@ -188,7 +207,7 @@ impl Miner {
/// Creates new instance of miner without accounts, but with given spec.
pub fn with_spec(spec: &Spec) -> Miner {
Miner {
transaction_queue: Arc::new(Mutex::new(TransactionQueue::new())),
transaction_queue: Arc::new(Mutex::new(TransactionQueue::default())),
options: Default::default(),
next_allowed_reseal: Mutex::new(Instant::now()),
sealing_block_last_request: Mutex::new(0),
@@ -206,7 +225,13 @@ impl Miner {
/// Creates new instance of miner
pub fn new(options: MinerOptions, gas_pricer: GasPricer, spec: &Spec, accounts: Option<Arc<AccountProvider>>) -> Arc<Miner> {
let work_poster = if !options.new_work_notify.is_empty() { Some(WorkPoster::new(&options.new_work_notify)) } else { None };
let txq = Arc::new(Mutex::new(TransactionQueue::with_limits(options.tx_queue_size, options.tx_gas_limit)));
let gas_limit = match options.tx_queue_gas_limit {
GasLimit::Fixed(ref limit) => *limit,
_ => !U256::zero(),
};
let txq = Arc::new(Mutex::new(TransactionQueue::with_limits(
options.tx_queue_strategy, options.tx_queue_size, gas_limit, options.tx_gas_limit
)));
Arc::new(Miner {
transaction_queue: txq,
next_allowed_reseal: Mutex::new(Instant::now()),
@@ -243,6 +268,7 @@ impl Miner {
fn prepare_sealing(&self, chain: &MiningBlockChainClient) {
trace!(target: "miner", "prepare_sealing: entering");
let _timer = PerfTimer::new("prepare_sealing");
{
trace!(target: "miner", "recalibrating...");
let txq = self.transaction_queue.clone();
@@ -253,6 +279,7 @@ impl Miner {
trace!(target: "miner", "done recalibration.");
}
let _timer = PerfTimer::new("prepare_block");
let (transactions, mut open_block, original_work_hash) = {
let transactions = {self.transaction_queue.lock().top_transactions()};
let mut sealing_work = self.sealing_work.lock();
@@ -395,6 +422,10 @@ impl Miner {
let gas_limit = HeaderView::new(&chain.best_block_header()).gas_limit();
let mut queue = self.transaction_queue.lock();
queue.set_gas_limit(gas_limit);
if let GasLimit::Auto = self.options.tx_queue_gas_limit {
// Set total tx queue gas limit to be 20x the block gas limit.
queue.set_total_gas_limit(gas_limit * 20.into());
}
}
/// Returns true if we had to prepare new pending block
@@ -437,13 +468,39 @@ impl Miner {
balance: chain.latest_balance(a),
};
let best_block_header: Header = ::util::rlp::decode(&chain.best_block_header());
transactions.into_iter()
.map(|tx| transaction_queue.add(tx, &fetch_account, origin))
.map(|tx| {
match self.engine.verify_transaction_basic(&tx, &best_block_header) {
Err(e) => {
debug!(target: "miner", "Rejected tx {:?} with invalid signature: {:?}", tx.hash(), e);
Err(e)
},
Ok(()) => {
transaction_queue.add(tx, &fetch_account, origin)
},
}
})
.collect()
}
/// Are we allowed to do a non-mandatory reseal?
fn tx_reseal_allowed(&self) -> bool { Instant::now() > *self.next_allowed_reseal.lock() }
fn from_pending_block<H, F, G>(&self, latest_block_number: BlockNumber, from_chain: F, map_block: G) -> H
where F: Fn() -> H, G: Fn(&ClosedBlock) -> H {
let sealing_work = self.sealing_work.lock();
sealing_work.queue.peek_last_ref().map_or_else(
|| from_chain(),
|b| {
if b.block().header().number() > latest_block_number {
map_block(b)
} else {
from_chain()
}
}
)
}
}
const SEALING_TIMEOUT_IN_BLOCKS : u64 = 5;
@@ -499,7 +556,7 @@ impl MinerService for Miner {
let needed_balance = t.value + t.gas * t.gas_price;
if balance < needed_balance {
// give the sender a sufficient balance
state.add_balance(&sender, &(needed_balance - balance));
state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty);
}
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
let mut ret = try!(Executive::new(&mut state, &env_info, &*self.engine, chain.vm_factory()).transact(t, options));
@@ -516,29 +573,35 @@ impl MinerService for Miner {
}
fn balance(&self, chain: &MiningBlockChainClient, address: &Address) -> U256 {
let sealing_work = self.sealing_work.lock();
sealing_work.queue.peek_last_ref().map_or_else(
self.from_pending_block(
chain.chain_info().best_block_number,
|| chain.latest_balance(address),
|b| b.block().fields().state.balance(address)
)
}
fn storage_at(&self, chain: &MiningBlockChainClient, address: &Address, position: &H256) -> H256 {
let sealing_work = self.sealing_work.lock();
sealing_work.queue.peek_last_ref().map_or_else(
self.from_pending_block(
chain.chain_info().best_block_number,
|| chain.latest_storage_at(address, position),
|b| b.block().fields().state.storage_at(address, position)
)
}
fn nonce(&self, chain: &MiningBlockChainClient, address: &Address) -> U256 {
let sealing_work = self.sealing_work.lock();
sealing_work.queue.peek_last_ref().map_or_else(|| chain.latest_nonce(address), |b| b.block().fields().state.nonce(address))
self.from_pending_block(
chain.chain_info().best_block_number,
|| chain.latest_nonce(address),
|b| b.block().fields().state.nonce(address)
)
}
fn code(&self, chain: &MiningBlockChainClient, address: &Address) -> Option<Bytes> {
let sealing_work = self.sealing_work.lock();
sealing_work.queue.peek_last_ref().map_or_else(|| chain.latest_code(address), |b| b.block().fields().state.code(address).map(|c| (*c).clone()))
self.from_pending_block(
chain.chain_info().best_block_number,
|| chain.latest_code(address),
|b| b.block().fields().state.code(address).map(|c| (*c).clone())
)
}
fn set_author(&self, author: Address) {
@@ -683,50 +746,74 @@ impl MinerService for Miner {
queue.top_transactions()
}
fn pending_transactions(&self) -> Vec<SignedTransaction> {
fn pending_transactions(&self, best_block: BlockNumber) -> Vec<SignedTransaction> {
let queue = self.transaction_queue.lock();
let sw = self.sealing_work.lock();
// TODO: should only use the sealing_work when it's current (it could be an old block)
let sealing_set = match sw.enabled {
true => sw.queue.peek_last_ref(),
false => None,
};
match (&self.options.pending_set, sealing_set) {
(&PendingSet::AlwaysQueue, _) | (&PendingSet::SealingOrElseQueue, None) => queue.top_transactions(),
(_, sealing) => sealing.map_or_else(Vec::new, |s| s.transactions().to_owned()),
match self.options.pending_set {
PendingSet::AlwaysQueue => queue.top_transactions(),
PendingSet::SealingOrElseQueue => {
self.from_pending_block(
best_block,
|| queue.top_transactions(),
|sealing| sealing.transactions().to_owned()
)
},
PendingSet::AlwaysSealing => {
self.from_pending_block(
best_block,
|| vec![],
|sealing| sealing.transactions().to_owned()
)
},
}
}
fn pending_transactions_hashes(&self) -> Vec<H256> {
fn pending_transactions_hashes(&self, best_block: BlockNumber) -> Vec<H256> {
let queue = self.transaction_queue.lock();
let sw = self.sealing_work.lock();
let sealing_set = match sw.enabled {
true => sw.queue.peek_last_ref(),
false => None,
};
match (&self.options.pending_set, sealing_set) {
(&PendingSet::AlwaysQueue, _) | (&PendingSet::SealingOrElseQueue, None) => queue.pending_hashes(),
(_, sealing) => sealing.map_or_else(Vec::new, |s| s.transactions().iter().map(|t| t.hash()).collect()),
match self.options.pending_set {
PendingSet::AlwaysQueue => queue.pending_hashes(),
PendingSet::SealingOrElseQueue => {
self.from_pending_block(
best_block,
|| queue.pending_hashes(),
|sealing| sealing.transactions().iter().map(|t| t.hash()).collect()
)
},
PendingSet::AlwaysSealing => {
self.from_pending_block(
best_block,
|| vec![],
|sealing| sealing.transactions().iter().map(|t| t.hash()).collect()
)
},
}
}
fn transaction(&self, hash: &H256) -> Option<SignedTransaction> {
fn transaction(&self, best_block: BlockNumber, hash: &H256) -> Option<SignedTransaction> {
let queue = self.transaction_queue.lock();
let sw = self.sealing_work.lock();
let sealing_set = match sw.enabled {
true => sw.queue.peek_last_ref(),
false => None,
};
match (&self.options.pending_set, sealing_set) {
(&PendingSet::AlwaysQueue, _) | (&PendingSet::SealingOrElseQueue, None) => queue.find(hash),
(_, sealing) => sealing.and_then(|s| s.transactions().iter().find(|t| &t.hash() == hash).cloned()),
match self.options.pending_set {
PendingSet::AlwaysQueue => queue.find(hash),
PendingSet::SealingOrElseQueue => {
self.from_pending_block(
best_block,
|| queue.find(hash),
|sealing| sealing.transactions().iter().find(|t| &t.hash() == hash).cloned()
)
},
PendingSet::AlwaysSealing => {
self.from_pending_block(
best_block,
|| None,
|sealing| sealing.transactions().iter().find(|t| &t.hash() == hash).cloned()
)
},
}
}
fn pending_receipt(&self, hash: &H256) -> Option<RichReceipt> {
let sealing_work = self.sealing_work.lock();
match (sealing_work.enabled, sealing_work.queue.peek_last_ref()) {
(true, Some(pending)) => {
fn pending_receipt(&self, best_block: BlockNumber, hash: &H256) -> Option<RichReceipt> {
self.from_pending_block(
best_block,
|| None,
|pending| {
let txs = pending.transactions();
txs.iter()
.map(|t| t.hash())
@@ -747,15 +834,15 @@ impl MinerService for Miner {
logs: receipt.logs.clone(),
}
})
},
_ => None
}
}
)
}
fn pending_receipts(&self) -> BTreeMap<H256, Receipt> {
let sealing_work = self.sealing_work.lock();
match (sealing_work.enabled, sealing_work.queue.peek_last_ref()) {
(true, Some(pending)) => {
fn pending_receipts(&self, best_block: BlockNumber) -> BTreeMap<H256, Receipt> {
self.from_pending_block(
best_block,
|| BTreeMap::new(),
|pending| {
let hashes = pending.transactions()
.iter()
.map(|t| t.hash());
@@ -763,9 +850,8 @@ impl MinerService for Miner {
let receipts = pending.receipts().iter().cloned();
hashes.zip(receipts).collect()
},
_ => BTreeMap::new()
}
}
)
}
fn last_nonce(&self, address: &Address) -> Option<U256> {
@@ -918,7 +1004,7 @@ impl MinerService for Miner {
mod tests {
use std::time::Duration;
use super::super::MinerService;
use super::super::{MinerService, PrioritizationStrategy};
use super::*;
use util::*;
use client::{TestBlockChainClient, EachBlockWith};
@@ -969,6 +1055,8 @@ mod tests {
reseal_min_period: Duration::from_secs(5),
tx_gas_limit: !U256::zero(),
tx_queue_size: 1024,
tx_queue_strategy: PrioritizationStrategy::GasFactorAndGasPrice,
tx_queue_gas_limit: GasLimit::None,
pending_set: PendingSet::AlwaysSealing,
work_queue_size: 5,
enable_resubmission: true,
@@ -993,22 +1081,50 @@ mod tests {
gas: U256::from(100_000),
gas_price: U256::zero(),
nonce: U256::zero(),
}.sign(keypair.secret())
}.sign(keypair.secret(), None)
};
let best_block = 0;
// when
let res = miner.import_own_transaction(&client, transaction);
// then
assert_eq!(res.unwrap(), TransactionImportResult::Current);
assert_eq!(miner.all_transactions().len(), 1);
assert_eq!(miner.pending_transactions().len(), 1);
assert_eq!(miner.pending_transactions_hashes().len(), 1);
assert_eq!(miner.pending_receipts().len(), 1);
assert_eq!(miner.pending_transactions(best_block).len(), 1);
assert_eq!(miner.pending_transactions_hashes(best_block).len(), 1);
assert_eq!(miner.pending_receipts(best_block).len(), 1);
// This method will let us know if pending block was created (before calling that method)
assert_eq!(miner.enable_and_prepare_sealing(&client), false);
}
#[test]
fn should_not_use_pending_block_if_best_block_is_higher() {
// given
let client = TestBlockChainClient::default();
let miner = miner();
let transaction = {
let keypair = KeyPair::create().unwrap();
Transaction {
action: Action::Create,
value: U256::zero(),
data: "3331600055".from_hex().unwrap(),
gas: U256::from(100_000),
gas_price: U256::zero(),
nonce: U256::zero(),
}.sign(keypair.secret(), None)
};
let best_block = 10;
// when
let res = miner.import_own_transaction(&client, transaction);
// then
assert_eq!(res.unwrap(), TransactionImportResult::Current);
assert_eq!(miner.all_transactions().len(), 1);
assert_eq!(miner.pending_transactions(best_block).len(), 0);
assert_eq!(miner.pending_transactions_hashes(best_block).len(), 0);
assert_eq!(miner.pending_receipts(best_block).len(), 0);
}
#[test]
fn should_import_external_transaction() {
// given
@@ -1023,18 +1139,18 @@ mod tests {
gas: U256::from(100_000),
gas_price: U256::zero(),
nonce: U256::zero(),
}.sign(keypair.secret())
}.sign(keypair.secret(), None)
};
let best_block = 0;
// when
let res = miner.import_external_transactions(&client, vec![transaction]).pop().unwrap();
// then
assert_eq!(res.unwrap(), TransactionImportResult::Current);
assert_eq!(miner.all_transactions().len(), 1);
assert_eq!(miner.pending_transactions_hashes().len(), 0);
assert_eq!(miner.pending_transactions().len(), 0);
assert_eq!(miner.pending_receipts().len(), 0);
assert_eq!(miner.pending_transactions_hashes(best_block).len(), 0);
assert_eq!(miner.pending_transactions(best_block).len(), 0);
assert_eq!(miner.pending_receipts(best_block).len(), 0);
// This method will let us know if pending block was created (before calling that method)
assert_eq!(miner.enable_and_prepare_sealing(&client), true);
}

View File

@@ -47,8 +47,8 @@ mod transaction_queue;
mod work_notify;
mod price_info;
pub use self::transaction_queue::{TransactionQueue, AccountDetails, TransactionOrigin};
pub use self::miner::{Miner, MinerOptions, PendingSet, GasPricer, GasPriceCalibratorOptions};
pub use self::transaction_queue::{TransactionQueue, PrioritizationStrategy, AccountDetails, TransactionOrigin};
pub use self::miner::{Miner, MinerOptions, PendingSet, GasPricer, GasPriceCalibratorOptions, GasLimit};
pub use self::external::{ExternalMiner, ExternalMinerService};
pub use client::TransactionImportResult;
@@ -56,6 +56,7 @@ use std::collections::BTreeMap;
use util::{H256, U256, Address, Bytes};
use client::{MiningBlockChainClient, Executed, CallAnalytics};
use block::ClosedBlock;
use header::BlockNumber;
use receipt::{RichReceipt, Receipt};
use error::{Error, CallError};
use transaction::SignedTransaction;
@@ -115,7 +116,7 @@ pub trait MinerService : Send + Sync {
Result<TransactionImportResult, Error>;
/// Returns hashes of transactions currently in pending
fn pending_transactions_hashes(&self) -> Vec<H256>;
fn pending_transactions_hashes(&self, best_block: BlockNumber) -> Vec<H256>;
/// Removes all transactions from the queue and restart mining operation.
fn clear_and_reset(&self, chain: &MiningBlockChainClient);
@@ -135,19 +136,19 @@ pub trait MinerService : Send + Sync {
where F: FnOnce(&ClosedBlock) -> T, Self: Sized;
/// Query pending transactions for hash.
fn transaction(&self, hash: &H256) -> Option<SignedTransaction>;
fn transaction(&self, best_block: BlockNumber, hash: &H256) -> Option<SignedTransaction>;
/// Get a list of all transactions.
fn all_transactions(&self) -> Vec<SignedTransaction>;
/// Get a list of all pending transactions.
fn pending_transactions(&self) -> Vec<SignedTransaction>;
fn pending_transactions(&self, best_block: BlockNumber) -> Vec<SignedTransaction>;
/// Get a list of all pending receipts.
fn pending_receipts(&self) -> BTreeMap<H256, Receipt>;
fn pending_receipts(&self, best_block: BlockNumber) -> BTreeMap<H256, Receipt>;
/// Get a particular reciept.
fn pending_receipt(&self, hash: &H256) -> Option<RichReceipt>;
fn pending_receipt(&self, best_block: BlockNumber, hash: &H256) -> Option<RichReceipt>;
/// Returns highest transaction nonce for given address.
fn last_nonce(&self, address: &Address) -> Option<U256>;

View File

@@ -21,55 +21,6 @@
//! transaction's nonce and next nonce expected from this sender). If nonces are equal transaction's gas price is used
//! for comparison (higher gas price = higher priority).
//!
//! # Usage Example
//!
//! ```rust
//! extern crate ethcore_util as util;
//! extern crate ethcore;
//! extern crate rustc_serialize;
//!
//! use util::crypto::KeyPair;
//! use util::hash::Address;
//! use util::numbers::{Uint, U256};
//! use ethcore::miner::{TransactionQueue, AccountDetails, TransactionOrigin};
//! use ethcore::transaction::*;
//! use rustc_serialize::hex::FromHex;
//!
//! fn main() {
//! let key = KeyPair::create().unwrap();
//! let t1 = Transaction { action: Action::Create, value: U256::from(100), data: "3331600055".from_hex().unwrap(),
//! gas: U256::from(100_000), gas_price: U256::one(), nonce: U256::from(10) };
//! let t2 = Transaction { action: Action::Create, value: U256::from(100), data: "3331600055".from_hex().unwrap(),
//! gas: U256::from(100_000), gas_price: U256::one(), nonce: U256::from(11) };
//!
//! let st1 = t1.sign(&key.secret());
//! let st2 = t2.sign(&key.secret());
//! let default_nonce = |_a: &Address| AccountDetails {
//! nonce: U256::from(10),
//! balance: U256::from(1_000_000),
//! };
//!
//! let mut txq = TransactionQueue::new();
//! txq.add(st2.clone(), &default_nonce, TransactionOrigin::External).unwrap();
//! txq.add(st1.clone(), &default_nonce, TransactionOrigin::External).unwrap();
//!
//! // Check status
//! assert_eq!(txq.status().pending, 2);
//! // Check top transactions
//! let top = txq.top_transactions();
//! assert_eq!(top.len(), 2);
//! assert_eq!(top[0], st1);
//! assert_eq!(top[1], st2);
//!
//! // And when transaction is removed (but nonce haven't changed)
//! // it will move subsequent transactions to future
//! txq.remove_invalid(&st1.hash(), &default_nonce);
//! assert_eq!(txq.status().pending, 0);
//! assert_eq!(txq.status().future, 1);
//! assert_eq!(txq.top_transactions().len(), 0);
//! }
//! ```
//!
//! # Maintaing valid state
//!
//! 1. Whenever transaction is imported to queue (to queue) all other transactions from this sender are revalidated in current. It means that they are moved to future and back again (height recalculation & gap filling).
@@ -134,9 +85,17 @@ struct TransactionOrder {
/// Gas Price of the transaction.
/// Low gas price = Low priority (processed later)
gas_price: U256,
/// Gas (limit) of the transaction.
/// Gas usage priority factor. Usage depends on strategy.
/// Represents the linear increment in required gas price for heavy transactions.
///
/// High gas limit + Low gas price = Low priority
/// High gas limit + High gas price = High priority
gas_factor: U256,
/// Gas (limit) of the transaction. Usage depends on strategy.
/// Low gas limit = High priority (processed earlier)
gas: U256,
/// Transaction ordering strategy
strategy: PrioritizationStrategy,
/// Hash to identify associated transaction
hash: H256,
/// Origin of the transaction
@@ -147,11 +106,15 @@ struct TransactionOrder {
impl TransactionOrder {
fn for_transaction(tx: &VerifiedTransaction, base_nonce: U256) -> Self {
fn for_transaction(tx: &VerifiedTransaction, base_nonce: U256, min_gas_price: U256, strategy: PrioritizationStrategy) -> Self {
let factor = (tx.transaction.gas >> 15) * min_gas_price;
TransactionOrder {
nonce_height: tx.nonce() - base_nonce,
gas_price: tx.transaction.gas_price,
gas: tx.transaction.gas,
gas_factor: factor,
strategy: strategy,
hash: tx.hash(),
origin: tx.origin,
penalties: 0,
@@ -199,18 +162,28 @@ impl Ord for TransactionOrder {
return self.origin.cmp(&b.origin);
}
// Then compare gas usage
let a_gas = self.gas;
let b_gas = b.gas;
if a_gas != b_gas {
return a_gas.cmp(&b_gas);
match self.strategy {
PrioritizationStrategy::GasAndGasPrice => {
if self.gas != b.gas {
return self.gas.cmp(&b.gas);
}
},
PrioritizationStrategy::GasFactorAndGasPrice => {
// avoiding overflows
// (gp1 - g1) > (gp2 - g2) <=>
// (gp1 + g2) > (gp2 + g1)
let f_a = self.gas_price + b.gas_factor;
let f_b = b.gas_price + self.gas_factor;
if f_a != f_b {
return f_b.cmp(&f_a);
}
},
PrioritizationStrategy::GasPriceOnly => {},
}
// Then compare gas_prices
let a_gas_price = self.gas_price;
let b_gas_price = b.gas_price;
if a_gas_price != b_gas_price {
return b_gas_price.cmp(&a_gas_price);
if self.gas_price != b.gas_price {
return b.gas_price.cmp(&self.gas_price);
}
// Compare hashes
@@ -257,6 +230,7 @@ struct TransactionSet {
by_priority: BTreeSet<TransactionOrder>,
by_address: Table<Address, U256, TransactionOrder>,
limit: usize,
gas_limit: U256,
}
impl TransactionSet {
@@ -277,14 +251,20 @@ impl TransactionSet {
/// It drops transactions from this set but also removes associated `VerifiedTransaction`.
/// Returns addresses and lowest nonces of transactions removed because of limit.
fn enforce_limit(&mut self, by_hash: &mut HashMap<H256, VerifiedTransaction>) -> Option<HashMap<Address, U256>> {
let len = self.by_priority.len();
if len <= self.limit {
return None;
}
let mut count = 0;
let mut gas: U256 = 0.into();
let to_drop : Vec<(Address, U256)> = {
self.by_priority
.iter()
.skip(self.limit)
.filter(|order| {
count = count + 1;
let r = gas.overflowing_add(order.gas);
if r.1 { return false }
gas = r.0;
// Own and retracted transactions are allowed to go above all limits.
order.origin != TransactionOrigin::Local && order.origin != TransactionOrigin::RetractedBlock &&
(gas > self.gas_limit || count > self.limit)
})
.map(|order| by_hash.get(&order.hash)
.expect("All transactions in `self.by_priority` and `self.by_address` are kept in sync with `by_hash`."))
.map(|tx| (tx.sender(), tx.nonce()))
@@ -295,6 +275,7 @@ impl TransactionSet {
.fold(HashMap::new(), |mut removed, (sender, nonce)| {
let order = self.drop(&sender, &nonce)
.expect("Transaction has just been found in `by_priority`; so it is in `by_address` also.");
trace!(target: "txqueue", "Dropped out of limit transaction: {:?}", order.hash);
by_hash.remove(&order.hash)
.expect("Hash found in `by_priorty` matches the one dropped; so it is included in `by_hash`");
@@ -350,8 +331,32 @@ pub struct AccountDetails {
/// Transactions with `gas > (gas_limit + gas_limit * Factor(in percents))` are not imported to the queue.
const GAS_LIMIT_HYSTERESIS: usize = 10; // (100/GAS_LIMIT_HYSTERESIS) %
/// Describes the strategy used to prioritize transactions in the queue.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum PrioritizationStrategy {
/// Use only gas price. Disregards the actual computation cost of the transaction.
/// i.e. Higher gas price = Higher priority
GasPriceOnly,
/// Use gas limit and then gas price.
/// i.e. Higher gas limit = Lower priority
GasAndGasPrice,
/// Calculate and use priority based on gas and gas price.
/// PRIORITY = GAS_PRICE - GAS/2^15 * MIN_GAS_PRICE
///
/// Rationale:
/// Heavy transactions are paying linear cost (GAS * GAS_PRICE)
/// while the computation might be more expensive.
///
/// i.e.
/// 1M gas tx with `gas_price=30*min` has the same priority
/// as 32k gas tx with `gas_price=min`
GasFactorAndGasPrice,
}
/// `TransactionQueue` implementation
pub struct TransactionQueue {
/// Prioritization strategy for this queue
strategy: PrioritizationStrategy,
/// Gas Price threshold for transactions that can be imported to this queue (defaults to 0)
minimal_gas_price: U256,
/// The maximum amount of gas any individual transaction may use.
@@ -370,31 +375,34 @@ pub struct TransactionQueue {
impl Default for TransactionQueue {
fn default() -> Self {
TransactionQueue::new()
TransactionQueue::new(PrioritizationStrategy::GasPriceOnly)
}
}
impl TransactionQueue {
/// Creates new instance of this Queue
pub fn new() -> Self {
Self::with_limits(1024, !U256::zero())
pub fn new(strategy: PrioritizationStrategy) -> Self {
Self::with_limits(strategy, 1024, !U256::zero(), !U256::zero())
}
/// Create new instance of this Queue with specified limits
pub fn with_limits(limit: usize, tx_gas_limit: U256) -> Self {
pub fn with_limits(strategy: PrioritizationStrategy, limit: usize, gas_limit: U256, tx_gas_limit: U256) -> Self {
let current = TransactionSet {
by_priority: BTreeSet::new(),
by_address: Table::new(),
limit: limit,
gas_limit: gas_limit,
};
let future = TransactionSet {
by_priority: BTreeSet::new(),
by_address: Table::new(),
limit: limit,
gas_limit: gas_limit,
};
TransactionQueue {
strategy: strategy,
minimal_gas_price: U256::zero(),
tx_gas_limit: tx_gas_limit,
gas_limit: !U256::zero(),
@@ -441,6 +449,13 @@ impl TransactionQueue {
};
}
/// Sets new total gas limit.
pub fn set_total_gas_limit(&mut self, gas_limit: U256) {
self.future.gas_limit = gas_limit;
self.current.gas_limit = gas_limit;
self.future.enforce_limit(&mut self.by_hash);
}
/// Set the new limit for the amount of gas any individual transaction may have.
/// Any transaction already imported to the queue is not affected.
pub fn set_tx_gas_limit(&mut self, limit: U256) {
@@ -560,7 +575,7 @@ impl TransactionQueue {
};
for k in nonces_from_sender {
let order = self.future.drop(&sender, &k).unwrap();
self.current.insert(sender, k, order.penalize());
self.future.insert(sender, k, order.penalize());
}
}
@@ -584,6 +599,8 @@ impl TransactionQueue {
let nonce = transaction.nonce();
let current_nonce = fetch_account(&sender).nonce;
trace!(target: "txqueue", "Removing invalid transaction: {:?}", transaction.hash());
// Remove from future
let order = self.future.drop(&sender, &nonce);
if order.is_some() {
@@ -658,6 +675,15 @@ impl TransactionQueue {
.collect()
}
#[cfg(test)]
fn future_transactions(&self) -> Vec<SignedTransaction> {
self.future.by_priority
.iter()
.map(|t| self.by_hash.get(&t.hash).expect("All transactions in `current` and `future` are always included in `by_hash`"))
.map(|t| t.transaction.clone())
.collect()
}
/// Returns hashes of all transactions from current, ordered by priority.
pub fn pending_hashes(&self) -> Vec<H256> {
self.current.by_priority
@@ -736,10 +762,21 @@ impl TransactionQueue {
return Err(TransactionError::AlreadyImported);
}
let min_gas_price = (self.minimal_gas_price, self.strategy);
let address = tx.sender();
let nonce = tx.nonce();
let hash = tx.hash();
{
// Rough size sanity check
let gas = &tx.transaction.gas;
if U256::from(tx.transaction.data.len()) > *gas {
// Droping transaction
trace!(target: "txqueue", "Dropping oversized transaction: {:?} (gas: {} < size {})", hash, gas, tx.transaction.data.len());
return Err(TransactionError::LimitReached);
}
}
// The transaction might be old, let's check that.
// This has to be the first test, otherwise calculating
// nonce height would result in overflow.
@@ -763,7 +800,7 @@ impl TransactionQueue {
if nonce > next_nonce {
// We have a gap - put to future.
// Insert transaction (or replace old one with lower gas price)
try!(check_too_cheap(Self::replace_transaction(tx, state_nonce, &mut self.future, &mut self.by_hash)));
try!(check_too_cheap(Self::replace_transaction(tx, state_nonce, min_gas_price, &mut self.future, &mut self.by_hash)));
// Enforce limit in Future
let removed = self.future.enforce_limit(&mut self.by_hash);
// Return an error if this transaction was not imported because of limit.
@@ -779,7 +816,7 @@ impl TransactionQueue {
self.move_matching_future_to_current(address, nonce + U256::one(), state_nonce);
// Replace transaction if any
try!(check_too_cheap(Self::replace_transaction(tx, state_nonce, &mut self.current, &mut self.by_hash)));
try!(check_too_cheap(Self::replace_transaction(tx, state_nonce, min_gas_price, &mut self.current, &mut self.by_hash)));
// Keep track of highest nonce stored in current
let new_max = self.last_nonces.get(&address).map_or(nonce, |n| cmp::max(nonce, *n));
self.last_nonces.insert(address, new_max);
@@ -815,8 +852,8 @@ impl TransactionQueue {
///
/// Returns `true` if transaction actually got to the queue (`false` if there was already a transaction with higher
/// gas_price)
fn replace_transaction(tx: VerifiedTransaction, base_nonce: U256, set: &mut TransactionSet, by_hash: &mut HashMap<H256, VerifiedTransaction>) -> bool {
let order = TransactionOrder::for_transaction(&tx, base_nonce);
fn replace_transaction(tx: VerifiedTransaction, base_nonce: U256, min_gas_price: (U256, PrioritizationStrategy), set: &mut TransactionSet, by_hash: &mut HashMap<H256, VerifiedTransaction>) -> bool {
let order = TransactionOrder::for_transaction(&tx, base_nonce, min_gas_price.0, min_gas_price.1);
let hash = tx.hash();
let address = tx.sender();
let nonce = tx.nonce();
@@ -837,12 +874,14 @@ impl TransactionQueue {
let old_fee = old.gas_price;
let new_fee = order.gas_price;
if old_fee.cmp(&new_fee) == Ordering::Greater {
trace!(target: "txqueue", "Didn't insert transaction because gas price was too low: {:?} ({:?} stays in the queue)", order.hash, old.hash);
// Put back old transaction since it has greater priority (higher gas_price)
set.insert(address, nonce, old);
// and remove new one
by_hash.remove(&order.hash).expect("The hash has been just inserted and no other line is altering `by_hash`.");
false
} else {
trace!(target: "txqueue", "Replaced transaction: {:?} with transaction with higher gas price: {:?}", old.hash, order.hash);
// Make sure we remove old transaction entirely
by_hash.remove(&old.hash).expect("The hash is coming from `future` so it has to be in `by_hash`.");
true
@@ -918,7 +957,7 @@ mod test {
fn new_tx_with_gas(gas: U256, gas_price: U256) -> SignedTransaction {
let keypair = KeyPair::create().unwrap();
new_unsigned_tx_with_gas(default_nonce_val(), gas, gas_price).sign(keypair.secret())
new_unsigned_tx_with_gas(default_nonce_val(), gas, gas_price).sign(keypair.secret(), None)
}
fn new_tx() -> SignedTransaction {
@@ -941,7 +980,7 @@ mod test {
let mut tx2 = new_unsigned_tx(nonce);
tx2.gas_price = 2.into();
(tx.sign(secret), tx2.sign(secret))
(tx.sign(secret, None), tx2.sign(secret, None))
}
fn new_txs(second_nonce: U256) -> (SignedTransaction, SignedTransaction) {
@@ -956,8 +995,7 @@ mod test {
tx.gas_price = tx.gas_price + gas_price;
let mut tx2 = new_unsigned_tx(nonce + 1.into());
tx2.gas_price = tx2.gas_price + gas_price;
(tx.sign(secret), tx2.sign(secret))
(tx.sign(secret, None), tx2.sign(secret, None))
}
fn new_txs_with_gas_price_diff(second_nonce: U256, gas_price: U256) -> (SignedTransaction, SignedTransaction) {
@@ -968,7 +1006,7 @@ mod test {
let mut tx2 = new_unsigned_tx(nonce + second_nonce);
tx2.gas_price = tx2.gas_price + gas_price;
(tx.sign(secret), tx2.sign(secret))
(tx.sign(secret, None), tx2.sign(secret, None))
}
#[test]
@@ -982,13 +1020,18 @@ mod test {
assert_eq!(TransactionOrigin::External.cmp(&TransactionOrigin::RetractedBlock), Ordering::Greater);
}
fn transaction_order(tx: &VerifiedTransaction, nonce: U256) -> TransactionOrder {
TransactionOrder::for_transaction(tx, nonce, 0.into(), PrioritizationStrategy::GasPriceOnly)
}
#[test]
fn should_create_transaction_set() {
// given
let mut set = TransactionSet {
by_priority: BTreeSet::new(),
by_address: Table::new(),
limit: 1
limit: 1,
gas_limit: !U256::zero(),
};
let (tx1, tx2) = new_txs(U256::from(1));
let tx1 = VerifiedTransaction::new(tx1, TransactionOrigin::External).unwrap();
@@ -1002,9 +1045,9 @@ mod test {
x
};
// Insert both transactions
let order1 = TransactionOrder::for_transaction(&tx1, U256::zero());
let order1 = transaction_order(&tx1, U256::zero());
set.insert(tx1.sender(), tx1.nonce(), order1.clone());
let order2 = TransactionOrder::for_transaction(&tx2, U256::zero());
let order2 = transaction_order(&tx2, U256::zero());
set.insert(tx2.sender(), tx2.nonce(), order2.clone());
assert_eq!(set.by_priority.len(), 2);
assert_eq!(set.by_address.len(), 2);
@@ -1027,7 +1070,8 @@ mod test {
let mut set = TransactionSet {
by_priority: BTreeSet::new(),
by_address: Table::new(),
limit: 1
limit: 1,
gas_limit: !U256::zero(),
};
// Create two transactions with same nonce
// (same hash)
@@ -1043,12 +1087,12 @@ mod test {
x
};
// Insert both transactions
let order1 = TransactionOrder::for_transaction(&tx1, U256::zero());
let order1 = transaction_order(&tx1, U256::zero());
set.insert(tx1.sender(), tx1.nonce(), order1.clone());
assert_eq!(set.by_priority.len(), 1);
assert_eq!(set.by_address.len(), 1);
// Two different orders (imagine nonce changed in the meantime)
let order2 = TransactionOrder::for_transaction(&tx2, U256::one());
let order2 = transaction_order(&tx2, U256::one());
set.insert(tx2.sender(), tx2.nonce(), order2.clone());
assert_eq!(set.by_priority.len(), 1);
assert_eq!(set.by_address.len(), 1);
@@ -1063,7 +1107,7 @@ mod test {
#[test]
fn should_handle_same_transaction_imported_twice_with_different_state_nonces() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let (tx, tx2) = new_similar_txs();
let prev_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce - U256::one(), balance:
!U256::zero() };
@@ -1088,7 +1132,7 @@ mod test {
#[test]
fn should_move_all_transactions_from_future() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let (tx, tx2) = new_txs_with_gas_price_diff(1.into(), 1.into());
let prev_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce - U256::one(), balance:
!U256::zero() };
@@ -1114,7 +1158,7 @@ mod test {
#[test]
fn should_import_tx() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let tx = new_tx();
// when
@@ -1129,7 +1173,7 @@ mod test {
#[test]
fn should_order_by_gas() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::new(PrioritizationStrategy::GasAndGasPrice);
let tx1 = new_tx_with_gas(50000.into(), 40.into());
let tx2 = new_tx_with_gas(40000.into(), 30.into());
let tx3 = new_tx_with_gas(30000.into(), 10.into());
@@ -1159,10 +1203,45 @@ mod test {
assert_eq!(txq.top_transactions()[2].gas_price, 20.into());
}
#[test]
fn should_order_by_gas_factor() {
// given
let mut txq = TransactionQueue::new(PrioritizationStrategy::GasFactorAndGasPrice);
let tx1 = new_tx_with_gas(150_000.into(), 40.into());
let tx2 = new_tx_with_gas(40_000.into(), 16.into());
let tx3 = new_tx_with_gas(30_000.into(), 15.into());
let tx4 = new_tx_with_gas(150_000.into(), 62.into());
txq.set_minimal_gas_price(15.into());
// when
let res1 = txq.add(tx1, &default_nonce, TransactionOrigin::External);
let res2 = txq.add(tx2, &default_nonce, TransactionOrigin::External);
let res3 = txq.add(tx3, &default_nonce, TransactionOrigin::External);
let res4 = txq.add(tx4, &default_nonce, TransactionOrigin::External);
// then
assert_eq!(res1.unwrap(), TransactionImportResult::Current);
assert_eq!(res2.unwrap(), TransactionImportResult::Current);
assert_eq!(res3.unwrap(), TransactionImportResult::Current);
assert_eq!(res4.unwrap(), TransactionImportResult::Current);
let stats = txq.status();
assert_eq!(stats.pending, 4);
println!("{:?}", txq.top_transactions());
assert_eq!(txq.top_transactions()[0].gas, 30_000.into());
assert_eq!(txq.top_transactions()[1].gas, 150_000.into());
assert_eq!(txq.top_transactions()[2].gas, 40_000.into());
assert_eq!(txq.top_transactions()[3].gas, 150_000.into());
assert_eq!(txq.top_transactions()[0].gas_price, 15.into());
assert_eq!(txq.top_transactions()[1].gas_price, 62.into());
assert_eq!(txq.top_transactions()[2].gas_price, 16.into());
assert_eq!(txq.top_transactions()[3].gas_price, 40.into());
}
#[test]
fn gas_limit_should_never_overflow() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
txq.set_gas_limit(U256::zero());
assert_eq!(txq.gas_limit, U256::zero());
@@ -1176,7 +1255,7 @@ mod test {
#[test]
fn should_not_import_transaction_above_gas_limit() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let tx = new_tx();
let gas = tx.gas;
let limit = gas / U256::from(2);
@@ -1198,7 +1277,7 @@ mod test {
#[test]
fn should_drop_transactions_from_senders_without_balance() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let tx = new_tx();
let account = |a: &Address| AccountDetails {
nonce: default_nonce(a).nonce,
@@ -1221,7 +1300,7 @@ mod test {
#[test]
fn should_not_import_transaction_below_min_gas_price_threshold_if_external() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let tx = new_tx();
txq.set_minimal_gas_price(tx.gas_price + U256::one());
@@ -1241,7 +1320,7 @@ mod test {
#[test]
fn should_import_transaction_below_min_gas_price_threshold_if_local() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let tx = new_tx();
txq.set_minimal_gas_price(tx.gas_price + U256::one());
@@ -1258,7 +1337,7 @@ mod test {
#[test]
fn should_reject_incorrectly_signed_transaction() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let tx = new_unsigned_tx(U256::from(123));
let stx = {
let mut s = RlpStream::new_list(9);
@@ -1283,7 +1362,7 @@ mod test {
#[test]
fn should_import_txs_from_same_sender() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let (tx, tx2) = new_txs(U256::from(1));
@@ -1301,7 +1380,7 @@ mod test {
#[test]
fn should_prioritize_local_transactions_within_same_nonce_height() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let tx = new_tx();
// the second one has same nonce but higher `gas_price`
let (_, tx2) = new_similar_txs();
@@ -1322,7 +1401,7 @@ mod test {
#[test]
fn should_prioritize_reimported_transactions_within_same_nonce_height() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let tx = new_tx();
// the second one has same nonce but higher `gas_price`
let (_, tx2) = new_similar_txs();
@@ -1343,7 +1422,7 @@ mod test {
#[test]
fn should_not_prioritize_local_transactions_with_different_nonce_height() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let (tx, tx2) = new_txs(U256::from(1));
// when
@@ -1357,10 +1436,40 @@ mod test {
assert_eq!(top.len(), 2);
}
#[test]
fn should_penalize_transactions_from_sender_in_future() {
// given
let prev_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce - U256::one(), balance: !U256::zero() };
let mut txq = TransactionQueue::default();
// txa, txb - slightly bigger gas price to have consistent ordering
let (txa, txb) = new_txs(U256::from(1));
let (tx1, tx2) = new_txs_with_higher_gas_price(U256::from(3));
// insert everything
txq.add(txa.clone(), &prev_nonce, TransactionOrigin::External).unwrap();
txq.add(txb.clone(), &prev_nonce, TransactionOrigin::External).unwrap();
txq.add(tx1.clone(), &prev_nonce, TransactionOrigin::External).unwrap();
txq.add(tx2.clone(), &prev_nonce, TransactionOrigin::External).unwrap();
assert_eq!(txq.status().future, 4);
// when
txq.penalize(&tx1.hash());
// then
let top = txq.future_transactions();
assert_eq!(top[0], txa);
assert_eq!(top[1], txb);
assert_eq!(top[2], tx1);
assert_eq!(top[3], tx2);
assert_eq!(top.len(), 4);
}
#[test]
fn should_penalize_transactions_from_sender() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
// txa, txb - slightly bigger gas price to have consistent ordering
let (txa, txb) = new_txs(U256::from(1));
let (tx1, tx2) = new_txs_with_higher_gas_price(U256::from(3));
@@ -1393,7 +1502,7 @@ mod test {
#[test]
fn should_return_pending_hashes() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let (tx, tx2) = new_txs(U256::from(1));
@@ -1411,7 +1520,7 @@ mod test {
#[test]
fn should_put_transaction_to_futures_if_gap_detected() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let (tx, tx2) = new_txs(U256::from(2));
@@ -1437,7 +1546,7 @@ mod test {
!U256::zero() };
let next2_nonce = default_nonce_val() + U256::from(3);
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let (tx, tx2) = new_txs(U256::from(1));
txq.add(tx.clone(), &prev_nonce, TransactionOrigin::External).unwrap();
@@ -1456,12 +1565,12 @@ mod test {
#[test]
fn should_move_transactions_if_gap_filled() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let kp = KeyPair::create().unwrap();
let secret = kp.secret();
let tx = new_unsigned_tx(U256::from(123)).sign(secret);
let tx1 = new_unsigned_tx(U256::from(124)).sign(secret);
let tx2 = new_unsigned_tx(U256::from(125)).sign(secret);
let tx = new_unsigned_tx(U256::from(123)).sign(secret, None);
let tx1 = new_unsigned_tx(U256::from(124)).sign(secret, None);
let tx2 = new_unsigned_tx(U256::from(125)).sign(secret, None);
txq.add(tx, &default_nonce, TransactionOrigin::External).unwrap();
assert_eq!(txq.status().pending, 1);
@@ -1480,7 +1589,7 @@ mod test {
#[test]
fn should_remove_transaction() {
// given
let mut txq2 = TransactionQueue::new();
let mut txq2 = TransactionQueue::default();
let (tx, tx2) = new_txs(U256::from(3));
txq2.add(tx.clone(), &default_nonce, TransactionOrigin::External).unwrap();
txq2.add(tx2.clone(), &default_nonce, TransactionOrigin::External).unwrap();
@@ -1501,7 +1610,7 @@ mod test {
#[test]
fn should_move_transactions_to_future_if_gap_introduced() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let (tx, tx2) = new_txs(U256::from(1));
let tx3 = new_tx();
txq.add(tx2.clone(), &default_nonce, TransactionOrigin::External).unwrap();
@@ -1522,7 +1631,7 @@ mod test {
#[test]
fn should_clear_queue() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let (tx, tx2) = new_txs(U256::one());
// add
@@ -1542,7 +1651,7 @@ mod test {
#[test]
fn should_drop_old_transactions_when_hitting_the_limit() {
// given
let mut txq = TransactionQueue::with_limits(1, !U256::zero());
let mut txq = TransactionQueue::with_limits(PrioritizationStrategy::GasPriceOnly, 1, !U256::zero(), !U256::zero());
let (tx, tx2) = new_txs(U256::one());
let sender = tx.sender().unwrap();
let nonce = tx.nonce;
@@ -1564,7 +1673,7 @@ mod test {
#[test]
fn should_return_correct_nonces_when_dropped_because_of_limit() {
// given
let mut txq = TransactionQueue::with_limits(2, !U256::zero());
let mut txq = TransactionQueue::with_limits(PrioritizationStrategy::GasPriceOnly, 2, !U256::zero(), !U256::zero());
let tx = new_tx();
let (tx1, tx2) = new_txs(U256::one());
let sender = tx1.sender().unwrap();
@@ -1585,7 +1694,7 @@ mod test {
#[test]
fn should_limit_future_transactions() {
let mut txq = TransactionQueue::with_limits(1, !U256::zero());
let mut txq = TransactionQueue::with_limits(PrioritizationStrategy::GasPriceOnly, 1, !U256::zero(), !U256::zero());
txq.current.set_limit(10);
let (tx1, tx2) = new_txs_with_gas_price_diff(U256::from(4), U256::from(1));
let (tx3, tx4) = new_txs_with_gas_price_diff(U256::from(4), U256::from(2));
@@ -1602,9 +1711,37 @@ mod test {
assert_eq!(txq.status().future, 1);
}
#[test]
fn should_limit_by_gas() {
let mut txq = TransactionQueue::with_limits(PrioritizationStrategy::GasPriceOnly, 100, default_gas_val() * U256::from(2), !U256::zero());
let (tx1, tx2) = new_txs_with_gas_price_diff(U256::from(1), U256::from(1));
let (tx3, tx4) = new_txs_with_gas_price_diff(U256::from(1), U256::from(2));
txq.add(tx1.clone(), &default_nonce, TransactionOrigin::External).ok();
txq.add(tx2.clone(), &default_nonce, TransactionOrigin::External).ok();
txq.add(tx3.clone(), &default_nonce, TransactionOrigin::External).ok();
txq.add(tx4.clone(), &default_nonce, TransactionOrigin::External).ok();
assert_eq!(txq.status().pending, 2);
}
#[test]
fn should_keep_own_transactions_above_gas_limit() {
let mut txq = TransactionQueue::with_limits(PrioritizationStrategy::GasPriceOnly, 100, default_gas_val() * U256::from(2), !U256::zero());
let (tx1, tx2) = new_txs_with_gas_price_diff(U256::from(1), U256::from(1));
let (tx3, tx4) = new_txs_with_gas_price_diff(U256::from(1), U256::from(2));
let (tx5, tx6) = new_txs_with_gas_price_diff(U256::from(1), U256::from(2));
txq.add(tx1.clone(), &default_nonce, TransactionOrigin::Local).unwrap();
txq.add(tx2.clone(), &default_nonce, TransactionOrigin::Local).unwrap();
txq.add(tx5.clone(), &default_nonce, TransactionOrigin::External).unwrap();
// Not accepted because of limit
txq.add(tx6.clone(), &default_nonce, TransactionOrigin::External).unwrap_err();
txq.add(tx3.clone(), &default_nonce, TransactionOrigin::Local).unwrap();
txq.add(tx4.clone(), &default_nonce, TransactionOrigin::Local).unwrap();
assert_eq!(txq.status().pending, 4);
}
#[test]
fn should_drop_transactions_with_old_nonces() {
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let tx = new_tx();
let last_nonce = tx.nonce + U256::one();
let fetch_last_nonce = |_a: &Address| AccountDetails{ nonce: last_nonce, balance: !U256::zero() };
@@ -1624,7 +1761,7 @@ mod test {
// given
let nonce = |a: &Address| AccountDetails { nonce: default_nonce(a).nonce + U256::one(),
balance: !U256::zero() };
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let (_tx1, tx2) = new_txs(U256::from(1));
txq.add(tx2.clone(), &default_nonce, TransactionOrigin::External).unwrap();
assert_eq!(txq.status().future, 1);
@@ -1643,7 +1780,7 @@ mod test {
#[test]
fn should_accept_same_transaction_twice_if_removed() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let (tx1, tx2) = new_txs(U256::from(1));
txq.add(tx1.clone(), &default_nonce, TransactionOrigin::External).unwrap();
txq.add(tx2.clone(), &default_nonce, TransactionOrigin::External).unwrap();
@@ -1664,7 +1801,7 @@ mod test {
#[test]
fn should_not_move_to_future_if_state_nonce_is_higher() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let (tx, tx2) = new_txs(U256::from(1));
let tx3 = new_tx();
txq.add(tx2.clone(), &default_nonce, TransactionOrigin::External).unwrap();
@@ -1687,13 +1824,13 @@ mod test {
fn should_replace_same_transaction_when_has_higher_fee() {
init_log();
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let keypair = KeyPair::create().unwrap();
let tx = new_unsigned_tx(U256::from(123)).sign(keypair.secret());
let tx = new_unsigned_tx(U256::from(123)).sign(keypair.secret(), None);
let tx2 = {
let mut tx2 = (*tx).clone();
tx2.gas_price = U256::from(200);
tx2.sign(keypair.secret())
tx2.sign(keypair.secret(), None)
};
// when
@@ -1710,18 +1847,18 @@ mod test {
#[test]
fn should_replace_same_transaction_when_importing_to_futures() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let keypair = KeyPair::create().unwrap();
let tx0 = new_unsigned_tx(U256::from(123)).sign(keypair.secret());
let tx0 = new_unsigned_tx(U256::from(123)).sign(keypair.secret(), None);
let tx1 = {
let mut tx1 = (*tx0).clone();
tx1.nonce = U256::from(124);
tx1.sign(keypair.secret())
tx1.sign(keypair.secret(), None)
};
let tx2 = {
let mut tx2 = (*tx1).clone();
tx2.gas_price = U256::from(200);
tx2.sign(keypair.secret())
tx2.sign(keypair.secret(), None)
};
// when
@@ -1744,7 +1881,7 @@ mod test {
!U256::zero() };
let next_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce + U256::one(), balance:
!U256::zero() };
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let (tx1, tx2) = new_txs(U256::one());
txq.add(tx1.clone(), &previous_nonce, TransactionOrigin::External).unwrap();
txq.add(tx2, &previous_nonce, TransactionOrigin::External).unwrap();
@@ -1762,7 +1899,7 @@ mod test {
#[test]
fn should_return_none_when_transaction_from_given_address_does_not_exist() {
// given
let txq = TransactionQueue::new();
let txq = TransactionQueue::default();
// then
assert_eq!(txq.last_nonce(&Address::default()), None);
@@ -1771,7 +1908,7 @@ mod test {
#[test]
fn should_return_correct_nonce_when_transactions_from_given_address_exist() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let tx = new_tx();
let from = tx.sender().unwrap();
let nonce = tx.nonce;
@@ -1787,7 +1924,7 @@ mod test {
#[test]
fn should_remove_old_transaction_even_if_newer_transaction_was_not_known() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let (tx1, tx2) = new_txs(U256::one());
let (nonce1, nonce2) = (tx1.nonce, tx2.nonce);
let details1 = |_a: &Address| AccountDetails { nonce: nonce1, balance: !U256::zero() };
@@ -1805,7 +1942,7 @@ mod test {
#[test]
fn should_return_valid_last_nonce_after_remove_all() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let (tx1, tx2) = new_txs(U256::from(4));
let sender = tx1.sender().unwrap();
let (nonce1, nonce2) = (tx1.nonce, tx2.nonce);
@@ -1829,7 +1966,7 @@ mod test {
#[test]
fn should_return_true_if_there_is_local_transaction_pending() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let (tx1, tx2) = new_txs(U256::from(1));
assert_eq!(txq.has_local_pending_transactions(), false);
@@ -1845,7 +1982,7 @@ mod test {
#[test]
fn should_keep_right_order_in_future() {
// given
let mut txq = TransactionQueue::with_limits(1, !U256::zero());
let mut txq = TransactionQueue::with_limits(PrioritizationStrategy::GasPriceOnly, 1, !U256::zero(), !U256::zero());
let (tx1, tx2) = new_txs(U256::from(1));
let prev_nonce = |a: &Address| AccountDetails { nonce: default_nonce(a).nonce - U256::one(), balance:
default_nonce(a).balance };
@@ -1862,7 +1999,7 @@ mod test {
#[test]
fn should_return_correct_last_nonce() {
// given
let mut txq = TransactionQueue::new();
let mut txq = TransactionQueue::default();
let (tx1, tx2, tx2_2, tx3) = {
let keypair = KeyPair::create().unwrap();
let secret = &keypair.secret();
@@ -1874,7 +2011,7 @@ mod test {
let tx3 = new_unsigned_tx(nonce + 2.into());
(tx.sign(secret), tx2.sign(secret), tx2_2.sign(secret), tx3.sign(secret))
(tx.sign(secret, None), tx2.sign(secret, None), tx2_2.sign(secret, None), tx3.sign(secret, None))
};
let sender = tx1.sender().unwrap();
txq.add(tx1, &default_nonce, TransactionOrigin::Local).unwrap();

View File

@@ -27,7 +27,7 @@ use ids::BlockID;
use views::BlockView;
use super::state_db::StateDB;
use util::{Bytes, Hashable, HashDB, snappy, TrieDB, TrieDBMut, TrieMut, BytesConvertable};
use util::{Bytes, Hashable, HashDB, snappy, TrieDB, TrieDBMut, TrieMut, BytesConvertable, U256, Uint};
use util::Mutex;
use util::hash::{FixedHash, H256};
use util::journaldb::{self, Algorithm, JournalDB};
@@ -39,6 +39,8 @@ use self::account::Account;
use self::block::AbridgedBlock;
use self::io::SnapshotWriter;
use super::account::Account as StateAccount;
use crossbeam::{scope, ScopedJoinHandle};
use rand::{Rng, OsRng};
@@ -417,6 +419,7 @@ impl StateRebuilder {
/// Feed an uncompressed state chunk into the rebuilder.
pub fn feed(&mut self, chunk: &[u8]) -> Result<(), ::error::Error> {
let rlp = UntrustedRlp::new(chunk);
let empty_rlp = StateAccount::new_basic(U256::zero(), U256::zero()).rlp();
let account_fat_rlps: Vec<_> = rlp.iter().map(|r| r.as_raw()).collect();
let mut pairs = Vec::with_capacity(rlp.item_count());
let backing = self.db.backing().clone();
@@ -464,7 +467,9 @@ impl StateRebuilder {
};
for (hash, thin_rlp) in pairs {
bloom.set(hash.as_slice());
if &thin_rlp[..] != &empty_rlp[..] {
bloom.set(hash.as_slice());
}
try!(account_trie.insert(&hash, &thin_rlp));
}
}

View File

@@ -37,7 +37,9 @@ pub struct CommonParams {
/// Maximum size of extra data.
pub maximum_extra_data_size: usize,
/// Network id.
pub network_id: U256,
pub network_id: usize,
/// Main subprotocol name.
pub subprotocol_name: String,
/// Minimum gas limit.
pub min_gas_limit: U256,
/// Fork block to check.
@@ -50,6 +52,7 @@ impl From<ethjson::spec::Params> for CommonParams {
account_start_nonce: p.account_start_nonce.into(),
maximum_extra_data_size: p.maximum_extra_data_size.into(),
network_id: p.network_id.into(),
subprotocol_name: p.subprotocol_name.unwrap_or_else(|| "eth".to_owned()),
min_gas_limit: p.min_gas_limit.into(),
fork_block: if let (Some(n), Some(h)) = (p.fork_block, p.fork_hash) { Some((n.into(), h.into())) } else { None },
}
@@ -155,7 +158,7 @@ impl Spec {
pub fn nodes(&self) -> &[String] { &self.nodes }
/// Get the configured Network ID.
pub fn network_id(&self) -> U256 { self.params.network_id }
pub fn network_id(&self) -> usize { self.params.network_id }
/// Get the configured network fork block.
pub fn fork_block(&self) -> Option<(BlockNumber, H256)> { self.params.fork_block }
@@ -240,7 +243,7 @@ impl Spec {
}
}
for (address, account) in self.genesis_state.get().iter() {
db.note_account_bloom(address);
db.note_non_null_account(address);
account.insert_additional(&mut AccountDBMut::new(db.as_hashdb_mut(), address));
}
assert!(db.as_hashdb().contains(&self.state_root()));

View File

@@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::cell::{RefCell, RefMut};
use std::collections::hash_map::Entry;
use common::*;
use engines::Engine;
use executive::{Executive, TransactOptions};
@@ -38,42 +38,93 @@ pub struct ApplyOutcome {
/// Result type for the execution ("application") of a transaction.
pub type ApplyResult = Result<ApplyOutcome, Error>;
#[derive(Debug)]
enum AccountEntry {
/// Contains account data.
Cached(Account),
/// Account has been deleted.
Killed,
/// Account does not exist.
Missing,
#[derive(Eq, PartialEq, Clone, Copy, Debug)]
/// Account modification state. Used to check if the account was
/// Modified in between commits and overall.
enum AccountState {
/// Account was loaded from disk and never modified in this state object.
CleanFresh,
/// Account was loaded from the global cache and never modified.
CleanCached,
/// Account has been modified and is not committed to the trie yet.
/// This is set if any of the account data is changed, including
/// storage and code.
Dirty,
/// Account was modified and committed to the trie.
Committed,
}
#[derive(Debug)]
/// In-memory copy of the account data. Holds the optional account
/// and the modification status.
/// Account entry can contain existing (`Some`) or non-existing
/// account (`None`)
struct AccountEntry {
account: Option<Account>,
state: AccountState,
}
// Account cache item. Contains account data and
// modification state
impl AccountEntry {
fn is_dirty(&self) -> bool {
match *self {
AccountEntry::Cached(ref a) => a.is_dirty(),
AccountEntry::Killed => true,
AccountEntry::Missing => false,
}
self.state == AccountState::Dirty
}
/// Clone dirty data into new `AccountEntry`.
/// Clone dirty data into new `AccountEntry`. This includes
/// basic account data and modified storage keys.
/// Returns None if clean.
fn clone_dirty(&self) -> Option<AccountEntry> {
match *self {
AccountEntry::Cached(ref acc) if acc.is_dirty() => Some(AccountEntry::Cached(acc.clone_dirty())),
AccountEntry::Killed => Some(AccountEntry::Killed),
_ => None,
fn clone_if_dirty(&self) -> Option<AccountEntry> {
match self.is_dirty() {
true => Some(self.clone_dirty()),
false => None,
}
}
/// Clone account entry data that needs to be saved in the snapshot.
/// This includes basic account information and all locally cached storage keys
fn clone_for_snapshot(&self) -> AccountEntry {
match *self {
AccountEntry::Cached(ref acc) => AccountEntry::Cached(acc.clone_all()),
AccountEntry::Killed => AccountEntry::Killed,
AccountEntry::Missing => AccountEntry::Missing,
/// Clone dirty data into new `AccountEntry`. This includes
/// basic account data and modified storage keys.
fn clone_dirty(&self) -> AccountEntry {
AccountEntry {
account: self.account.as_ref().map(Account::clone_dirty),
state: self.state,
}
}
// Create a new account entry and mark it as dirty.
fn new_dirty(account: Option<Account>) -> AccountEntry {
AccountEntry {
account: account,
state: AccountState::Dirty,
}
}
// Create a new account entry and mark it as clean.
fn new_clean(account: Option<Account>) -> AccountEntry {
AccountEntry {
account: account,
state: AccountState::CleanFresh,
}
}
// Create a new account entry and mark it as clean and cached.
fn new_clean_cached(account: Option<Account>) -> AccountEntry {
AccountEntry {
account: account,
state: AccountState::CleanCached,
}
}
// Replace data with another entry but preserve storage cache.
fn overwrite_with(&mut self, other: AccountEntry) {
self.state = other.state;
match other.account {
Some(acc) => match self.account {
Some(ref mut ours) => {
ours.overwrite_with(acc);
},
None => {},
},
None => self.account = None,
}
}
}
@@ -86,6 +137,9 @@ impl AccountEntry {
/// locally from previous commits. Global cache reflects the database
/// state and never contains any changes.
///
/// Cache items contains account data, or the flag that account does not exist
/// and modification state (see `AccountState`)
///
/// Account data can be in the following cache states:
/// * In global but not local - something that was queried from the database,
/// but never modified
@@ -99,12 +153,32 @@ impl AccountEntry {
/// then global state cache. If data is not found in any of the caches
/// it is loaded from the DB to the local cache.
///
/// **** IMPORTANT *************************************************************
/// All the modifications to the account data must set the `Dirty` state in the
/// `AccountEntry`. This is done in `require` and `require_or_from`. So just
/// use that.
/// ****************************************************************************
///
/// Upon destruction all the local cache data merged into the global cache.
/// The merge might be rejected if current state is non-canonical.
///
/// State snapshotting.
///
/// A new snapshot can be created with `snapshot()`. Snapshots can be
/// created in a hierarchy.
/// When a snapshot is active all changes are applied directly into
/// `cache` and the original value is copied into an active snapshot.
/// Reverting a snapshot with `revert_to_snapshot` involves copying
/// original values from the latest snapshot back into `cache`. The code
/// takes care not to overwrite cached storage while doing that.
/// Snapshot can be discateded with `discard_snapshot`. All of the orignal
/// backed-up values are moved into a parent snapshot (if any).
///
pub struct State {
db: StateDB,
root: H256,
cache: RefCell<HashMap<Address, AccountEntry>>,
// The original account is preserved in
snapshots: RefCell<Vec<HashMap<Address, Option<AccountEntry>>>>,
account_start_nonce: U256,
trie_factory: TrieFactory,
@@ -117,6 +191,13 @@ enum RequireCache {
Code,
}
#[derive(PartialEq)]
pub enum CleanupMode<'a> {
ForceCreate,
NoEmpty,
KillEmpty(&'a mut HashSet<Address>),
}
const SEC_TRIE_DB_UNWRAP_STR: &'static str = "A state can only be created with valid root. Creating a SecTrieDB with a valid root will not fail. \
Therefore creating a SecTrieDB with this state's root will not fail.";
@@ -158,35 +239,48 @@ impl State {
Ok(state)
}
/// Create a recoverable snaphot of this state
/// Create a recoverable snaphot of this state.
pub fn snapshot(&mut self) {
self.snapshots.borrow_mut().push(HashMap::new());
self.snapshots.get_mut().push(HashMap::new());
}
/// Merge last snapshot with previous
pub fn clear_snapshot(&mut self) {
/// Merge last snapshot with previous.
pub fn discard_snapshot(&mut self) {
// merge with previous snapshot
let last = self.snapshots.borrow_mut().pop();
let last = self.snapshots.get_mut().pop();
if let Some(mut snapshot) = last {
if let Some(ref mut prev) = self.snapshots.borrow_mut().last_mut() {
for (k, v) in snapshot.drain() {
prev.entry(k).or_insert(v);
if let Some(ref mut prev) = self.snapshots.get_mut().last_mut() {
if prev.is_empty() {
**prev = snapshot;
} else {
for (k, v) in snapshot.drain() {
prev.entry(k).or_insert(v);
}
}
}
}
}
/// Revert to snapshot
pub fn revert_snapshot(&mut self) {
if let Some(mut snapshot) = self.snapshots.borrow_mut().pop() {
/// Revert to the last snapshot and discard it.
pub fn revert_to_snapshot(&mut self) {
if let Some(mut snapshot) = self.snapshots.get_mut().pop() {
for (k, v) in snapshot.drain() {
match v {
Some(v) => {
self.cache.borrow_mut().insert(k, v);
match self.cache.get_mut().entry(k) {
Entry::Occupied(mut e) => {
// Merge snapshotted changes back into the main account
// storage preserving the cache.
e.get_mut().overwrite_with(v);
},
Entry::Vacant(e) => {
e.insert(v);
}
}
},
None => {
match self.cache.borrow_mut().entry(k) {
::std::collections::hash_map::Entry::Occupied(e) => {
match self.cache.get_mut().entry(k) {
Entry::Occupied(e) => {
if e.get().is_dirty() {
e.remove();
}
@@ -200,10 +294,17 @@ impl State {
}
fn insert_cache(&self, address: &Address, account: AccountEntry) {
if let Some(ref mut snapshot) = self.snapshots.borrow_mut().last_mut() {
if !snapshot.contains_key(address) {
snapshot.insert(address.clone(), self.cache.borrow_mut().insert(address.clone(), account));
return;
// Dirty account which is not in the cache means this is a new account.
// It goes directly into the snapshot as there's nothing to rever to.
//
// In all other cases account is read as clean first, and after that made
// dirty in and added to the snapshot with `note_cache`.
if account.is_dirty() {
if let Some(ref mut snapshot) = self.snapshots.borrow_mut().last_mut() {
if !snapshot.contains_key(address) {
snapshot.insert(address.clone(), self.cache.borrow_mut().insert(address.clone(), account));
return;
}
}
}
self.cache.borrow_mut().insert(address.clone(), account);
@@ -212,14 +313,14 @@ impl State {
fn note_cache(&self, address: &Address) {
if let Some(ref mut snapshot) = self.snapshots.borrow_mut().last_mut() {
if !snapshot.contains_key(address) {
snapshot.insert(address.clone(), self.cache.borrow().get(address).map(AccountEntry::clone_for_snapshot));
snapshot.insert(address.clone(), self.cache.borrow().get(address).map(AccountEntry::clone_dirty));
}
}
}
/// Destroy the current object and return root and database.
pub fn drop(mut self) -> (H256, StateDB) {
self.commit_cache();
self.update_shared_cache();
(self.root, self.db)
}
@@ -230,29 +331,36 @@ impl State {
/// Create a new contract at address `contract`. If there is already an account at the address
/// it will have its code reset, ready for `init_code()`.
pub fn new_contract(&mut self, contract: &Address, balance: U256) {
self.insert_cache(contract, AccountEntry::Cached(Account::new_contract(balance, self.account_start_nonce)));
pub fn new_contract(&mut self, contract: &Address, balance: U256, nonce_offset: U256) {
self.insert_cache(contract, AccountEntry::new_dirty(Some(Account::new_contract(balance, self.account_start_nonce + nonce_offset))));
}
/// Remove an existing account.
pub fn kill_account(&mut self, account: &Address) {
self.insert_cache(account, AccountEntry::Killed);
self.insert_cache(account, AccountEntry::new_dirty(None));
}
/// Determine whether an account exists.
pub fn exists(&self, a: &Address) -> bool {
self.ensure_cached(a, RequireCache::None, |a| a.is_some())
// Bloom filter does not contain empty accounts, so it is important here to
// check if account exists in the database directly before EIP-161 is in effect.
self.ensure_cached(a, RequireCache::None, false, |a| a.is_some())
}
/// Determine whether an account exists and if not empty.
pub fn exists_and_not_null(&self, a: &Address) -> bool {
self.ensure_cached(a, RequireCache::None, false, |a| a.map_or(false, |a| !a.is_null()))
}
/// Get the balance of account `a`.
pub fn balance(&self, a: &Address) -> U256 {
self.ensure_cached(a, RequireCache::None,
self.ensure_cached(a, RequireCache::None, true,
|a| a.as_ref().map_or(U256::zero(), |account| *account.balance()))
}
/// Get the nonce of account `a`.
pub fn nonce(&self, a: &Address) -> U256 {
self.ensure_cached(a, RequireCache::None,
self.ensure_cached(a, RequireCache::None, true,
|a| a.as_ref().map_or(self.account_start_nonce, |account| *account.nonce()))
}
@@ -271,8 +379,8 @@ impl State {
let local_cache = self.cache.borrow_mut();
let mut local_account = None;
if let Some(maybe_acc) = local_cache.get(address) {
match *maybe_acc {
AccountEntry::Cached(ref account) => {
match maybe_acc.account {
Some(ref account) => {
if let Some(value) = account.cached_storage_at(key) {
return value;
} else {
@@ -288,61 +396,72 @@ impl State {
return result;
}
if let Some(ref mut acc) = local_account {
if let AccountEntry::Cached(ref account) = **acc {
if let Some(ref account) = acc.account {
return account.storage_at(&AccountDB::from_hash(self.db.as_hashdb(), account.address_hash(address)), key)
} else {
return H256::new()
}
}
}
// account is not found in the global cache, get from the DB and insert into local
if !self.db.check_account_bloom(address) { return H256::zero() }
// check bloom before any requests to trie
if !self.db.check_non_null_bloom(address) { return H256::zero() }
let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
let maybe_acc = match db.get(address) {
Ok(acc) => acc.map(Account::from_rlp),
Err(e) => panic!("Potential DB corruption encountered: {}", e),
};
let r = maybe_acc.as_ref().map_or(H256::new(), |a| a.storage_at(&AccountDB::from_hash(self.db.as_hashdb(), a.address_hash(address)), key));
match maybe_acc {
Some(account) => self.insert_cache(address, AccountEntry::Cached(account)),
None => self.insert_cache(address, AccountEntry::Missing),
}
self.insert_cache(address, AccountEntry::new_clean(maybe_acc));
r
}
/// Get accounts' code.
pub fn code(&self, a: &Address) -> Option<Arc<Bytes>> {
self.ensure_cached(a, RequireCache::Code,
self.ensure_cached(a, RequireCache::Code, true,
|a| a.as_ref().map_or(None, |a| a.code().clone()))
}
pub fn code_hash(&self, a: &Address) -> H256 {
self.ensure_cached(a, RequireCache::None,
self.ensure_cached(a, RequireCache::None, true,
|a| a.as_ref().map_or(SHA3_EMPTY, |a| a.code_hash()))
}
/// Get accounts' code size.
pub fn code_size(&self, a: &Address) -> Option<u64> {
self.ensure_cached(a, RequireCache::CodeSize,
self.ensure_cached(a, RequireCache::CodeSize, true,
|a| a.as_ref().and_then(|a| a.code_size()))
}
/// Add `incr` to the balance of account `a`.
pub fn add_balance(&mut self, a: &Address, incr: &U256) {
pub fn add_balance(&mut self, a: &Address, incr: &U256, cleanup_mode: CleanupMode) {
trace!(target: "state", "add_balance({}, {}): {}", a, incr, self.balance(a));
self.require(a, false).add_balance(incr);
let is_value_transfer = !incr.is_zero();
if is_value_transfer || (cleanup_mode == CleanupMode::ForceCreate && !self.exists(a)) {
self.require(a, false).add_balance(incr);
} else {
match cleanup_mode {
CleanupMode::KillEmpty(set) => if !is_value_transfer && self.exists(a) && !self.exists_and_not_null(a) {
set.insert(a.clone());
},
_ => {}
}
}
}
/// Subtract `decr` from the balance of account `a`.
pub fn sub_balance(&mut self, a: &Address, decr: &U256) {
trace!(target: "state", "sub_balance({}, {}): {}", a, decr, self.balance(a));
self.require(a, false).sub_balance(decr);
if !decr.is_zero() || !self.exists(a) {
self.require(a, false).sub_balance(decr);
}
}
/// Subtracts `by` from the balance of `from` and adds it to that of `to`.
pub fn transfer_balance(&mut self, from: &Address, to: &Address, by: &U256) {
pub fn transfer_balance(&mut self, from: &Address, to: &Address, by: &U256, cleanup_mode: CleanupMode) {
self.sub_balance(from, by);
self.add_balance(to, by);
self.add_balance(to, by, cleanup_mode);
}
/// Increment the nonce of account `a` by 1.
@@ -352,7 +471,9 @@ impl State {
/// Mutate storage of account `a` so that it is `value` for `key`.
pub fn set_storage(&mut self, a: &Address, key: H256, value: H256) {
self.require(a, false).set_storage(key, value)
if self.storage_at(a, &key) != value {
self.require(a, false).set_storage(key, value)
}
}
/// Initialise the code of account `a` so that it is `code`.
@@ -392,32 +513,31 @@ impl State {
accounts: &mut HashMap<Address, AccountEntry>
) -> Result<(), Error> {
// first, commit the sub trees.
// TODO: is this necessary or can we dispense with the `ref mut a` for just `a`?
for (address, ref mut a) in accounts.iter_mut() {
match a {
&mut&mut AccountEntry::Cached(ref mut account) if account.is_dirty() => {
db.note_account_bloom(&address);
let mut account_db = AccountDBMut::from_hash(db.as_hashdb_mut(), account.address_hash(address));
for (address, ref mut a) in accounts.iter_mut().filter(|&(_, ref a)| a.is_dirty()) {
if let Some(ref mut account) = a.account {
let addr_hash = account.address_hash(address);
{
let mut account_db = AccountDBMut::from_hash(db.as_hashdb_mut(), addr_hash);
account.commit_storage(trie_factory, &mut account_db);
account.commit_code(&mut account_db);
}
_ => {}
if !account.is_empty() {
db.note_non_null_account(address);
}
}
}
{
let mut trie = trie_factory.from_existing(db.as_hashdb_mut(), root).unwrap();
for (address, ref mut a) in accounts.iter_mut() {
match **a {
AccountEntry::Cached(ref mut account) if account.is_dirty() => {
account.set_clean();
for (address, ref mut a) in accounts.iter_mut().filter(|&(_, ref a)| a.is_dirty()) {
a.state = AccountState::Committed;
match a.account {
Some(ref mut account) => {
try!(trie.insert(address, &account.rlp()));
},
AccountEntry::Killed => {
None => {
try!(trie.remove(address));
**a = AccountEntry::Missing;
},
_ => {},
}
}
}
@@ -425,20 +545,12 @@ impl State {
Ok(())
}
fn commit_cache(&mut self) {
/// Merge local cache into shared canonical state cache.
fn update_shared_cache(&mut self) {
let mut addresses = self.cache.borrow_mut();
for (address, a) in addresses.drain() {
match a {
AccountEntry::Cached(account) => {
if !account.is_dirty() {
self.db.cache_account(address, Some(account));
}
},
AccountEntry::Missing => {
self.db.cache_account(address, None);
},
_ => {},
}
trace!("Committing cache {:?} entries", addresses.len());
for (address, a) in addresses.drain().filter(|&(_, ref a)| a.state == AccountState::Committed || a.state == AccountState::CleanFresh) {
self.db.add_to_account_cache(address, a.account, a.state == AccountState::Committed);
}
}
@@ -459,8 +571,7 @@ impl State {
pub fn populate_from(&mut self, accounts: PodState) {
assert!(self.snapshots.borrow().is_empty());
for (add, acc) in accounts.drain().into_iter() {
self.db.note_account_bloom(&add);
self.cache.borrow_mut().insert(add, AccountEntry::Cached(Account::from_pod(acc)));
self.cache.borrow_mut().insert(add, AccountEntry::new_dirty(Some(Account::from_pod(acc))));
}
}
@@ -470,7 +581,7 @@ impl State {
// TODO: handle database rather than just the cache.
// will need fat db.
PodState::from(self.cache.borrow().iter().fold(BTreeMap::new(), |mut m, (add, opt)| {
if let AccountEntry::Cached(ref acc) = *opt {
if let Some(ref acc) = opt.account {
m.insert(add.clone(), PodAccount::from_account(acc));
}
m
@@ -478,14 +589,14 @@ impl State {
}
fn query_pod(&mut self, query: &PodState) {
for (ref address, ref pod_account) in query.get() {
self.ensure_cached(address, RequireCache::Code, |a| {
if a.is_some() {
for key in pod_account.storage.keys() {
self.storage_at(address, key);
}
}
});
for (address, pod_account) in query.get().into_iter()
.filter(|&(ref a, _)| self.ensure_cached(a, RequireCache::Code, true, |a| a.is_some()))
{
// needs to be split into two parts for the refcell code here
// to work.
for key in pod_account.storage.keys() {
self.storage_at(address, key);
}
}
}
@@ -515,11 +626,11 @@ impl State {
/// Check caches for required data
/// First searches for account in the local, then the shared cache.
/// Populates local cache if nothing found.
fn ensure_cached<F, U>(&self, a: &Address, require: RequireCache, f: F) -> U
fn ensure_cached<F, U>(&self, a: &Address, require: RequireCache, check_bloom: bool, f: F) -> U
where F: Fn(Option<&Account>) -> U {
// check local cache first
if let Some(ref mut maybe_acc) = self.cache.borrow_mut().get_mut(a) {
if let AccountEntry::Cached(ref mut account) = **maybe_acc {
if let Some(ref mut account) = maybe_acc.account {
Self::update_account_cache(require, account, a, self.db.as_hashdb());
return f(Some(account));
}
@@ -535,8 +646,10 @@ impl State {
match result {
Some(r) => r,
None => {
// first check bloom if it is not in database for sure
if check_bloom && !self.db.check_non_null_bloom(a) { return f(None); }
// not found in the global cache, get from the DB and insert into local
if !self.db.check_account_bloom(a) { return f(None); }
let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
let mut maybe_acc = match db.get(a) {
Ok(acc) => acc.map(Account::from_rlp),
@@ -546,10 +659,7 @@ impl State {
Self::update_account_cache(require, account, a, self.db.as_hashdb());
}
let r = f(maybe_acc.as_ref());
match maybe_acc {
Some(account) => self.insert_cache(a, AccountEntry::Cached(account)),
None => self.insert_cache(a, AccountEntry::Missing),
}
self.insert_cache(a, AccountEntry::new_clean(maybe_acc));
r
}
}
@@ -568,36 +678,37 @@ impl State {
let contains_key = self.cache.borrow().contains_key(a);
if !contains_key {
match self.db.get_cached_account(a) {
Some(Some(acc)) => self.insert_cache(a, AccountEntry::Cached(acc)),
Some(None) => self.insert_cache(a, AccountEntry::Missing),
Some(acc) => self.insert_cache(a, AccountEntry::new_clean_cached(acc)),
None => {
let maybe_acc = if self.db.check_account_bloom(a) {
let maybe_acc = if self.db.check_non_null_bloom(a) {
let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
let maybe_acc = match db.get(a) {
Ok(Some(acc)) => AccountEntry::Cached(Account::from_rlp(acc)),
Ok(None) => AccountEntry::Missing,
match db.get(a) {
Ok(Some(acc)) => AccountEntry::new_clean(Some(Account::from_rlp(&acc))),
Ok(None) => AccountEntry::new_clean(None),
Err(e) => panic!("Potential DB corruption encountered: {}", e),
};
maybe_acc
}
}
else {
AccountEntry::Missing
AccountEntry::new_clean(None)
};
self.insert_cache(a, maybe_acc);
}
}
} else {
self.note_cache(a);
}
match self.cache.borrow_mut().get_mut(a).unwrap() {
&mut AccountEntry::Cached(ref mut acc) => not_default(acc),
slot => *slot = AccountEntry::Cached(default()),
}
self.note_cache(a);
match &mut self.cache.borrow_mut().get_mut(a).unwrap().account {
&mut Some(ref mut acc) => not_default(acc),
slot => *slot = Some(default()),
}
// at this point the account is guaranteed to be in the cache.
RefMut::map(self.cache.borrow_mut(), |c| {
match c.get_mut(a).unwrap() {
&mut AccountEntry::Cached(ref mut account) => {
let mut entry = c.get_mut(a).unwrap();
// set the dirty flag after changing account data.
entry.state = AccountState::Dirty;
match entry.account {
Some(ref mut account) => {
if require_code {
let addr_hash = account.address_hash(a);
account.cache_code(&AccountDB::from_hash(self.db.as_hashdb(), addr_hash));
@@ -621,7 +732,7 @@ impl Clone for State {
let cache = {
let mut cache: HashMap<Address, AccountEntry> = HashMap::new();
for (key, val) in self.cache.borrow().iter() {
if let Some(entry) = val.clone_dirty() {
if let Some(entry) = val.clone_if_dirty() {
cache.insert(key.clone(), entry);
}
}
@@ -673,9 +784,9 @@ fn should_apply_create_transaction() {
action: Action::Create,
value: 100.into(),
data: FromHex::from_hex("601080600c6000396000f3006000355415600957005b60203560003555").unwrap(),
}.sign(&"".sha3());
}.sign(&"".sha3(), None);
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
@@ -734,9 +845,9 @@ fn should_trace_failed_create_transaction() {
action: Action::Create,
value: 100.into(),
data: FromHex::from_hex("5b600056").unwrap(),
}.sign(&"".sha3());
}.sign(&"".sha3(), None);
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
@@ -772,10 +883,10 @@ fn should_trace_call_transaction() {
action: Action::Call(0xa.into()),
value: 100.into(),
data: vec![],
}.sign(&"".sha3());
}.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("6000").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
@@ -816,9 +927,9 @@ fn should_trace_basic_call_transaction() {
action: Action::Call(0xa.into()),
value: 100.into(),
data: vec![],
}.sign(&"".sha3());
}.sign(&"".sha3(), None);
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
@@ -859,7 +970,7 @@ fn should_trace_call_transaction_to_builtin() {
action: Action::Call(0x1.into()),
value: 0.into(),
data: vec![],
}.sign(&"".sha3());
}.sign(&"".sha3(), None);
let vm_factory = Default::default();
let result = state.apply(&info, engine, &vm_factory, &t, true).unwrap();
@@ -902,7 +1013,7 @@ fn should_not_trace_subcall_transaction_to_builtin() {
action: Action::Call(0xa.into()),
value: 0.into(),
data: vec![],
}.sign(&"".sha3());
}.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060006001610be0f1").unwrap());
let vm_factory = Default::default();
@@ -946,7 +1057,7 @@ fn should_not_trace_callcode() {
action: Action::Call(0xa.into()),
value: 0.into(),
data: vec![],
}.sign(&"".sha3());
}.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b611000f2").unwrap());
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
@@ -1009,7 +1120,7 @@ fn should_not_trace_delegatecall() {
action: Action::Call(0xa.into()),
value: 0.into(),
data: vec![],
}.sign(&"".sha3());
}.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("6000600060006000600b618000f4").unwrap());
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
@@ -1069,10 +1180,10 @@ fn should_trace_failed_call_transaction() {
action: Action::Call(0xa.into()),
value: 100.into(),
data: vec![],
}.sign(&"".sha3());
}.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("5b600056").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
@@ -1110,11 +1221,11 @@ fn should_trace_call_with_subcall_transaction() {
action: Action::Call(0xa.into()),
value: 100.into(),
data: vec![],
}.sign(&"".sha3());
}.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
@@ -1171,10 +1282,10 @@ fn should_trace_call_with_basic_subcall_transaction() {
action: Action::Call(0xa.into()),
value: 100.into(),
data: vec![],
}.sign(&"".sha3());
}.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006045600b6000f1").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
@@ -1227,10 +1338,10 @@ fn should_not_trace_call_with_invalid_basic_subcall_transaction() {
action: Action::Call(0xa.into()),
value: 100.into(),
data: vec![],
}.sign(&"".sha3());
}.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060ff600b6000f1").unwrap()); // not enough funds.
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
@@ -1271,11 +1382,11 @@ fn should_trace_failed_subcall_transaction() {
action: Action::Call(0xa.into()),
value: 100.into(),
data: vec![],//600480600b6000396000f35b600056
}.sign(&"".sha3());
}.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
state.init_code(&0xb.into(), FromHex::from_hex("5b600056").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
@@ -1328,12 +1439,12 @@ fn should_trace_call_with_subcall_with_subcall_transaction() {
action: Action::Call(0xa.into()),
value: 100.into(),
data: vec![],
}.sign(&"".sha3());
}.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1").unwrap());
state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
@@ -1404,12 +1515,12 @@ fn should_trace_failed_subcall_with_subcall_transaction() {
action: Action::Call(0xa.into()),
value: 100.into(),
data: vec![],//600480600b6000396000f35b600056
}.sign(&"".sha3());
}.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1505b601256").unwrap());
state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
@@ -1478,11 +1589,11 @@ fn should_trace_suicide() {
action: Action::Call(0xa.into()),
value: 100.into(),
data: vec![],
}.sign(&"".sha3());
}.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("73000000000000000000000000000000000000000bff").unwrap());
state.add_balance(&0xa.into(), &50.into());
state.add_balance(t.sender().as_ref().unwrap(), &100.into());
state.add_balance(&0xa.into(), &50.into(), CleanupMode::NoEmpty);
state.add_balance(t.sender().as_ref().unwrap(), &100.into(), CleanupMode::NoEmpty);
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
@@ -1554,7 +1665,7 @@ fn get_from_database() {
let (root, db) = {
let mut state = get_temp_state_in(temp.as_path());
state.inc_nonce(&a);
state.add_balance(&a, &U256::from(69u64));
state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty);
state.commit().unwrap();
assert_eq!(state.balance(&a), U256::from(69u64));
state.drop()
@@ -1571,14 +1682,49 @@ fn remove() {
let mut state_result = get_temp_state();
let mut state = state_result.reference_mut();
assert_eq!(state.exists(&a), false);
assert_eq!(state.exists_and_not_null(&a), false);
state.inc_nonce(&a);
assert_eq!(state.exists(&a), true);
assert_eq!(state.exists_and_not_null(&a), true);
assert_eq!(state.nonce(&a), U256::from(1u64));
state.kill_account(&a);
assert_eq!(state.exists(&a), false);
assert_eq!(state.exists_and_not_null(&a), false);
assert_eq!(state.nonce(&a), U256::from(0u64));
}
#[test]
fn empty_account_is_not_created() {
let a = Address::zero();
let path = RandomTempPath::new();
let db = get_temp_state_db_in(path.as_path());
let (root, db) = {
let mut state = State::new(db, U256::from(0), Default::default());
state.add_balance(&a, &U256::default(), CleanupMode::NoEmpty); // create an empty account
state.commit().unwrap();
state.drop()
};
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
assert!(!state.exists(&a));
assert!(!state.exists_and_not_null(&a));
}
#[test]
fn empty_account_exists_when_creation_forced() {
let a = Address::zero();
let path = RandomTempPath::new();
let db = get_temp_state_db_in(path.as_path());
let (root, db) = {
let mut state = State::new(db, U256::from(0), Default::default());
state.add_balance(&a, &U256::default(), CleanupMode::ForceCreate); // create an empty account
state.commit().unwrap();
state.drop()
};
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
assert!(state.exists(&a));
assert!(!state.exists_and_not_null(&a));
}
#[test]
fn remove_from_database() {
let a = Address::zero();
@@ -1614,7 +1760,7 @@ fn alter_balance() {
let mut state = state_result.reference_mut();
let a = Address::zero();
let b = address_from_u64(1u64);
state.add_balance(&a, &U256::from(69u64));
state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty);
assert_eq!(state.balance(&a), U256::from(69u64));
state.commit().unwrap();
assert_eq!(state.balance(&a), U256::from(69u64));
@@ -1622,7 +1768,7 @@ fn alter_balance() {
assert_eq!(state.balance(&a), U256::from(27u64));
state.commit().unwrap();
assert_eq!(state.balance(&a), U256::from(27u64));
state.transfer_balance(&a, &b, &U256::from(18u64));
state.transfer_balance(&a, &b, &U256::from(18u64), CleanupMode::NoEmpty);
assert_eq!(state.balance(&a), U256::from(9u64));
assert_eq!(state.balance(&b), U256::from(18u64));
state.commit().unwrap();
@@ -1675,14 +1821,14 @@ fn snapshot_basic() {
let mut state = state_result.reference_mut();
let a = Address::zero();
state.snapshot();
state.add_balance(&a, &U256::from(69u64));
state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty);
assert_eq!(state.balance(&a), U256::from(69u64));
state.clear_snapshot();
state.discard_snapshot();
assert_eq!(state.balance(&a), U256::from(69u64));
state.snapshot();
state.add_balance(&a, &U256::from(1u64));
state.add_balance(&a, &U256::from(1u64), CleanupMode::NoEmpty);
assert_eq!(state.balance(&a), U256::from(70u64));
state.revert_snapshot();
state.revert_to_snapshot();
assert_eq!(state.balance(&a), U256::from(69u64));
}
@@ -1693,11 +1839,11 @@ fn snapshot_nested() {
let a = Address::zero();
state.snapshot();
state.snapshot();
state.add_balance(&a, &U256::from(69u64));
state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty);
assert_eq!(state.balance(&a), U256::from(69u64));
state.clear_snapshot();
state.discard_snapshot();
assert_eq!(state.balance(&a), U256::from(69u64));
state.revert_snapshot();
state.revert_to_snapshot();
assert_eq!(state.balance(&a), U256::from(0));
}
@@ -1709,4 +1855,20 @@ fn create_empty() {
assert_eq!(state.root().hex(), "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421");
}
#[test]
fn should_not_panic_on_state_diff_with_storage() {
let state = get_temp_state();
let mut state = state.reference().clone();
let a: Address = 0xa.into();
state.init_code(&a, b"abcdefg".to_vec());
state.add_balance(&a, &256.into(), CleanupMode::NoEmpty);
state.set_storage(&a, 0xb.into(), 0xc.into());
let mut new_state = state.clone();
new_state.set_storage(&a, 0xb.into(), 0xd.into());
new_state.diff_from(state);
}
}

View File

@@ -14,22 +14,53 @@
// 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::collections::{VecDeque, HashSet};
use lru_cache::LruCache;
use util::journaldb::JournalDB;
use util::hash::{H256};
use util::hashdb::HashDB;
use util::{Arc, Address, DBTransaction, UtilError, Mutex, Hashable, BytesConvertable};
use account::Account;
use header::BlockNumber;
use util::{Arc, Address, Database, DBTransaction, UtilError, Mutex, Hashable, BytesConvertable};
use bloomfilter::{Bloom, BloomJournal};
use util::Database;
use client::DB_COL_ACCOUNT_BLOOM;
use byteorder::{LittleEndian, ByteOrder};
const STATE_CACHE_ITEMS: usize = 65536;
const STATE_CACHE_ITEMS: usize = 256000;
const STATE_CACHE_BLOCKS: usize = 12;
/// Shared canonical state cache.
struct AccountCache {
/// DB Account cache. `None` indicates that account is known to be missing.
accounts: LruCache<Address, Option<Account>>,
/// Accounts changed in recently committed blocks. Ordered by block number.
modifications: VecDeque<BlockChanges>,
}
/// Buffered account cache item.
struct CacheQueueItem {
/// Account address.
address: Address,
/// Acccount data or `None` if account does not exist.
account: Option<Account>,
/// Indicates that the account was modified before being
/// added to the cache.
modified: bool,
}
#[derive(Debug)]
/// Accumulates a list of accounts changed in a block.
struct BlockChanges {
/// Block number.
number: BlockNumber,
/// Block hash.
hash: H256,
/// Parent block hash.
parent: H256,
/// A set of modified account addresses.
accounts: HashSet<Address>,
/// Block is part of the canonical chain.
is_canon: bool,
}
/// State database abstraction.
@@ -39,11 +70,21 @@ struct AccountCache {
/// on commit.
/// For non-canonical clones cache is cleared on commit.
pub struct StateDB {
/// Backing database.
db: Box<JournalDB>,
/// Shared canonical state cache.
account_cache: Arc<Mutex<AccountCache>>,
cache_overlay: Vec<(Address, Option<Account>)>,
is_canon: bool,
/// Local cache buffer.
cache_buffer: Vec<CacheQueueItem>,
/// Shared account bloom. Does not handle chain reorganizations.
account_bloom: Arc<Mutex<Bloom>>,
/// Hash of the block on top of which this instance was created or
/// `None` if cache is disabled
parent_hash: Option<H256>,
/// Hash of the committing block or `None` if not committed yet.
commit_hash: Option<H256>,
/// Number of the committing block or `None` if not committed yet.
commit_number: Option<BlockNumber>,
}
pub const ACCOUNT_BLOOM_SPACE: usize = 1048576;
@@ -52,6 +93,8 @@ pub const DEFAULT_ACCOUNT_PRESET: usize = 1000000;
pub const ACCOUNT_BLOOM_HASHCOUNT_KEY: &'static [u8] = b"account_hash_count";
impl StateDB {
/// Loads accounts bloom from the database
/// This bloom is used to handle request for the non-existant account fast
pub fn load_bloom(db: &Database) -> Bloom {
let hash_count_entry = db.get(DB_COL_ACCOUNT_BLOOM, ACCOUNT_BLOOM_HASHCOUNT_KEY)
.expect("Low-level database error");
@@ -82,20 +125,25 @@ impl StateDB {
let bloom = Self::load_bloom(db.backing());
StateDB {
db: db,
account_cache: Arc::new(Mutex::new(AccountCache { accounts: LruCache::new(STATE_CACHE_ITEMS) })),
cache_overlay: Vec::new(),
is_canon: false,
account_cache: Arc::new(Mutex::new(AccountCache {
accounts: LruCache::new(STATE_CACHE_ITEMS),
modifications: VecDeque::new(),
})),
cache_buffer: Vec::new(),
account_bloom: Arc::new(Mutex::new(bloom)),
parent_hash: None,
commit_hash: None,
commit_number: None,
}
}
pub fn check_account_bloom(&self, address: &Address) -> bool {
pub fn check_non_null_bloom(&self, address: &Address) -> bool {
trace!(target: "account_bloom", "Check account bloom: {:?}", address);
let bloom = self.account_bloom.lock();
bloom.check(address.sha3().as_slice())
}
pub fn note_account_bloom(&self, address: &Address) {
pub fn note_non_null_account(&self, address: &Address) {
trace!(target: "account_bloom", "Note account bloom: {:?}", address);
let mut bloom = self.account_bloom.lock();
bloom.set(address.sha3().as_slice());
@@ -124,14 +172,106 @@ impl StateDB {
}
let records = try!(self.db.commit(batch, now, id, end));
if self.is_canon {
self.commit_cache();
} else {
self.clear_cache();
}
self.commit_hash = Some(id.clone());
self.commit_number = Some(now);
Ok(records)
}
/// Apply buffered cache changes and synchronize canonical
/// state cache with the best block state.
/// This function updates the cache by removing entries that are
/// invalidated by chain reorganization. `update_cache` should be
/// called after the block has been commited and the blockchain
/// route has ben calculated.
pub fn sync_cache(&mut self, enacted: &[H256], retracted: &[H256], is_best: bool) {
trace!("sync_cache id = (#{:?}, {:?}), parent={:?}, best={}", self.commit_number, self.commit_hash, self.parent_hash, is_best);
let mut cache = self.account_cache.lock();
let mut cache = &mut *cache;
// Clean changes from re-enacted and retracted blocks
let mut clear = false;
for block in enacted.iter().filter(|h| self.commit_hash.as_ref().map_or(true, |p| *h != p)) {
clear = clear || {
if let Some(ref mut m) = cache.modifications.iter_mut().find(|ref m| &m.hash == block) {
trace!("Reverting enacted block {:?}", block);
m.is_canon = true;
for a in &m.accounts {
trace!("Reverting enacted address {:?}", a);
cache.accounts.remove(a);
}
false
} else {
true
}
};
}
for block in retracted {
clear = clear || {
if let Some(ref mut m) = cache.modifications.iter_mut().find(|ref m| &m.hash == block) {
trace!("Retracting block {:?}", block);
m.is_canon = false;
for a in &m.accounts {
trace!("Retracted address {:?}", a);
cache.accounts.remove(a);
}
false
} else {
true
}
};
}
if clear {
// We don't know anything about the block; clear everything
trace!("Wiping cache");
cache.accounts.clear();
cache.modifications.clear();
}
// Apply cache changes only if committing on top of the latest canonical state
// blocks are ordered by number and only one block with a given number is marked as canonical
// (contributed to canonical state cache)
if let (Some(ref number), Some(ref hash), Some(ref parent)) = (self.commit_number, self.commit_hash, self.parent_hash) {
if cache.modifications.len() == STATE_CACHE_BLOCKS {
cache.modifications.pop_back();
}
let mut modifications = HashSet::new();
trace!("committing {} cache entries", self.cache_buffer.len());
for account in self.cache_buffer.drain(..) {
if account.modified {
modifications.insert(account.address.clone());
}
if is_best {
if let Some(&mut Some(ref mut existing)) = cache.accounts.get_mut(&account.address) {
if let Some(new) = account.account {
if account.modified {
existing.overwrite_with(new);
}
continue;
}
}
cache.accounts.insert(account.address, account.account);
}
}
// Save modified accounts. These are ordered by the block number.
let block_changes = BlockChanges {
accounts: modifications,
number: *number,
hash: hash.clone(),
is_canon: is_best,
parent: parent.clone(),
};
let insert_at = cache.modifications.iter().enumerate().find(|&(_, ref m)| m.number < *number).map(|(i, _)| i);
trace!("inserting modifications at {:?}", insert_at);
if let Some(insert_at) = insert_at {
cache.modifications.insert(insert_at, block_changes);
} else {
cache.modifications.push_back(block_changes);
}
}
}
/// Returns an interface to HashDB.
pub fn as_hashdb(&self) -> &HashDB {
self.db.as_hashdb()
@@ -147,20 +287,24 @@ impl StateDB {
StateDB {
db: self.db.boxed_clone(),
account_cache: self.account_cache.clone(),
cache_overlay: Vec::new(),
is_canon: false,
cache_buffer: Vec::new(),
account_bloom: self.account_bloom.clone(),
parent_hash: None,
commit_hash: None,
commit_number: None,
}
}
/// Clone the database for a canonical state.
pub fn boxed_clone_canon(&self) -> StateDB {
pub fn boxed_clone_canon(&self, parent: &H256) -> StateDB {
StateDB {
db: self.db.boxed_clone(),
account_cache: self.account_cache.clone(),
cache_overlay: Vec::new(),
is_canon: true,
cache_buffer: Vec::new(),
account_bloom: self.account_bloom.clone(),
parent_hash: Some(parent.clone()),
commit_hash: None,
commit_number: None,
}
}
@@ -179,53 +323,152 @@ impl StateDB {
&*self.db
}
/// Enqueue cache change.
pub fn cache_account(&mut self, addr: Address, data: Option<Account>) {
self.cache_overlay.push((addr, data));
/// Returns underlying `JournalDB`.
pub fn journal_db_mut(&mut self) -> &mut JournalDB {
&mut *self.db
}
/// Apply pending cache changes.
fn commit_cache(&mut self) {
let mut cache = self.account_cache.lock();
for (address, account) in self.cache_overlay.drain(..) {
if let Some(&mut Some(ref mut existing)) = cache.accounts.get_mut(&address) {
if let Some(new) = account {
existing.merge_with(new);
continue;
}
}
cache.accounts.insert(address, account);
}
}
/// Clear the cache.
pub fn clear_cache(&mut self) {
self.cache_overlay.clear();
let mut cache = self.account_cache.lock();
cache.accounts.clear();
/// Add pending cache change.
/// The change is queued to be applied in `commit`.
pub fn add_to_account_cache(&mut self, addr: Address, data: Option<Account>, modified: bool) {
self.cache_buffer.push(CacheQueueItem {
address: addr,
account: data,
modified: modified,
})
}
/// Get basic copy of the cached account. Does not include storage.
/// Returns 'None' if the state is non-canonical and cache is disabled
/// or if the account is not cached.
/// Returns 'None' if cache is disabled or if the account is not cached.
pub fn get_cached_account(&self, addr: &Address) -> Option<Option<Account>> {
if !self.is_canon {
let mut cache = self.account_cache.lock();
if !Self::is_allowed(addr, &self.parent_hash, &cache.modifications) {
return None;
}
let mut cache = self.account_cache.lock();
cache.accounts.get_mut(&addr).map(|a| a.as_ref().map(|a| a.clone_basic()))
}
/// Get value from a cached account.
/// Returns 'None' if the state is non-canonical and cache is disabled
/// or if the account is not cached.
/// Returns 'None' if cache is disabled or if the account is not cached.
pub fn get_cached<F, U>(&self, a: &Address, f: F) -> Option<U>
where F: FnOnce(Option<&mut Account>) -> U {
if !self.is_canon {
let mut cache = self.account_cache.lock();
if !Self::is_allowed(a, &self.parent_hash, &cache.modifications) {
return None;
}
let mut cache = self.account_cache.lock();
cache.accounts.get_mut(a).map(|c| f(c.as_mut()))
}
/// Check if the account can be returned from cache by matching current block parent hash against canonical
/// state and filtering out account modified in later blocks.
fn is_allowed(addr: &Address, parent_hash: &Option<H256>, modifications: &VecDeque<BlockChanges>) -> bool {
let mut parent = match *parent_hash {
None => {
trace!("Cache lookup skipped for {:?}: no parent hash", addr);
return false;
}
Some(ref parent) => parent,
};
if modifications.is_empty() {
return true;
}
// Ignore all accounts modified in later blocks
// Modifications contains block ordered by the number
// We search for our parent in that list first and then for
// all its parent until we hit the canonical block,
// checking against all the intermediate modifications.
let mut iter = modifications.iter();
while let Some(ref m) = iter.next() {
if &m.hash == parent {
if m.is_canon {
return true;
}
parent = &m.parent;
}
if m.accounts.contains(addr) {
trace!("Cache lookup skipped for {:?}: modified in a later block", addr);
return false;
}
}
trace!("Cache lookup skipped for {:?}: parent hash is unknown", addr);
return false;
}
}
#[cfg(test)]
mod tests {
use util::{U256, H256, FixedHash, Address, DBTransaction};
use tests::helpers::*;
use account::Account;
use util::log::init_log;
#[test]
fn state_db_smoke() {
init_log();
let mut state_db_result = get_temp_state_db();
let state_db = state_db_result.take();
let root_parent = H256::random();
let address = Address::random();
let h0 = H256::random();
let h1a = H256::random();
let h1b = H256::random();
let h2a = H256::random();
let h2b = H256::random();
let h3a = H256::random();
let h3b = H256::random();
let mut batch = DBTransaction::new(state_db.journal_db().backing());
// blocks [ 3a(c) 2a(c) 2b 1b 1a(c) 0 ]
// balance [ 5 5 4 3 2 2 ]
let mut s = state_db.boxed_clone_canon(&root_parent);
s.add_to_account_cache(address, Some(Account::new_basic(2.into(), 0.into())), false);
s.commit(&mut batch, 0, &h0, None).unwrap();
s.sync_cache(&[], &[], true);
let mut s = state_db.boxed_clone_canon(&h0);
s.commit(&mut batch, 1, &h1a, None).unwrap();
s.sync_cache(&[], &[], true);
let mut s = state_db.boxed_clone_canon(&h0);
s.add_to_account_cache(address, Some(Account::new_basic(3.into(), 0.into())), true);
s.commit(&mut batch, 1, &h1b, None).unwrap();
s.sync_cache(&[], &[], false);
let mut s = state_db.boxed_clone_canon(&h1b);
s.add_to_account_cache(address, Some(Account::new_basic(4.into(), 0.into())), true);
s.commit(&mut batch, 2, &h2b, None).unwrap();
s.sync_cache(&[], &[], false);
let mut s = state_db.boxed_clone_canon(&h1a);
s.add_to_account_cache(address, Some(Account::new_basic(5.into(), 0.into())), true);
s.commit(&mut batch, 2, &h2a, None).unwrap();
s.sync_cache(&[], &[], true);
let mut s = state_db.boxed_clone_canon(&h2a);
s.commit(&mut batch, 3, &h3a, None).unwrap();
s.sync_cache(&[], &[], true);
let s = state_db.boxed_clone_canon(&h3a);
assert_eq!(s.get_cached_account(&address).unwrap().unwrap().balance(), &U256::from(5));
let s = state_db.boxed_clone_canon(&h1a);
assert!(s.get_cached_account(&address).is_none());
let s = state_db.boxed_clone_canon(&h2b);
assert!(s.get_cached_account(&address).is_none());
let s = state_db.boxed_clone_canon(&h1b);
assert!(s.get_cached_account(&address).is_none());
// reorg to 3b
// blocks [ 3b(c) 3a 2a 2b(c) 1b 1a 0 ]
let mut s = state_db.boxed_clone_canon(&h2b);
s.commit(&mut batch, 3, &h3b, None).unwrap();
s.sync_cache(&[h1b.clone(), h2b.clone(), h3b.clone()], &[h1a.clone(), h2a.clone(), h3a.clone()], true);
let s = state_db.boxed_clone_canon(&h3a);
assert!(s.get_cached_account(&address).is_none());
}
}

View File

@@ -18,6 +18,8 @@
use std::collections::HashSet;
use util::{Address, U256};
use log_entry::LogEntry;
use evm::Schedule;
use state::CleanupMode;
/// State changes which should be applied in finalize,
/// after transaction is fully executed.
@@ -26,6 +28,9 @@ pub struct Substate {
/// Any accounts that have suicided.
pub suicides: HashSet<Address>,
/// Any accounts that are tagged for garbage collection.
pub garbage: HashSet<Address>,
/// Any logs.
pub logs: Vec<LogEntry>,
@@ -45,10 +50,20 @@ impl Substate {
/// Merge secondary substate `s` into self, accruing each element correspondingly.
pub fn accrue(&mut self, s: Substate) {
self.suicides.extend(s.suicides.into_iter());
self.garbage.extend(s.garbage.into_iter());
self.logs.extend(s.logs.into_iter());
self.sstore_clears_count = self.sstore_clears_count + s.sstore_clears_count;
self.contracts_created.extend(s.contracts_created.into_iter());
}
/// Get the cleanup mode object from this.
pub fn to_cleanup_mode(&mut self, schedule: &Schedule) -> CleanupMode {
match (schedule.no_empty, schedule.kill_empty) {
(false, _) => CleanupMode::ForceCreate,
(true, false) => CleanupMode::NoEmpty,
(true, true) => CleanupMode::KillEmpty(&mut self.garbage),
}
}
}
#[cfg(test)]

View File

@@ -16,12 +16,14 @@
use io::IoChannel;
use client::{BlockChainClient, MiningBlockChainClient, Client, ClientConfig, BlockID};
use state::CleanupMode;
use ethereum;
use block::IsBlock;
use tests::helpers::*;
use common::*;
use devtools::*;
use miner::Miner;
use spec::Spec;
#[test]
fn imports_from_empty() {
@@ -151,7 +153,7 @@ fn can_handle_long_fork() {
push_blocks_to_client(client, 49, 1201, 800);
push_blocks_to_client(client, 53, 1201, 600);
for _ in 0..40 {
for _ in 0..400 {
client.import_verified_blocks();
}
assert_eq!(2000, client.chain_info().best_block_number);
@@ -167,3 +169,26 @@ fn can_mine() {
assert_eq!(*b.block().header().parent_hash(), BlockView::new(&dummy_blocks[0]).header_view().sha3());
}
#[test]
fn change_history_size() {
let dir = RandomTempPath::new();
let test_spec = Spec::new_null();
let mut config = ClientConfig::default();
config.history = 2;
let address = Address::random();
{
let client = Client::new(ClientConfig::default(), &test_spec, dir.as_path(), Arc::new(Miner::with_spec(&test_spec)), IoChannel::disconnected()).unwrap();
for _ in 0..20 {
let mut b = client.prepare_open_block(Address::default(), (3141562.into(), 31415620.into()), vec![]);
b.block_mut().fields_mut().state.add_balance(&address, &5.into(), CleanupMode::NoEmpty);
b.block_mut().fields_mut().state.commit().unwrap();
let b = b.close_and_lock().seal(&*test_spec.engine, vec![]).unwrap();
client.import_sealed_block(b).unwrap(); // account change is in the journal overlay
}
}
let mut config = ClientConfig::default();
config.history = 10;
let client = Client::new(config, &test_spec, dir.as_path(), Arc::new(Miner::with_spec(&test_spec)), IoChannel::disconnected()).unwrap();
assert_eq!(client.state().balance(&address), 100.into());
}

View File

@@ -32,19 +32,21 @@ use miner::Miner;
pub enum ChainEra {
Frontier,
Homestead,
DaoHardfork,
Eip150,
Eip161,
TransitionTest,
}
pub struct TestEngine {
engine: Arc<Engine>,
max_depth: usize
max_depth: usize,
}
impl TestEngine {
pub fn new(max_depth: usize) -> TestEngine {
TestEngine {
engine: ethereum::new_frontier_test().engine,
max_depth: max_depth
max_depth: max_depth,
}
}
}
@@ -180,7 +182,7 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
action: Action::Create,
data: vec![],
value: U256::zero(),
}.sign(kp.secret()), None).unwrap();
}.sign(kp.secret(), None), None).unwrap();
n += 1;
}

View File

@@ -16,4 +16,6 @@
pub mod helpers;
mod client;
#[cfg(feature="ipc")]
mod rpc;

View File

@@ -268,16 +268,6 @@ impl<T> TraceDatabase for TraceDB<T> where T: DatabaseExtras {
return;
}
// at first, let's insert new block traces
{
let mut traces = self.traces.write();
// it's important to use overwrite here,
// cause this value might be queried by hash later
batch.write_with_cache(DB_COL_TRACE, &mut *traces, request.block_hash, request.traces, CacheUpdatePolicy::Overwrite);
// note_used must be called after locking traces to avoid cache/traces deadlock on garbage collection
self.note_used(CacheID::Trace(request.block_hash.clone()));
}
// now let's rebuild the blooms
{
let range_start = request.block_number as Number + 1 - request.enacted.len();
@@ -288,12 +278,25 @@ impl<T> TraceDatabase for TraceDB<T> where T: DatabaseExtras {
// all traces are expected to be found here. That's why `expect` has been used
// instead of `filter_map`. If some traces haven't been found, it meens that
// traces database is corrupted or incomplete.
.map(|block_hash| self.traces(block_hash).expect("Traces database is incomplete."))
.map(|block_traces| block_traces.bloom())
.map(|block_hash| if block_hash == &request.block_hash {
request.traces.bloom()
} else {
self.traces(block_hash).expect("Traces database is incomplete.").bloom()
})
.map(blooms::Bloom::from)
.map(Into::into)
.collect();
// insert new block traces into the cache and the database
{
let mut traces = self.traces.write();
// it's important to use overwrite here,
// cause this value might be queried by hash later
batch.write_with_cache(DB_COL_TRACE, &mut *traces, request.block_hash, request.traces, CacheUpdatePolicy::Overwrite);
// note_used must be called after locking traces to avoid cache/traces deadlock on garbage collection
self.note_used(CacheID::Trace(request.block_hash.clone()));
}
let chain = BloomGroupChain::new(self.bloom_config, self);
let trace_blooms = chain.replace(&replaced_range, enacted_blooms);
let blooms_to_insert = trace_blooms.into_iter()

View File

@@ -25,7 +25,7 @@ use std::mem;
use std::collections::VecDeque;
/// Blockchain Filter.
#[derive(Binary)]
#[derive(Binary, Debug, PartialEq)]
pub struct Filter {
/// Blockchain will be searched from this block.
pub from_block: BlockID,

View File

@@ -20,7 +20,7 @@ use util::numbers::*;
use std::ops::Deref;
use util::rlp::*;
use util::sha3::*;
use util::{UtilError, CryptoError, Bytes, Signature, Secret, ec};
use util::{UtilError, CryptoError, Bytes, Signature, Secret, Public, ec};
use std::cell::*;
use error::*;
use evm::Schedule;
@@ -75,8 +75,8 @@ pub struct Transaction {
impl Transaction {
/// Append object with a without signature into RLP stream
pub fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream) {
s.begin_list(6);
pub fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream, network_id: Option<u8>) {
s.begin_list(if let None = network_id { 6 } else { 9 });
s.append(&self.nonce);
s.append(&self.gas_price);
s.append(&self.gas);
@@ -86,6 +86,11 @@ impl Transaction {
};
s.append(&self.value);
s.append(&self.data);
if let Some(n) = network_id {
s.append(&n);
s.append(&0u8);
s.append(&0u8);
}
}
}
@@ -102,7 +107,7 @@ impl From<ethjson::state::Transaction> for SignedTransaction {
},
value: t.value.into(),
data: t.data.into(),
}.sign(&t.secret.into())
}.sign(&t.secret.into(), None)
}
}
@@ -132,26 +137,27 @@ impl From<ethjson::transaction::Transaction> for SignedTransaction {
impl Transaction {
/// The message hash of the transaction.
pub fn hash(&self) -> H256 {
pub fn hash(&self, network_id: Option<u8>) -> H256 {
let mut stream = RlpStream::new();
self.rlp_append_unsigned_transaction(&mut stream);
self.rlp_append_unsigned_transaction(&mut stream, network_id);
stream.out().sha3()
}
/// Signs the transaction as coming from `sender`.
pub fn sign(self, secret: &Secret) -> SignedTransaction {
let sig = ec::sign(secret, &self.hash()).unwrap();
self.with_signature(sig)
pub fn sign(self, secret: &Secret, network_id: Option<u8>) -> SignedTransaction {
let sig = ec::sign(secret, &self.hash(network_id))
.expect("data is valid and context has signing capabilities; qed");
self.with_signature(sig, network_id)
}
/// Signs the transaction with signature.
pub fn with_signature(self, sig: H520) -> SignedTransaction {
pub fn with_signature(self, sig: Signature, network_id: Option<u8>) -> SignedTransaction {
let (r, s, v) = sig.to_rsv();
SignedTransaction {
unsigned: self,
r: r,
s: s,
v: v + 27,
v: v + if let Some(n) = network_id { 35 + n * 2 } else { 27 },
hash: Cell::new(None),
sender: Cell::new(None),
}
@@ -201,7 +207,8 @@ impl Transaction {
pub struct SignedTransaction {
/// Plain Transaction.
unsigned: Transaction,
/// The V field of the signature, either 27 or 28; helps describe the point on the curve.
/// The V field of the signature; the LS bit described which half of the curve our point falls
/// in. The MS bits describe which network this transaction is for. If 27/28, its for all networks.
v: u8,
/// The R field of the signature; helps describe the point on the curve.
r: U256,
@@ -257,7 +264,7 @@ impl Encodable for SignedTransaction {
impl SignedTransaction {
/// Append object with a signature into RLP stream
pub fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) {
fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) {
s.begin_list(9);
s.append(&self.nonce);
s.append(&self.gas_price);
@@ -286,8 +293,16 @@ impl SignedTransaction {
}
}
/// 0 is `v` is 27, 1 if 28, and 4 otherwise.
pub fn standard_v(&self) -> u8 { match self.v { 27 => 0, 28 => 1, _ => 4 } }
/// 0 if `v` would have been 27 under "Electrum" notation, 1 if 28 or 4 if invalid.
pub fn standard_v(&self) -> u8 { match self.v { v if v == 27 || v == 28 || v > 36 => (v - 1) % 2, _ => 4 } }
/// The network ID, or `None` if this is a global transaction.
pub fn network_id(&self) -> Option<u8> {
match self.v {
v if v > 36 => Some((v - 35) / 2),
_ => None,
}
}
/// Construct a signature object from the sig.
pub fn signature(&self) -> Signature { Signature::from_rsv(&From::from(&self.r), &From::from(&self.s), self.standard_v()) }
@@ -303,28 +318,38 @@ impl SignedTransaction {
/// Returns transaction sender.
pub fn sender(&self) -> Result<Address, Error> {
let sender = self.sender.get();
match sender {
Some(s) => Ok(s),
None => {
let s = Address::from(try!(ec::recover(&self.signature(), &self.unsigned.hash())).sha3());
self.sender.set(Some(s));
Ok(s)
}
}
let sender = self.sender.get();
match sender {
Some(s) => Ok(s),
None => {
let s = Address::from(try!(self.public_key()).sha3());
self.sender.set(Some(s));
Ok(s)
}
}
}
/// Returns the public key of the sender.
pub fn public_key(&self) -> Result<Public, Error> {
Ok(try!(ec::recover(&self.signature(), &self.unsigned.hash(self.network_id()))))
}
/// Do basic validation, checking for valid signature and minimum gas,
// TODO: consider use in block validation.
#[cfg(test)]
#[cfg(feature = "json-tests")]
pub fn validate(self, schedule: &Schedule, require_low: bool) -> Result<SignedTransaction, Error> {
pub fn validate(self, schedule: &Schedule, require_low: bool, allow_network_id_of_one: bool) -> Result<SignedTransaction, Error> {
if require_low && !ec::is_low_s(&self.s) {
return Err(Error::Util(UtilError::Crypto(CryptoError::InvalidSignature)));
}
match self.network_id() {
None => {},
Some(1) if allow_network_id_of_one => {},
_ => return Err(TransactionError::InvalidNetworkId.into()),
}
try!(self.sender());
if self.gas < U256::from(self.gas_required(&schedule)) {
Err(From::from(TransactionError::InvalidGasLimit(::util::OutOfBounds{min: Some(U256::from(self.gas_required(&schedule))), max: None, found: self.gas})))
Err(TransactionError::InvalidGasLimit(::util::OutOfBounds{min: Some(U256::from(self.gas_required(&schedule))), max: None, found: self.gas}).into())
} else {
Ok(self)
}
@@ -364,6 +389,7 @@ fn sender_test() {
} else { panic!(); }
assert_eq!(t.value, U256::from(0x0au64));
assert_eq!(t.sender().unwrap(), address_from_hex("0f65fe9276bc9a24ae7083ae28e2660ef72df99e"));
assert_eq!(t.network_id(), None);
}
#[test]
@@ -376,8 +402,9 @@ fn signing() {
gas: U256::from(50_000),
value: U256::from(1),
data: b"Hello!".to_vec()
}.sign(&key.secret());
}.sign(&key.secret(), None);
assert_eq!(Address::from(key.public().sha3()), t.sender().unwrap());
assert_eq!(t.network_id(), None);
}
#[test]
@@ -391,7 +418,47 @@ fn fake_signing() {
data: b"Hello!".to_vec()
}.fake_sign(Address::from(0x69));
assert_eq!(Address::from(0x69), t.sender().unwrap());
assert_eq!(t.network_id(), None);
let t = t.clone();
assert_eq!(Address::from(0x69), t.sender().unwrap());
assert_eq!(t.network_id(), None);
}
#[test]
fn should_recover_from_network_specific_signing() {
let key = ::util::crypto::KeyPair::create().unwrap();
let t = Transaction {
action: Action::Create,
nonce: U256::from(42),
gas_price: U256::from(3000),
gas: U256::from(50_000),
value: U256::from(1),
data: b"Hello!".to_vec()
}.sign(&key.secret(), Some(69));
assert_eq!(Address::from(key.public().sha3()), t.sender().unwrap());
assert_eq!(t.network_id(), Some(69));
}
#[test]
fn should_agree_with_vitalik() {
use rustc_serialize::hex::FromHex;
let test_vector = |tx_data: &str, address: &'static str| {
let signed: SignedTransaction = decode(&FromHex::from_hex(tx_data).unwrap());
signed.check_low_s().unwrap();
assert_eq!(signed.sender().unwrap(), address.into());
flushln!("networkid: {:?}", signed.network_id());
};
test_vector("f864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", "0xf0f6f18bca1b28cd68e4357452947e021241e9ce")
test_vector("f864018504a817c80182a410943535353535353535353535353535353535353535018025a0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bcaa0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", "0x23ef145a395ea3fa3deb533b8a9e1b4c6c25d112")
test_vector("f864028504a817c80282f618943535353535353535353535353535353535353535088025a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", "0x2e485e0c23b4c3c542628a5f672eeab0ad4888be")
test_vector("f865038504a817c803830148209435353535353535353535353535353535353535351b8025a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", "0x82a88539669a3fd524d669e858935de5e5410cf0")
test_vector("f865048504a817c80483019a28943535353535353535353535353535353535353535408025a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", "0xf9358f2538fd5ccfeb848b64a96b743fcc930554")
test_vector("f865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", "0xa8f7aba377317440bc5b26198a363ad22af1f3a4")
test_vector("f866068504a817c80683023e3894353535353535353535353535353535353535353581d88025a06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2fa06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", "0xf1f571dc362a0e5b2696b8e775f8491d3e50de35")
test_vector("f867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", "0xd37922162ab7cea97c97a87551ed02c9a38b7332")
test_vector("f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", "0x9bddad43f934d313c2b79ca28a432dd2b7281029")
test_vector("f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", "0x3c24d7329e92f84f08556ceb6df1cdb0104ca49f")
}

View File

@@ -360,7 +360,7 @@ mod tests {
gas: U256::from(30_000),
gas_price: U256::from(40_000),
nonce: U256::one()
}.sign(keypair.secret());
}.sign(keypair.secret(), None);
let tr2 = Transaction {
action: Action::Create,
@@ -369,7 +369,7 @@ mod tests {
gas: U256::from(30_000),
gas_price: U256::from(40_000),
nonce: U256::from(2)
}.sign(keypair.secret());
}.sign(keypair.secret(), None);
let good_transactions = [ tr1.clone(), tr2.clone() ];

View File

@@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use keccak::Keccak256;
use super::{KeyPair, Error, Generator, Secret};
use super::{KeyPair, Error, Generator};
/// Simple brainwallet.
pub struct Brain(String);
@@ -38,9 +38,9 @@ impl Generator for Brain {
match i > 16384 {
false => i += 1,
true => {
let result = KeyPair::from_secret(Secret::from(secret.clone()));
if result.is_ok() {
return result
let result = KeyPair::from_secret(secret.clone().into());
if result.as_ref().ok().map_or(false, |r| r.address()[0] == 0) {
return result;
}
},
}

View File

@@ -23,7 +23,7 @@ use account::{Version, Cipher, Kdf, Aes128Ctr, Pbkdf2, Prf};
#[derive(Debug, PartialEq, Clone)]
pub struct Crypto {
pub cipher: Cipher,
pub ciphertext: [u8; 32],
pub ciphertext: Vec<u8>,
pub kdf: Kdf,
pub mac: [u8; 32],
}
@@ -95,7 +95,7 @@ impl Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: iv,
}),
ciphertext: ciphertext,
ciphertext: ciphertext.to_vec(),
kdf: Kdf::Pbkdf2(Pbkdf2 {
dklen: crypto::KEY_LENGTH as u32,
salt: salt,
@@ -107,6 +107,10 @@ impl Crypto {
}
pub fn secret(&self, password: &str) -> Result<Secret, Error> {
if self.ciphertext.len() > 32 {
return Err(Error::InvalidSecret);
}
let (derived_left_bits, derived_right_bits) = match self.kdf {
Kdf::Pbkdf2(ref params) => crypto::derive_key_iterations(password, &params.salt, params.c),
Kdf::Scrypt(ref params) => crypto::derive_key_scrypt(password, &params.salt, params.n, params.p, params.r),
@@ -122,7 +126,8 @@ impl Crypto {
match self.cipher {
Cipher::Aes128Ctr(ref params) => {
crypto::aes::decrypt(&derived_left_bits, &params.iv, &self.ciphertext, &mut *secret)
let from = 32 - self.ciphertext.len();
crypto::aes::decrypt(&derived_left_bits, &params.iv, &self.ciphertext, &mut (&mut *secret)[from..])
},
}

View File

@@ -76,15 +76,14 @@ impl DiskDirectory {
.map(|entry| entry.path())
.collect::<Vec<PathBuf>>();
let files: Result<Vec<_>, _> = paths.iter()
.map(fs::File::open)
.collect();
let files = try!(files);
files.into_iter()
.map(json::KeyFile::load)
.zip(paths.into_iter())
paths
.iter()
.map(|p| (
fs::File::open(p)
.map_err(Error::from)
.and_then(|r| json::KeyFile::load(r).map_err(|e| Error::Custom(format!("{:?}", e)))),
p
))
.map(|(file, path)| match file {
Ok(file) => Ok((path.clone(), SafeAccount::from_file(
file, path.file_name().and_then(|n| n.to_str()).expect("Keys have valid UTF8 names only.").to_owned()
@@ -163,7 +162,8 @@ mod test {
#[test]
fn should_create_new_account() {
// given
let dir = env::temp_dir();
let mut dir = env::temp_dir();
dir.push("ethstore_should_create_new_account");
let keypair = Random.generate().unwrap();
let password = "hello world";
let directory = DiskDirectory::create(dir.clone()).unwrap();

View File

@@ -0,0 +1,58 @@
use std::{ops, str};
use serde::{Deserialize, Deserializer, Error, Serialize, Serializer};
use rustc_serialize::hex::{ToHex, FromHex, FromHexError};
#[derive(Debug, PartialEq)]
pub struct Bytes(Vec<u8>);
impl ops::Deref for Bytes {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Deserialize for Bytes {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
where D: Deserializer
{
let s = try!(String::deserialize(deserializer));
let data = try!(s.from_hex().map_err(|e| Error::custom(format!("Invalid hex value {}", e))));
Ok(Bytes(data))
}
}
impl Serialize for Bytes {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer {
serializer.serialize_str(&self.0.to_hex())
}
}
impl str::FromStr for Bytes {
type Err = FromHexError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
s.from_hex().map(Bytes)
}
}
impl From<&'static str> for Bytes {
fn from(s: &'static str) -> Self {
s.parse().expect(&format!("invalid string literal for {}: '{}'", stringify!(Self), s))
}
}
impl From<Vec<u8>> for Bytes {
fn from(v: Vec<u8>) -> Self {
Bytes(v)
}
}
impl From<Bytes> for Vec<u8> {
fn from(b: Bytes) -> Self {
b.0
}
}

View File

@@ -17,12 +17,14 @@
use serde::{Deserialize, Deserializer, Serialize, Serializer, Error};
use serde::de::{Visitor, MapVisitor};
use serde::ser;
use super::{Cipher, CipherSer, CipherSerParams, Kdf, KdfSer, KdfSerParams, H256};
use super::{Cipher, CipherSer, CipherSerParams, Kdf, KdfSer, KdfSerParams, H256, Bytes};
pub type CipherText = Bytes;
#[derive(Debug, PartialEq)]
pub struct Crypto {
pub cipher: Cipher,
pub ciphertext: H256,
pub ciphertext: CipherText,
pub kdf: Kdf,
pub mac: H256,
}

View File

@@ -14,9 +14,7 @@
// 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::fmt;
use std::ops;
use std::str::FromStr;
use std::{ops, fmt, str};
use rustc_serialize::hex::{FromHex, ToHex};
use serde::{Serialize, Serializer, Deserialize, Deserializer, Error as SerdeError};
use serde::de::Visitor;
@@ -65,7 +63,7 @@ macro_rules! impl_hash {
type Value = $name;
fn visit_str<E>(&mut self, value: &str) -> Result<Self::Value, E> where E: SerdeError {
FromStr::from_str(value).map_err(SerdeError::custom)
value.parse().map_err(SerdeError::custom)
}
fn visit_string<E>(&mut self, value: String) -> Result<Self::Value, E> where E: SerdeError {
@@ -77,7 +75,7 @@ macro_rules! impl_hash {
}
}
impl FromStr for $name {
impl str::FromStr for $name {
type Err = Error;
fn from_str(value: &str) -> Result<Self, Self::Err> {
@@ -92,6 +90,12 @@ macro_rules! impl_hash {
}
}
impl From<&'static str> for $name {
fn from(s: &'static str) -> Self {
s.parse().expect(&format!("invalid string literal for {}: '{}'", stringify!(Self), s))
}
}
impl From<[u8; $size]> for $name {
fn from(bytes: [u8; $size]) -> Self {
$name(bytes)

View File

@@ -15,8 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Universaly unique identifier.
use std::str::FromStr;
use std::fmt;
use std::{fmt, str};
use rustc_serialize::hex::{ToHex, FromHex};
use serde::{Deserialize, Serialize, Deserializer, Serializer, Error as SerdeError};
use serde::de::Visitor;
@@ -73,7 +72,7 @@ fn copy_into(from: &str, into: &mut [u8]) -> Result<(), Error> {
Ok(())
}
impl FromStr for UUID {
impl str::FromStr for UUID {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
@@ -95,6 +94,12 @@ impl FromStr for UUID {
}
}
impl From<&'static str> for UUID {
fn from(s: &'static str) -> Self {
s.parse().expect(&format!("invalid string literal for {}: '{}'", stringify!(Self), s))
}
}
impl Serialize for UUID {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer {
@@ -116,7 +121,7 @@ impl Visitor for UUIDVisitor {
type Value = UUID;
fn visit_str<E>(&mut self, value: &str) -> Result<Self::Value, E> where E: SerdeError {
UUID::from_str(value).map_err(SerdeError::custom)
value.parse().map_err(SerdeError::custom)
}
fn visit_string<E>(&mut self, value: String) -> Result<Self::Value, E> where E: SerdeError {
@@ -126,19 +131,18 @@ impl Visitor for UUIDVisitor {
#[cfg(test)]
mod tests {
use std::str::FromStr;
use super::UUID;
#[test]
fn uuid_from_str() {
let uuid = UUID::from_str("3198bc9c-6672-5ab3-d995-4942343ae5b6").unwrap();
let uuid: UUID = "3198bc9c-6672-5ab3-d995-4942343ae5b6".into();
assert_eq!(uuid, UUID::from([0x31, 0x98, 0xbc, 0x9c, 0x66, 0x72, 0x5a, 0xb3, 0xd9, 0x95, 0x49, 0x42, 0x34, 0x3a, 0xe5, 0xb6]));
}
#[test]
fn uuid_from_and_to_str() {
let from = "3198bc9c-6672-5ab3-d995-4942343ae5b6";
let uuid = UUID::from_str(from).unwrap();
let uuid: UUID = from.into();
let to: String = uuid.into();
assert_eq!(from, &to);
}

View File

@@ -98,7 +98,7 @@ impl Visitor for KeyFileVisitor {
Some(KeyFileField::Version) => { version = Some(try!(visitor.visit_value())); }
Some(KeyFileField::Crypto) => { crypto = Some(try!(visitor.visit_value())); }
Some(KeyFileField::Address) => { address = Some(try!(visitor.visit_value())); }
Some(KeyFileField::Name) => { name = visitor.visit_value().ok(); } // ignore anyhing that is not a string to be permissive.
Some(KeyFileField::Name) => { name = visitor.visit_value().ok(); } // ignore anyhing that is not a string to be permissive.
Some(KeyFileField::Meta) => { meta = visitor.visit_value().ok(); } // ignore anyhing that is not a string to be permissive.
None => { break; }
}
@@ -153,7 +153,7 @@ impl KeyFile {
mod tests {
use std::str::FromStr;
use serde_json;
use json::{KeyFile, UUID, Version, Crypto, Cipher, Aes128Ctr, Kdf, Scrypt, H128, H160, H256};
use json::{KeyFile, UUID, Version, Crypto, Cipher, Aes128Ctr, Kdf, Scrypt};
#[test]
fn basic_keyfile() {
@@ -185,20 +185,20 @@ mod tests {
let expected = KeyFile {
id: UUID::from_str("8777d9f6-7860-4b9b-88b7-0b57ee6b3a73").unwrap(),
version: Version::V3,
address: H160::from_str("6edddfc6349aff20bc6467ccf276c5b52487f7a8").unwrap(),
address: "6edddfc6349aff20bc6467ccf276c5b52487f7a8".into(),
crypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: H128::from_str("b5a7ec855ec9e2c405371356855fec83").unwrap(),
iv: "b5a7ec855ec9e2c405371356855fec83".into(),
}),
ciphertext: H256::from_str("7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc").unwrap(),
ciphertext: "7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc".into(),
kdf: Kdf::Scrypt(Scrypt {
n: 262144,
dklen: 32,
p: 1,
r: 8,
salt: H256::from_str("1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209").unwrap(),
salt: "1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209".into(),
}),
mac: H256::from_str("46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f").unwrap(),
mac: "46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f".into(),
},
name: Some("Test".to_owned()),
meta: Some("{}".to_owned()),
@@ -234,22 +234,22 @@ mod tests {
}"#;
let expected = KeyFile {
id: UUID::from_str("8777d9f6-7860-4b9b-88b7-0b57ee6b3a73").unwrap(),
id: "8777d9f6-7860-4b9b-88b7-0b57ee6b3a73".into(),
version: Version::V3,
address: H160::from_str("6edddfc6349aff20bc6467ccf276c5b52487f7a8").unwrap(),
address: "6edddfc6349aff20bc6467ccf276c5b52487f7a8".into(),
crypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: H128::from_str("b5a7ec855ec9e2c405371356855fec83").unwrap(),
iv: "b5a7ec855ec9e2c405371356855fec83".into(),
}),
ciphertext: H256::from_str("7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc").unwrap(),
ciphertext: "7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc".into(),
kdf: Kdf::Scrypt(Scrypt {
n: 262144,
dklen: 32,
p: 1,
r: 8,
salt: H256::from_str("1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209").unwrap(),
salt: "1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209".into(),
}),
mac: H256::from_str("46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f").unwrap(),
mac: "46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f".into(),
},
name: None,
meta: None,
@@ -262,22 +262,22 @@ mod tests {
#[test]
fn to_and_from_json() {
let file = KeyFile {
id: UUID::from_str("8777d9f6-7860-4b9b-88b7-0b57ee6b3a73").unwrap(),
id: "8777d9f6-7860-4b9b-88b7-0b57ee6b3a73".into(),
version: Version::V3,
address: H160::from_str("6edddfc6349aff20bc6467ccf276c5b52487f7a8").unwrap(),
address: "6edddfc6349aff20bc6467ccf276c5b52487f7a8".into(),
crypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: H128::from_str("b5a7ec855ec9e2c405371356855fec83").unwrap(),
iv: "b5a7ec855ec9e2c405371356855fec83".into(),
}),
ciphertext: H256::from_str("7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc").unwrap(),
ciphertext: "7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc".into(),
kdf: Kdf::Scrypt(Scrypt {
n: 262144,
dklen: 32,
p: 1,
r: 8,
salt: H256::from_str("1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209").unwrap(),
salt: "1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209".into(),
}),
mac: H256::from_str("46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f").unwrap(),
mac: "46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f".into(),
},
name: Some("Test".to_owned()),
meta: None,

View File

@@ -1,3 +1,4 @@
mod bytes;
mod cipher;
mod crypto;
mod error;
@@ -8,8 +9,9 @@ mod key_file;
mod presale;
mod version;
pub use self::bytes::Bytes;
pub use self::cipher::{Cipher, CipherSer, CipherSerParams, Aes128Ctr};
pub use self::crypto::Crypto;
pub use self::crypto::{Crypto, CipherText};
pub use self::error::Error;
pub use self::hash::{H128, H160, H256};
pub use self::id::UUID;

View File

@@ -1,30 +1,8 @@
use std::io::Read;
use std::ops::Deref;
use serde_json;
use serde::{Deserialize, Deserializer, Error};
use rustc_serialize::hex::FromHex;
use super::{H160};
use super::{H160, Bytes};
#[derive(Debug, PartialEq)]
pub struct Encseed(Vec<u8>);
impl Deref for Encseed {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Deserialize for Encseed {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
where D: Deserializer
{
let s = try!(String::deserialize(deserializer));
let data = try!(s.from_hex().map_err(|e| Error::custom(format!("Invalid hex value {}", e))));
Ok(Encseed(data))
}
}
pub type Encseed = Bytes;
#[derive(Debug, PartialEq, Deserialize)]
pub struct PresaleWallet {
@@ -43,8 +21,7 @@ impl PresaleWallet {
mod tests {
use std::str::FromStr;
use serde_json;
use rustc_serialize::hex::FromHex;
use json::{PresaleWallet, H160, Encseed};
use json::{PresaleWallet, H160};
#[test]
fn presale_wallet() {
@@ -57,7 +34,7 @@ mod tests {
} "#;
let expected = PresaleWallet {
encseed: Encseed("137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066".from_hex().unwrap()),
encseed: "137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066".into(),
address: H160::from_str("ede84640d1a1d3e06902048e67aa7db8d52c2ce1").unwrap(),
};
@@ -77,7 +54,7 @@ mod tests {
} "#;
let expected = PresaleWallet {
encseed: Encseed("137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0d".from_hex().unwrap()),
encseed: "137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0d".into(),
address: H160::from_str("ede84640d1a1d3e06902048e67aa7db8d52c2ce1").unwrap(),
};

View File

@@ -19,9 +19,8 @@ extern crate ethstore;
mod util;
use std::str::FromStr;
use ethstore::{SecretStore, EthStore};
use ethstore::ethkey::{Random, Generator, Secret, Address};
use ethstore::ethkey::{Random, Generator, Secret, KeyPair, verify_address};
use ethstore::dir::DiskDirectory;
use util::TransientDir;
@@ -103,14 +102,21 @@ fn pat_path() -> &'static str {
}
}
fn ciphertext_path() -> &'static str {
match ::std::fs::metadata("ethstore") {
Ok(_) => "ethstore/tests/res/ciphertext",
Err(_) => "tests/res/ciphertext",
}
}
#[test]
fn secret_store_laod_geth_files() {
let dir = DiskDirectory::at(test_path());
let store = EthStore::open(Box::new(dir)).unwrap();
assert_eq!(store.accounts().unwrap(), vec![
Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap(),
Address::from_str("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf").unwrap(),
Address::from_str("63121b431a52f8043c16fcf0d1df9cb7b5f66649").unwrap(),
"3f49624084b67849c7b4e805c5988c21a430f9d9".parse().unwrap(),
"5ba4dcf897e97c2bdf8315b9ef26c13c085988cf".parse().unwrap(),
"63121b431a52f8043c16fcf0d1df9cb7b5f66649".parse().unwrap(),
]);
}
@@ -119,9 +125,30 @@ fn secret_store_load_pat_files() {
let dir = DiskDirectory::at(pat_path());
let store = EthStore::open(Box::new(dir)).unwrap();
assert_eq!(store.accounts().unwrap(), vec![
Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap(),
Address::from_str("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf").unwrap(),
"3f49624084b67849c7b4e805c5988c21a430f9d9".parse().unwrap(),
"5ba4dcf897e97c2bdf8315b9ef26c13c085988cf".parse().unwrap(),
]);
}
#[test]
fn test_decrypting_files_with_short_ciphertext() {
// 31e9d1e6d844bd3a536800ef8d8be6a9975db509, 30
let kp1 = KeyPair::from_secret("000081c29e8142bb6a81bef5a92bda7a8328a5c85bb2f9542e76f9b0f94fc018".parse().unwrap()).unwrap();
// d1e64e5480bfaf733ba7d48712decb8227797a4e , 31
let kp2 = KeyPair::from_secret("00fa7b3db73dc7dfdf8c5fbdb796d741e4488628c41fc4febd9160a866ba0f35".parse().unwrap()).unwrap();
let dir = DiskDirectory::at(ciphertext_path());
let store = EthStore::open(Box::new(dir)).unwrap();
let accounts = store.accounts().unwrap();
assert_eq!(accounts, vec![
"31e9d1e6d844bd3a536800ef8d8be6a9975db509".parse().unwrap(),
"d1e64e5480bfaf733ba7d48712decb8227797a4e".parse().unwrap(),
]);
let message = Default::default();
let s1 = store.sign(&accounts[0], "foo", &message).unwrap();
let s2 = store.sign(&accounts[1], "foo", &message).unwrap();
assert!(verify_address(&accounts[0], &s1, &message).unwrap());
assert!(verify_address(&kp1.address(), &s1, &message).unwrap());
assert!(verify_address(&kp2.address(), &s2, &message).unwrap());
}

View File

@@ -0,0 +1,21 @@
{
"address" : "31e9d1e6d844bd3a536800ef8d8be6a9975db509",
"crypto" : {
"cipher" : "aes-128-ctr",
"cipherparams" : {
"iv" : "3ca92af36ad7c2cd92454c59cea5ef00"
},
"ciphertext" : "108b7d34f3442fc26ab1ab90ca91476ba6bfa8c00975a49ef9051dc675aa",
"kdf" : "scrypt",
"kdfparams" : {
"dklen" : 32,
"n" : 2,
"r" : 8,
"p" : 1,
"salt" : "d0769e608fb86cda848065642a9c6fa046845c928175662b8e356c77f914cd3b"
},
"mac" : "75d0e6759f7b3cefa319c3be41680ab6beea7d8328653474bd06706d4cc67420"
},
"id" : "a37e1559-5955-450d-8075-7b8931b392b2",
"version" : 3
}

View File

@@ -0,0 +1,21 @@
{
"address" : "d1e64e5480bfaf733ba7d48712decb8227797a4e",
"crypto" : {
"cipher" : "aes-128-ctr",
"cipherparams" : {
"iv" : "e0c41130a323adc1446fc82f724bca2f"
},
"ciphertext" : "9517cd5bdbe69076f9bf5057248c6c050141e970efa36ce53692d5d59a3984",
"kdf" : "scrypt",
"kdfparams" : {
"dklen" : 32,
"n" : 2,
"r" : 8,
"p" : 1,
"salt" : "711f816911c92d649fb4c84b047915679933555030b3552c1212609b38208c63"
},
"mac" : "d5e116151c6aa71470e67a7d42c9620c75c4d23229847dcc127794f0732b0db5"
},
"id" : "fecfc4ce-e956-48fd-953b-30f8b52ed66c",
"version" : 3
}

View File

@@ -48,6 +48,14 @@ impl Ext for FakeExt {
unimplemented!();
}
fn exists_and_not_null(&self, address: &Address) -> bool {
unimplemented!();
}
fn origin_balance(&self) -> U256 {
unimplemented!();
}
fn balance(&self, _address: &Address) -> U256 {
unimplemented!();
}

View File

@@ -49,7 +49,7 @@ include!(concat!(env!("OUT_DIR"), "/lib.rs"));
include!("lib.rs.in");
#[cfg(feature = "with-syntex")]
pub fn register(reg: &mut syntex::Registry) {
pub fn register_cleaner(reg: &mut syntex::Registry) {
use syntax::{ast, fold};
#[cfg(feature = "with-syntex")]
@@ -59,6 +59,7 @@ pub fn register(reg: &mut syntex::Registry) {
fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
match attr.node.value.node {
ast::MetaItemKind::List(ref n, _) if n == &"ipc" => { return None; }
ast::MetaItemKind::Word(ref n) if n == &"ipc" => { return None; }
_ => {}
}
@@ -73,19 +74,24 @@ pub fn register(reg: &mut syntex::Registry) {
fold::Folder::fold_crate(&mut StripAttributeFolder, krate)
}
reg.add_post_expansion_pass(strip_attributes);
}
#[cfg(feature = "with-syntex")]
pub fn register(reg: &mut syntex::Registry) {
reg.add_attr("feature(custom_derive)");
reg.add_attr("feature(custom_attribute)");
reg.add_decorator("derive_Ipc", codegen::expand_ipc_implementation);
reg.add_decorator("ipc", codegen::expand_ipc_implementation);
reg.add_decorator("derive_Binary", serialization::expand_serialization_implementation);
reg.add_post_expansion_pass(strip_attributes);
register_cleaner(reg);
}
#[cfg(not(feature = "with-syntex"))]
pub fn register(reg: &mut rustc_plugin::Registry) {
reg.register_syntax_extension(
syntax::parse::token::intern("derive_Ipc"),
syntax::parse::token::intern("ipc"),
syntax::ext::base::MultiDecorator(
Box::new(codegen::expand_ipc_implementation)));
reg.register_syntax_extension(
@@ -133,6 +139,30 @@ pub fn derive_ipc(src_path: &str) -> Result<(), Error> {
Ok(())
}
pub fn cleanup_ipc(src_path: &str) -> Result<(), Error> {
use std::env;
use std::path::{Path, PathBuf};
let out_dir = env::var_os("OUT_DIR").unwrap();
let file_name = try!(PathBuf::from(src_path).file_name().ok_or(Error::InvalidFileName).map(|val| val.to_str().unwrap().to_owned()));
let mut registry = syntex::Registry::new();
register_cleaner(&mut registry);
if let Err(_) = registry.expand("", &Path::new(src_path), &Path::new(&out_dir).join(&file_name))
{
// will be reported by compiler
return Err(Error::ExpandFailure)
}
Ok(())
}
pub fn derive_ipc_cond(src_path: &str, cond: bool) -> Result<(), Error> {
if cond {
derive_ipc(src_path)
}
else {
cleanup_ipc(src_path)
}
}
pub fn derive_binary(src_path: &str) -> Result<(), Error> {
use std::env;
use std::path::{Path, PathBuf};

View File

@@ -34,7 +34,7 @@ pub struct HypervisorService {
check_list: RwLock<HashMap<IpcModuleId, bool>>,
}
#[derive(Ipc)]
#[ipc]
impl HypervisorService {
fn module_ready(&self, module_id: u64) -> bool {
let mut check_list = self.check_list.write().unwrap();

View File

@@ -36,7 +36,7 @@ impl IpcConfig for DBWriter {}
#[derive(Binary)]
pub enum DBError { Write, Read }
#[derive(Ipc)]
#[ipc]
impl<L: Sized> DBWriter for DB<L> {
fn write(&self, data: Vec<u8>) -> Result<(), DBError> {
let mut writes = self.writes.write().unwrap();
@@ -51,7 +51,7 @@ impl<L: Sized> DBWriter for DB<L> {
}
}
#[derive(Ipc)]
#[ipc]
trait DBNotify {
fn notify(&self, a: u64, b: u64) -> bool;
}

View File

@@ -31,7 +31,7 @@ pub struct CustomData {
pub b: u64,
}
#[derive(Ipc)]
#[ipc]
impl Service {
fn commit(&self, f: u32) -> u32 {
let mut lock = self.commits.write().unwrap();

View File

@@ -21,7 +21,7 @@ use std::collections::VecDeque;
pub struct BadlyNamedService;
#[derive(Ipc)]
//#[derive(Ipc)]
#[ipc(client_ident="PrettyNamedClient")]
impl BadlyNamedService {
fn is_zero(&self, x: u64) -> bool {

View File

@@ -63,7 +63,7 @@ mod tests {
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit" : "0x",
"homesteadTransition" : "0x",
"daoHardforkTransition": "0xffffffffffffffff",
"daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000",
"daoHardforkAccounts": []

View File

@@ -40,8 +40,8 @@ pub struct EthashParams {
/// See main EthashParams docs.
pub registrar: Option<Address>,
/// See main EthashParams docs.
#[serde(rename="frontierCompatibilityModeLimit")]
pub frontier_compatibility_mode_limit: Option<Uint>,
#[serde(rename="homesteadTransition")]
pub homestead_transition: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="daoHardforkTransition")]
pub dao_hardfork_transition: Option<Uint>,
@@ -51,6 +51,37 @@ pub struct EthashParams {
/// See main EthashParams docs.
#[serde(rename="daoHardforkAccounts")]
pub dao_hardfork_accounts: Option<Vec<Address>>,
/// See main EthashParams docs.
#[serde(rename="difficultyHardforkTransition")]
pub difficulty_hardfork_transition: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="difficultyHardforkBoundDivisor")]
pub difficulty_hardfork_bound_divisor: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="bombDefuseTransition")]
pub bomb_defuse_transition: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="eip150Transition")]
pub eip150_transition: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="eip155Transition")]
pub eip155_transition: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="eip160Transition")]
pub eip160_transition: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="eip161abcTransition")]
pub eip161abc_transition: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="eip161dTransition")]
pub eip161d_transition: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="maxCodeSize")]
pub max_code_size: Option<Uint>,
}
/// Ethash engine deserialization.
@@ -75,7 +106,7 @@ mod tests {
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar": "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0x42",
"homesteadTransition": "0x42",
"daoHardforkTransition": "0x08",
"daoHardforkBeneficiary": "0xabcabcabcabcabcabcabcabcabcabcabcabcabca",
"daoHardforkAccounts": [
@@ -99,7 +130,15 @@ mod tests {
"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97",
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
]
],
"difficultyHardforkTransition": "0x59d9",
"difficultyHardforkBoundDivisor": "0x0200",
"bombDefuseTransition": "0x42",
"eip150Transition": "0x42",
"eip155Transition": "0x42",
"eip160Transition": "0x42",
"eip161abcTransition": "0x42",
"eip161dTransition": "0x42"
}
}"#;

View File

@@ -28,12 +28,17 @@ pub struct Params {
/// Maximum size of extra data.
#[serde(rename="maximumExtraDataSize")]
pub maximum_extra_data_size: Uint,
/// Network id.
#[serde(rename="networkID")]
pub network_id: Uint,
/// Minimum gas limit.
#[serde(rename="minGasLimit")]
pub min_gas_limit: Uint,
/// Network id.
#[serde(rename="networkID")]
pub network_id: Uint,
/// Name of the main ("eth") subprotocol.
#[serde(rename="subprotocolName")]
pub subprotocol_name: Option<String>,
/// Option fork block number to check.
#[serde(rename="forkBlock")]
pub fork_block: Option<Uint>,
@@ -50,7 +55,7 @@ mod tests {
#[test]
fn params_deserialization() {
let s = r#"{
"frontierCompatibilityModeLimit": "0x118c30",
"homesteadTransition": "0x118c30",
"maximumExtraDataSize": "0x20",
"networkID" : "0x1",
"minGasLimit": "0x1388",

View File

@@ -66,7 +66,7 @@ mod tests {
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit" : "0x",
"homesteadTransition" : "0x",
"daoHardforkTransition": "0xffffffffffffffff",
"daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000",
"daoHardforkAccounts": []
@@ -75,7 +75,7 @@ mod tests {
},
"params": {
"accountStartNonce": "0x0100000",
"frontierCompatibilityModeLimit": "0x789b0",
"homesteadTransition": "0x789b0",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x2",

View File

@@ -4,7 +4,7 @@
!define DESCRIPTION "Fast, light, robust Ethereum implementation"
!define VERSIONMAJOR 1
!define VERSIONMINOR 3
!define VERSIONBUILD 3
!define VERSIONBUILD 15
!addplugindir .\

View File

@@ -75,6 +75,7 @@ pub struct ImportBlockchain {
pub file_path: Option<String>,
pub format: Option<DataFormat>,
pub pruning: Pruning,
pub pruning_history: u64,
pub compaction: DatabaseCompactionProfile,
pub wal: bool,
pub mode: Mode,
@@ -91,6 +92,7 @@ pub struct ExportBlockchain {
pub file_path: Option<String>,
pub format: Option<DataFormat>,
pub pruning: Pruning,
pub pruning_history: u64,
pub compaction: DatabaseCompactionProfile,
pub wal: bool,
pub mode: Mode,
@@ -131,7 +133,7 @@ fn execute_import(cmd: ImportBlockchain) -> Result<String, String> {
try!(execute_upgrades(&cmd.dirs, genesis_hash, spec.fork_name.as_ref(), algorithm, cmd.compaction.compaction_profile()));
// prepare client config
let client_config = to_client_config(&cmd.cache_config, &cmd.dirs, genesis_hash, cmd.mode, cmd.tracing, cmd.pruning, cmd.compaction, cmd.wal, cmd.vm_type, "".into(), spec.fork_name.as_ref());
let client_config = to_client_config(&cmd.cache_config, &cmd.dirs, genesis_hash, cmd.mode, cmd.tracing, cmd.pruning, cmd.pruning_history, cmd.compaction, cmd.wal, cmd.vm_type, "".into(), spec.fork_name.as_ref());
// build client
let service = try!(ClientService::start(
@@ -242,7 +244,7 @@ fn execute_export(cmd: ExportBlockchain) -> Result<String, String> {
try!(execute_upgrades(&cmd.dirs, genesis_hash, spec.fork_name.as_ref(), algorithm, cmd.compaction.compaction_profile()));
// prepare client config
let client_config = to_client_config(&cmd.cache_config, &cmd.dirs, genesis_hash, cmd.mode, cmd.tracing, cmd.pruning, cmd.compaction, cmd.wal, VMType::default(), "".into(), spec.fork_name.as_ref());
let client_config = to_client_config(&cmd.cache_config, &cmd.dirs, genesis_hash, cmd.mode, cmd.tracing, cmd.pruning, cmd.pruning_history, cmd.compaction, cmd.wal, VMType::default(), "".into(), spec.fork_name.as_ref());
let service = try!(ClientService::start(
client_config,

View File

@@ -50,7 +50,7 @@ Operating Options:
[default: 3600].
--chain CHAIN Specify the blockchain type. CHAIN may be either a
JSON chain specification file or olympic, frontier,
homestead, mainnet, morden, classic or testnet
homestead, mainnet, ropsten, morden, classic or testnet
[default: homestead].
-d --db-path PATH Specify the database & configuration directory path
[default: $HOME/.parity].
@@ -126,7 +126,6 @@ API and Console Options:
--ipc-apis APIS Specify custom API set available via JSON-RPC over
IPC [default: web3,eth,net,ethcore,personal,traces,rpc].
--no-dapps Disable the Dapps server (e.g. status page).
--dapps-port PORT Specify the port portion of the Dapps server
[default: 8080].
--dapps-interface IP Specify the hostname portion of the Dapps
@@ -164,7 +163,7 @@ Sealing/Mining Options:
--work-queue-size ITEMS Specify the number of historical work packages
which are kept cached lest a solution is found for
them later. High values take more memory but result
in fewer unusable solutions [default: 20].
in fewer unusable solutions [default: 5].
--tx-gas-limit GAS Apply a limit of GAS as the maximum amount of gas
a single transaction may have for it to be mined.
--relay-set SET Set of transactions to relay. SET may be:
@@ -193,7 +192,17 @@ Sealing/Mining Options:
--extra-data STRING Specify a custom extra-data for authored blocks, no
more than 32 characters.
--tx-queue-size LIMIT Maximum amount of transactions in the queue (waiting
to be included in next block) [default: 1024].
to be included in next block) [default: 2048].
--tx-queue-strategy S Prioritization strategy used to order transactions
in the queue. S may be:
gas - Prioritize txs with low gas limit;
gas_price - Prioritize txs with high gas price;
gas_factor - Prioritize txs using gas price
and gas limit ratio [default: gas_factor].
--tx-queue-gas LIMIT Maximum amount of total gas for external transactions in
the queue. LIMIT can be either an amount of gas or
'auto' or 'off'. 'auto' sets the limit to be 20x
the current block gas limit. [default: auto].
--remove-solved Move solved blocks from the work package queue
instead of cloning them. This gives a slightly
faster import speed, but means that extra solutions
@@ -213,6 +222,8 @@ Footprint Options:
fast - maintain journal overlay. Fast but 50MB used.
auto - use the method most recently synced or
default to fast if none synced [default: auto].
--pruning-history NUM Set a number of recent states to keep when pruning
is active. [default: 64].
--cache-size-db MB Override database cache size [default: 64].
--cache-size-blocks MB Specify the prefered size of the blockchain cache in
megabytes [default: 8].
@@ -277,6 +288,7 @@ Legacy Options:
--etherbase ADDRESS Equivalent to --author ADDRESS.
--extradata STRING Equivalent to --extra-data STRING.
--cache MB Equivalent to --cache-size MB.
--no-dapps Disable the Dapps server (e.g. status page).
Miscellaneous Options:
-l --logging LOGGING Specify the logging level. Must conform to the same
@@ -317,8 +329,9 @@ pub struct Args {
pub flag_keys_iterations: u32,
pub flag_no_import_keys: bool,
pub flag_bootnodes: Option<String>,
pub flag_network_id: Option<String>,
pub flag_network_id: Option<usize>,
pub flag_pruning: String,
pub flag_pruning_history: u64,
pub flag_tracing: String,
pub flag_port: u16,
pub flag_min_peers: u16,
@@ -372,12 +385,14 @@ pub struct Args {
pub flag_gas_cap: String,
pub flag_extra_data: Option<String>,
pub flag_tx_queue_size: usize,
pub flag_tx_queue_strategy: String,
pub flag_tx_queue_gas: String,
pub flag_notify_work: Option<String>,
pub flag_logging: Option<String>,
pub flag_version: bool,
pub flag_from: String,
pub flag_to: String,
pub flag_at: String,
pub flag_at: String,
pub flag_format: Option<String>,
pub flag_jitvm: bool,
pub flag_log_file: Option<String>,
@@ -400,7 +415,7 @@ pub struct Args {
pub flag_rpccorsdomain: Option<String>,
pub flag_rpcapi: Option<String>,
pub flag_testnet: bool,
pub flag_networkid: Option<String>,
pub flag_networkid: Option<usize>,
pub flag_ipcdisable: bool,
pub flag_ipc_off: bool,
pub flag_jsonrpc_off: bool,

View File

@@ -25,13 +25,13 @@ use util::{Hashable, U256, Uint, Bytes, version_data, Secret, Address};
use util::log::Colour;
use ethsync::{NetworkConfiguration, is_valid_node_url};
use ethcore::client::{VMType, Mode};
use ethcore::miner::MinerOptions;
use ethcore::miner::{MinerOptions, PrioritizationStrategy};
use rpc::{IpcConfiguration, HttpConfiguration};
use ethcore_rpc::NetworkSettings;
use cache::CacheConfig;
use helpers::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_price, replace_home,
geth_ipc_path, parity_ipc_path, to_bootnodes, to_addresses, to_address};
geth_ipc_path, parity_ipc_path, to_bootnodes, to_addresses, to_address, to_gas_limit};
use params::{ResealPolicy, AccountsConfig, GasPricerConfig, MinerExtras};
use ethcore_logger::Config as LogConfig;
use dir::Directories;
@@ -73,6 +73,7 @@ impl Configuration {
pub fn into_command(self) -> Result<Cmd, String> {
let dirs = self.directories();
let pruning = try!(self.args.flag_pruning.parse());
let pruning_history = self.args.flag_pruning_history;
let vm_type = try!(self.vm_type());
let mode = try!(to_mode(&self.args.flag_mode, self.args.flag_mode_timeout, self.args.flag_mode_alarm));
let miner_options = try!(self.miner_options());
@@ -80,7 +81,7 @@ impl Configuration {
let http_conf = try!(self.http_config());
let ipc_conf = try!(self.ipc_config());
let net_conf = try!(self.net_config());
let network_id = try!(self.network_id());
let network_id = self.network_id();
let cache_config = self.cache_config();
let spec = try!(self.chain().parse());
let tracing = try!(self.args.flag_tracing.parse());
@@ -134,6 +135,7 @@ impl Configuration {
file_path: self.args.arg_file.clone(),
format: format,
pruning: pruning,
pruning_history: pruning_history,
compaction: compaction,
wal: wal,
mode: mode,
@@ -150,6 +152,7 @@ impl Configuration {
file_path: self.args.arg_file.clone(),
format: format,
pruning: pruning,
pruning_history: pruning_history,
compaction: compaction,
wal: wal,
mode: mode,
@@ -164,6 +167,7 @@ impl Configuration {
dirs: dirs,
spec: spec,
pruning: pruning,
pruning_history: pruning_history,
logger_config: logger_config,
mode: mode,
tracing: tracing,
@@ -180,6 +184,7 @@ impl Configuration {
dirs: dirs,
spec: spec,
pruning: pruning,
pruning_history: pruning_history,
logger_config: logger_config,
mode: mode,
tracing: tracing,
@@ -202,6 +207,7 @@ impl Configuration {
dirs: dirs,
spec: spec,
pruning: pruning,
pruning_history: pruning_history,
daemon: daemon,
logger_config: logger_config,
miner_options: miner_options,
@@ -288,7 +294,7 @@ impl Configuration {
fn chain(&self) -> String {
if self.args.flag_testnet {
"morden".to_owned()
"ropsten".to_owned()
} else {
self.args.flag_chain.clone()
}
@@ -319,6 +325,15 @@ impl Configuration {
Ok(cfg)
}
fn transaction_queue_strategy(&self) -> Result<PrioritizationStrategy, String> {
match self.args.flag_tx_queue_strategy.as_str() {
"gas" => Ok(PrioritizationStrategy::GasAndGasPrice),
"gas_price" => Ok(PrioritizationStrategy::GasPriceOnly),
"gas_factor" => Ok(PrioritizationStrategy::GasFactorAndGasPrice),
_ => Err(format!("Invalid queue strategy: {}", self.args.flag_tx_queue_strategy)),
}
}
fn miner_options(&self) -> Result<MinerOptions, String> {
let reseal = try!(self.args.flag_reseal_on_txs.parse::<ResealPolicy>());
@@ -332,6 +347,8 @@ impl Configuration {
None => U256::max_value(),
},
tx_queue_size: self.args.flag_tx_queue_size,
tx_queue_strategy: try!(self.transaction_queue_strategy()),
tx_queue_gas_limit: try!(to_gas_limit(&self.args.flag_tx_queue_gas)),
pending_set: try!(to_pending_set(&self.args.flag_relay_set)),
reseal_min_period: Duration::from_millis(self.args.flag_reseal_min_period),
work_queue_size: self.args.flag_work_queue_size,
@@ -448,12 +465,8 @@ impl Configuration {
Ok(ret)
}
fn network_id(&self) -> Result<Option<U256>, String> {
let net_id = self.args.flag_network_id.as_ref().or(self.args.flag_networkid.as_ref());
match net_id {
Some(id) => Ok(Some(try!(to_u256(id)))),
None => Ok(None),
}
fn network_id(&self) -> Option<usize> {
self.args.flag_network_id.or(self.args.flag_networkid)
}
fn rpc_apis(&self) -> String {
@@ -535,10 +548,10 @@ impl Configuration {
let dapps_path = replace_home(&self.args.flag_dapps_path);
let signer_path = replace_home(&self.args.flag_signer_path);
if self.args.flag_geth {
let geth_path = path::ethereum::default();
::std::fs::create_dir_all(geth_path.as_path()).unwrap_or_else(
|e| warn!("Failed to create '{}' for geth mode: {}", &geth_path.to_str().unwrap(), e));
if self.args.flag_geth && !cfg!(windows) {
let geth_root = if self.args.flag_testnet { path::ethereum::test() } else { path::ethereum::default() };
::std::fs::create_dir_all(geth_root.as_path()).unwrap_or_else(
|e| warn!("Failed to create '{}' for geth mode: {}", &geth_root.to_str().unwrap(), e));
}
Directories {
@@ -604,6 +617,7 @@ mod tests {
use docopt::Docopt;
use ethcore_rpc::NetworkSettings;
use ethcore::client::{VMType, BlockID};
use ethcore::miner::{MinerOptions, PrioritizationStrategy};
use helpers::{replace_home, default_network_config};
use run::RunCmd;
use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, DataFormat};
@@ -683,6 +697,7 @@ mod tests {
file_path: Some("blockchain.json".into()),
format: Default::default(),
pruning: Default::default(),
pruning_history: 64,
compaction: Default::default(),
wal: true,
mode: Default::default(),
@@ -702,6 +717,7 @@ mod tests {
dirs: Default::default(),
file_path: Some("blockchain.json".into()),
pruning: Default::default(),
pruning_history: 64,
format: Default::default(),
compaction: Default::default(),
wal: true,
@@ -723,6 +739,7 @@ mod tests {
dirs: Default::default(),
file_path: Some("blockchain.json".into()),
pruning: Default::default(),
pruning_history: 64,
format: Some(DataFormat::Hex),
compaction: Default::default(),
wal: true,
@@ -750,6 +767,7 @@ mod tests {
dirs: Default::default(),
spec: Default::default(),
pruning: Default::default(),
pruning_history: 64,
daemon: None,
logger_config: Default::default(),
miner_options: Default::default(),
@@ -777,6 +795,27 @@ mod tests {
}));
}
#[test]
fn should_parse_mining_options() {
// given
let mut mining_options = MinerOptions::default();
// when
let conf0 = parse(&["parity"]);
let conf1 = parse(&["parity", "--tx-queue-strategy", "gas_factor"]);
let conf2 = parse(&["parity", "--tx-queue-strategy", "gas_price"]);
let conf3 = parse(&["parity", "--tx-queue-strategy", "gas"]);
// then
assert_eq!(conf0.miner_options().unwrap(), mining_options);
mining_options.tx_queue_strategy = PrioritizationStrategy::GasFactorAndGasPrice;
assert_eq!(conf1.miner_options().unwrap(), mining_options);
mining_options.tx_queue_strategy = PrioritizationStrategy::GasPriceOnly;
assert_eq!(conf2.miner_options().unwrap(), mining_options);
mining_options.tx_queue_strategy = PrioritizationStrategy::GasAndGasPrice;
assert_eq!(conf3.miner_options().unwrap(), mining_options);
}
#[test]
fn should_parse_network_settings() {
// given
@@ -787,7 +826,7 @@ mod tests {
// then
assert_eq!(conf.network_settings(), NetworkSettings {
name: "testname".to_owned(),
chain: "morden".to_owned(),
chain: "ropsten".to_owned(),
network_port: 30303,
rpc_enabled: true,
rpc_interface: "local".to_owned(),

View File

@@ -22,7 +22,7 @@ use std::fs::File;
use util::{clean_0x, U256, Uint, Address, path, H256, CompactionProfile};
use util::journaldb::Algorithm;
use ethcore::client::{Mode, BlockID, Switch, VMType, DatabaseCompactionProfile, ClientConfig};
use ethcore::miner::PendingSet;
use ethcore::miner::{PendingSet, GasLimit};
use cache::CacheConfig;
use dir::Directories;
use params::Pruning;
@@ -94,6 +94,14 @@ pub fn to_pending_set(s: &str) -> Result<PendingSet, String> {
}
}
pub fn to_gas_limit(s: &str) -> Result<GasLimit, String> {
match s {
"auto" => Ok(GasLimit::Auto),
"off" => Ok(GasLimit::None),
other => Ok(GasLimit::Fixed(try!(to_u256(other)))),
}
}
pub fn to_address(s: Option<String>) -> Result<Address, String> {
match s {
Some(ref a) => clean_0x(a).parse().map_err(|_| format!("Invalid address: {:?}", a)),
@@ -194,6 +202,7 @@ pub fn to_client_config(
mode: Mode,
tracing: Switch,
pruning: Pruning,
pruning_history: u64,
compaction: DatabaseCompactionProfile,
wal: bool,
vm_type: VMType,
@@ -221,6 +230,7 @@ pub fn to_client_config(
client_config.mode = mode;
client_config.tracing.enabled = tracing;
client_config.pruning = pruning.to_algorithm(dirs, genesis_hash, fork_name);
client_config.history = pruning_history;
client_config.db_compaction = compaction;
client_config.db_wal = wal;
client_config.vm_type = vm_type;

View File

@@ -81,7 +81,6 @@ mod account;
mod blockchain;
mod presale;
mod run;
mod sync;
mod snapshot;
use std::{process, env};
@@ -117,11 +116,8 @@ fn start() -> Result<String, String> {
}
fn main() {
// just redirect to the sync::main()
if std::env::args().nth(1).map_or(false, |arg| arg == "sync") {
sync::main();
return;
}
// Always print backtrace on panic.
::std::env::set_var("RUST_BACKTRACE", "1");
match start() {
Ok(result) => {

View File

@@ -43,13 +43,15 @@ pub enum Error {
/// Returned when current version cannot be read or guessed.
UnknownDatabaseVersion,
/// Migration does not support existing pruning algorithm.
UnsuportedPruningMethod,
UnsupportedPruningMethod,
/// Existing DB is newer than the known one.
FutureDBVersion,
/// Migration is not possible.
MigrationImpossible,
/// Migration unexpectadly failed.
MigrationFailed,
/// Internal migration error.
Internal(MigrationError),
/// Migration was completed succesfully,
/// but there was a problem with io.
Io(IoError),
@@ -59,10 +61,11 @@ impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
let out = match *self {
Error::UnknownDatabaseVersion => "Current database version cannot be read".into(),
Error::UnsuportedPruningMethod => "Unsupported pruning method for database migration. Delete DB and resync.".into(),
Error::UnsupportedPruningMethod => "Unsupported pruning method for database migration. Delete DB and resync.".into(),
Error::FutureDBVersion => "Database was created with newer client version. Upgrade your client or delete DB and resync.".into(),
Error::MigrationImpossible => format!("Database migration to version {} is not possible.", CURRENT_VERSION),
Error::MigrationFailed => "Database migration unexpectedly failed".into(),
Error::Internal(ref err) => format!("{}", err),
Error::Io(ref err) => format!("Unexpected io error on DB migration: {}.", err),
};
@@ -80,7 +83,7 @@ impl From<MigrationError> for Error {
fn from(err: MigrationError) -> Self {
match err {
MigrationError::Io(e) => Error::Io(e),
_ => Error::MigrationFailed,
_ => Error::Internal(err),
}
}
}
@@ -245,9 +248,11 @@ pub fn migrate(path: &Path, pruning: Algorithm, compaction_profile: CompactionPr
// Perform pre-consolidation migrations
if version < CONSOLIDATION_VERSION && exists(&legacy::blocks_database_path(path)) {
println!("Migrating database from version {} to {}", version, CONSOLIDATION_VERSION);
try!(migrate_database(version, legacy::blocks_database_path(path), try!(legacy::blocks_database_migrations(&compaction_profile))));
try!(migrate_database(version, legacy::extras_database_path(path), try!(legacy::extras_database_migrations(&compaction_profile))));
try!(migrate_database(version, legacy::state_database_path(path), try!(legacy::state_database_migrations(pruning, &compaction_profile))));
try!(migrate_database(version, legacy::blocks_database_path(path), try!(legacy::blocks_database_migrations(&compaction_profile))));
let db_path = consolidated_database_path(path);
// Remove the database dir (it shouldn't exist anyway, but it might when migration was interrupted)
let _ = fs::remove_dir_all(db_path.clone());
@@ -263,6 +268,9 @@ pub fn migrate(path: &Path, pruning: Algorithm, compaction_profile: CompactionPr
println!("Migration finished");
}
// update version so we can apply post-consolidation migrations.
let version = ::std::cmp::max(CONSOLIDATION_VERSION, version);
// Further migrations
if version >= CONSOLIDATION_VERSION && version < CURRENT_VERSION && exists(&consolidated_database_path(path)) {
println!("Migrating database from version {} to {}", ::std::cmp::max(CONSOLIDATION_VERSION, version), CURRENT_VERSION);
@@ -270,10 +278,13 @@ pub fn migrate(path: &Path, pruning: Algorithm, compaction_profile: CompactionPr
println!("Migration finished");
}
// update version file.
try!(update_version(path));
// run any inplace migrations for the fully upgraded database
try!(run_inplace_upgrades(consolidated_database_path(path).as_path()));
// update version file.
update_version(path)
Ok(())
}
/// Old migrations utilities
@@ -333,7 +344,7 @@ mod legacy {
let res = match pruning {
Algorithm::Archive => manager.add_migration(migrations::state::ArchiveV7::default()),
Algorithm::OverlayRecent => manager.add_migration(migrations::state::OverlayRecentV7::default()),
_ => return Err(Error::UnsuportedPruningMethod),
_ => return Err(Error::UnsupportedPruningMethod),
};
try!(res.map_err(|_| Error::MigrationImpossible));

View File

@@ -25,10 +25,6 @@ use self::ipc_deps::*;
use ethcore_logger::Config as LogConfig;
pub mod service_urls {
pub const CLIENT: &'static str = "ipc:///tmp/parity-chain.ipc";
pub const SYNC: &'static str = "ipc:///tmp/parity-sync.ipc";
pub const SYNC_NOTIFY: &'static str = "ipc:///tmp/parity-sync-notify.ipc";
pub const NETWORK_MANAGER: &'static str = "ipc:///tmp/parity-manage-net.ipc";
}
#[cfg(not(feature="ipc"))]

View File

@@ -28,6 +28,7 @@ use dir::Directories;
pub enum SpecType {
Mainnet,
Testnet,
Ropsten,
Olympic,
Classic,
Custom(String),
@@ -47,6 +48,7 @@ impl FromStr for SpecType {
"frontier" | "homestead" | "mainnet" => SpecType::Mainnet,
"frontier-dogmatic" | "homestead-dogmatic" | "classic" => SpecType::Classic,
"morden" | "testnet" => SpecType::Testnet,
"ropsten" => SpecType::Ropsten,
"olympic" => SpecType::Olympic,
other => SpecType::Custom(other.into()),
};
@@ -59,6 +61,7 @@ impl SpecType {
match *self {
SpecType::Mainnet => Ok(ethereum::new_frontier()),
SpecType::Testnet => Ok(ethereum::new_morden()),
SpecType::Ropsten => Ok(ethereum::new_ropsten()),
SpecType::Olympic => Ok(ethereum::new_olympic()),
SpecType::Classic => Ok(ethereum::new_classic()),
SpecType::Custom(ref file) => Ok(Spec::load(&try!(contents(file).map_err(|_| "Could not load specification file."))))
@@ -215,7 +218,7 @@ impl Default for MinerExtras {
extra_data: version_data(),
gas_floor_target: U256::from(4_700_000),
gas_ceil_target: U256::from(6_283_184),
transactions_limit: 1024,
transactions_limit: 2048,
}
}
}
@@ -232,6 +235,7 @@ mod tests {
assert_eq!(SpecType::Mainnet, "mainnet".parse().unwrap());
assert_eq!(SpecType::Testnet, "testnet".parse().unwrap());
assert_eq!(SpecType::Testnet, "morden".parse().unwrap());
assert_eq!(SpecType::Ropsten, "ropsten".parse().unwrap());
assert_eq!(SpecType::Olympic, "olympic".parse().unwrap());
}

View File

@@ -22,7 +22,7 @@ use fdlimit::raise_fd_limit;
use ethcore_logger::{Config as LogConfig, setup_log};
use ethcore_rpc::NetworkSettings;
use ethsync::NetworkConfiguration;
use util::{Colour, version, U256};
use util::{Colour, version};
use io::{MayPanic, ForwardPanic, PanicHandler};
use ethcore::client::{Mode, Switch, DatabaseCompactionProfile, VMType, ChainNotify};
use ethcore::service::ClientService;
@@ -52,6 +52,7 @@ pub struct RunCmd {
pub dirs: Directories,
pub spec: SpecType,
pub pruning: Pruning,
pub pruning_history: u64,
/// Some if execution should be daemonized. Contains pid_file path.
pub daemon: Option<String>,
pub logger_config: LogConfig,
@@ -59,7 +60,7 @@ pub struct RunCmd {
pub http_conf: HttpConfiguration,
pub ipc_conf: IpcConfiguration,
pub net_conf: NetworkConfiguration,
pub network_id: Option<U256>,
pub network_id: Option<usize>,
pub acc_conf: AccountsConfig,
pub gas_pricer: GasPricerConfig,
pub miner_extras: MinerExtras,
@@ -79,13 +80,17 @@ pub struct RunCmd {
pub custom_bootnodes: bool,
}
pub fn execute(cmd: RunCmd) -> Result<(), String> {
pub fn execute(mut cmd: RunCmd) -> Result<(), String> {
// increase max number of open files
raise_fd_limit();
// set up logger
let logger = try!(setup_log(&cmd.logger_config));
if cmd.dapps_conf.enabled {
warn!("Warning: Parity UI is disabled in this release. Please upgrade to version 1.4.2 or higher.");
cmd.dapps_conf.enabled = false;
}
// set up panic handler
let panic_handler = PanicHandler::new_in_arc();
@@ -149,6 +154,7 @@ pub fn execute(cmd: RunCmd) -> Result<(), String> {
cmd.mode,
cmd.tracing,
cmd.pruning,
cmd.pruning_history,
cmd.compaction,
cmd.wal,
cmd.vm_type,

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