Compare commits

...

117 Commits

Author SHA1 Message Date
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
Denis S. Soldatov aka General-Beck
df4d98001a update gitlab-ci
set RUST 1.11 for windows
2016-10-04 14:43:49 +08:00
Robert Habermeier
2e4672ea13 Merge pull request #2414 from ethcore/compilation-beta
fix broken beta compilation (backport to beta)
2016-10-02 21:07:35 +02:00
Arkadiy Paronyan
7f7fe33bde Jumptable cache (#2435)
* v1.3.3

* Jumptable cache
2016-10-02 19:52:53 +02:00
Arkadiy Paronyan
3d313d592a Disabling debug symbols due to rustc 1.12 memory usage regression 2016-10-02 09:45:27 +02:00
NikVolf
abc6970d08 fix ethkey more 2016-10-01 15:29:11 +03:00
NikVolf
fa636d402d ethkey eq 2016-10-01 13:04:08 +03:00
NikVolf
73d6666294 some checksums 2016-10-01 00:28:31 +03:00
Denis S. Soldatov aka General-Beck
f16ccacd22 Update gitlab-ci
add checksum
2016-09-30 21:03:05 +07:00
Nikolay Volf
ba3de5d3b9 rayon bump 2016-09-30 02:25:35 +03:00
Robert Habermeier
f16de5501a fix broken beta compilation 2016-09-29 23:03:02 +03:00
Arkadiy Paronyan
e298ab30e4 Quick fix for missing tree route blocks (#2400) 2016-09-29 14:47:13 +02:00
Tomasz Drwięga
63d3a4dd59 Beta Backports (#2396)
* Removing extras data from retracted blocks. (#2375)

* Removing extras data from retracted blocks.

* Adding a test case

Conflicts:
	ethcore/src/blockchain/blockchain.rs

* Fixing transaction queue

Conflicts:
	ethcore/src/miner/transaction_queue.rs

* Prioritizing re-imported transactions (#2372)

* Prioritizing re-imported transactions

* Fixing compilation on beta

Conflicts:
	Cargo.lock
	ethcore/src/client/client.rs
	ethcore/src/miner/transaction_queue.rs

* Post-merge fixes
2016-09-29 13:19:53 +02:00
Arkadiy Paronyan
0e55b6c6c9 Cache the fork block header after snapshot restoration (#2391) 2016-09-29 12:34:40 +02:00
Nikolay Volf
4d115987cb Accounts bloom (#2357)
* proper bloom

* incremental bloom updates

* crate update

* return of the column

* fix n^2 byteorder write

* add notes to funs

* working bloom commits

* Optimizations

* bloom diag

* migration basic

* migration ongoing

* migration finalizing

* mingration api workarounds

* fix test_client setups

* snapshot bloom update

* review fixes

* just forward keys in the migration

* migration extra tracing

* fix migration path

* remove close pray

* review issues
2016-09-29 11:27:41 +02:00
Tomasz Drwięga
2d623f14db Disable colors for signer token in beta (#2379) 2016-09-28 23:33:50 +02:00
Robert Habermeier
1d1a3b9d02 correct sync memory usage calculation (#2386) 2016-09-28 23:00:27 +02:00
Arkadiy Paronyan
1d69b0e124 Fixing jit feature compilation (#2376)
* Fixing jit feature compilation

* Fixing jit feature compilation (#2310)

Conflicts:
	Cargo.lock

* Delegatecall support
2016-09-28 17:25:32 +02:00
Arkadiy Paronyan
3c59475be6 Clear state cache on sealed block import (#2377) 2016-09-28 17:24:47 +02:00
Denis S. Soldatov aka General-Beck
facab31551 Update gitlab-ci
add RUST_BACKTRACE=1 in test stage
2016-09-28 01:52:17 +07:00
Arkadiy Paronyan
c9cfcd2728 Canonical state cache (#2308)
* State cache

* Reduced copying data between caches

Whitespace and optional symbols

* Set a limit on storage cache

* Style and docs
2016-09-27 16:44:32 +02:00
Arkadiy Paronyan
557dbb73b8 DIV optimization (#2353) 2016-09-27 14:04:08 +02:00
Gav Wood
6f772a28e2 Reorder transaction_by_hash to favour canon search (#2331)
* Reorder transaction_by_hash to favour canon search

* Fix test.
2016-09-27 12:16:42 +02:00
Tomasz Drwięga
16f3119547 Lenient bytes deserialization (#2340)
* Lenient bytes deserialization

* Error when deserializing invalid hex

* Error when deserializing invalid hex

Conflicts:
	rpc/src/v1/types/bytes.rs
2016-09-27 11:24:27 +02:00
Tomasz Drwięga
c3741640f7 Penalize transactions with gas above gas limit (#2271)
* Handle RLP to string UTF-8 decoding errors (#2217)

* Penalize transactions with gas above gas limit

* Avoid penalizing legit transactions

* saturating not overflowing

* Remove crufty code

* Introduce gas price ordering.

* Gas before gas-price, as long as the minimum price is met.

* saturating add
2016-09-25 12:14:39 +02:00
Denis S. Soldatov aka General-Beck
decca7f698 Update gitlab-ci
deploy fix
2016-09-24 05:01:48 +07:00
Denis S. Soldatov aka General-Beck
fc53726c7f Update gitlab-ci
fix armv7 path
2016-09-24 03:00:22 +07:00
Denis S. Soldatov aka General-Beck
e2b81bc08d Update gitlab-ci
[ci skip]
rename x86_64-unknown-centos-gnu
2016-09-24 00:11:23 +07:00
Denis S. Soldatov aka General-Beck
4d2d1eac1f Update gitlab-ci
fix path in arm
2016-09-23 23:45:57 +07:00
Denis S. Soldatov aka General-Beck
5572e3dd1d Update gitlab-ci
fix  windows deploy to S3
add ubuntu 14.04 build
2016-09-23 23:40:25 +07:00
Tomasz Drwięga
0db1c0d336 Peek transaction queue via RPC (#2270)
* Handle RLP to string UTF-8 decoding errors (#2217)

* pending transactions
2016-09-23 18:13:03 +02:00
Denis S. Soldatov aka General-Beck
905f04dc9d Update Ubuntu arm Dockerfile
[ci skip] remove CC and CXX env
backport to beta https://github.com/ethcore/parity/pull/2064
2016-09-23 21:35:04 +07:00
Denis S. Soldatov aka General-Beck
f560cf360c Update Dockerfile ubuntu-aarch64
[ci skip] remove CC and CXX env
backport to beta https://github.com/ethcore/parity/pull/2064
2016-09-23 21:34:16 +07:00
Tomasz Drwięga
f5d48cbf2a Handle RLP to string UTF-8 decoding errors (#2217) (#2226) 2016-09-22 14:48:54 +02:00
Denis S. Soldatov aka General-Beck
d59e2ecbc6 Update gitlab-ci
fix x86_64-pc-windows-msvc
2016-09-21 22:36:54 +07:00
Denis S. Soldatov aka General-Beck
a97ca5aaf4 Update gitlab-ci
remove -export
2016-09-21 22:25:51 +07:00
Tomasz Drwięga
df61b1b328 Fixing compilation without ui feature (#2207) 2016-09-21 11:51:49 +01:00
Tomasz Drwięga
52a69d19e6 Avoid cloning clean stuff (#2173) 2016-09-20 23:10:26 +08:00
Arkadiy Paronyan
33084aaa07 v1.3.2 (#2200) 2016-09-20 14:21:17 +08:00
Arkadiy Paronyan
2a82fa0a47 Backports to beta (#2068)
* Fix several RPCs (#1926)

* Fix up pending receipts details.

* Add support for additional params and registry over RPC.

* Fix tests.

* Add test, additional fix.

Fixes #1932.

* Fix up tests.

* Fix test.

* Fix test.

* DB WAL size limit (#1935)

* Limit WAL size

* Check pruning by db modification date (#1924)

* Cache address hash (#1943)

* ECIES without MAC (#1948)

* Use random IV for ECIES AES

* ECIES encrypt/decrypt for a single message

* Derive IV from shared secret

* Apply settings to column families

* fixed #1933 (#1979)

* Fixed neighbours collection (#1996)

* dapps-hosts configuration

* Disabled counter check

* always process trie death row on commit, add more tracing

* fixed transaction addresses mapping, fixes #1971

* simplified iterator

* v1.3.1

* v1.3.1
2016-09-11 14:04:17 +02:00
Denis S. Soldatov aka General-Beck
1ccc90108c Update gitlab-ci 2016-09-10 00:59:40 +07:00
Marek Kotewicz
e60c5b59a6 Fixing serde overflow error (#1977) (#2030) 2016-09-01 12:23:05 +02:00
Denis S. Soldatov aka General-Beck
b199fbb6c6 Update gitlab-ci
clone from master
2016-08-27 02:59:47 +07:00
Denis S. Soldatov aka General-Beck
d9d506db57 Update gitlab-ci
remove CC&CXX env from beta branch
2016-08-19 12:18:37 +07:00
Arkadiy Paronyan
425e1ce04c Check pruning by db modification date (#1924) 2016-08-12 17:48:11 +02:00
Tomasz Drwięga
8741d0d155 Bumping Parity UI (#1920) 2016-08-12 12:58:31 +02:00
Arkadiy Paronyan
dfb2ddfdc2 Backports to beta (#1919)
* RPC errors & logs (#1845)

* Refactoring errors in RPC

* Updating jsonrpc-core

* Fixing code_at

* Avoid mentioning obvious segments in proof

[ci:skip]

* fixed cache_manager lock order

* Purging .derefs, fixing clippy warnings. (#1890)

* Fixing clippy warnings

* Purging derefs

* Simplifying engine derefs

* Simplifying more engine derefs

* Adding more details to miner log

* fixed #1889, .DS_Store is no longer treated as key file (#1892)

* fixed #1889, .DS_Store is no longer treated as key file

* ethstore filters directories, hidden files and common system files

* fixed compiling

* fix regression with geth dir

* fix regression with geth dir

* Fix ipc compilation and add ipc feature to test targets (#1902)

* fix compilation and add it to the ci run

* no separator?

* use quotes and spaces

* RocksDB version bump

* Don't return deleted nodes that are not yet flushed (#1908)

* polling & connection timeouts (#1910)

* Peers RPC + UI displaying active/connected/max peers (#1915)

* Peers API

* Bumping Parity-UI

* Fixing tests

* Save nodes removed from backing_overlay until commit (#1917)
2016-08-12 12:16:20 +02:00
Arkadiy Paronyan
52ac5a00f5 Backports for beta (#1888)
* Sync to peers with confirmed fork block only (#1863)

* Fixing gas conversion

* Validating u256->usize conversion

* Update cache usage on commiting block info (#1871)

* Use UntrustedRlp for block verification (#1872)

* take snapshot at specified block and slightly better informants (#1873)

* prettier informant for snapshot creation

* allow taking snapshot at a given block

* minor tweaks

* elaborate on cli

* Send new block hashes to all peers (#1875)

* Reduce max open files (#1876)

* ws-rs update

* Fixing test

* Fixing miner deadlock (#1885)
2016-08-09 14:05:02 +02:00
arkpar
6336bdecf3 Version set to beta 2016-08-06 08:08:27 +02:00
223 changed files with 7968 additions and 3335 deletions

2
.gitignore vendored
View File

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

View File

@@ -1,16 +1,82 @@
stages:
- build
- deploy
- test
variables:
GIT_DEPTH: "3"
SIMPLECOV: "true"
RUST_BACKTRACE: "1"
RUSTFLAGS: "-D warnings"
cache:
key: "$CI_BUILD_NAME/$CI_BUILD_REF_NAME"
untracked: true
linux-stable:
stage: build
image: ethcore/rust:stable
only:
- master
- beta
- tags
- stable
script:
- cargo build --release --verbose
- strip target/release/parity
- 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/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
artifacts:
paths:
- target/release/parity
name: "stable-x86_64-unknown-linux-gnu_parity"
linux-stable-14.04:
stage: build
image: ethcore/rust-14.04:latest
only:
- master
- beta
- tags
- stable
script:
- cargo build --release --verbose
- strip target/release/parity
- 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/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
artifacts:
paths:
- target/release/parity
name: "stable-x86_64-unknown-ubuntu_14_04-gnu_parity"
linux-beta:
stage: build
image: ethcore/rust:beta
only:
- master
- beta
- tags
- stable
script:
- cargo build --release --verbose
- strip target/release/parity
@@ -20,23 +86,16 @@ linux-beta:
artifacts:
paths:
- target/release/parity
name: "${CI_BUILD_NAME}_parity"
linux-stable:
stage: build
image: ethcore/rust:stable
script:
- cargo build --release --verbose
- strip target/release/parity
tags:
- rust
- rust-stable
artifacts:
paths:
- target/release/parity
name: "${CI_BUILD_NAME}_parity"
name: "beta-x86_64-unknown-linux-gnu_parity"
allow_failure: true
linux-nightly:
stage: build
image: ethcore/rust:nightly
only:
- master
- beta
- tags
- stable
script:
- cargo build --release --verbose
- strip target/release/parity
@@ -46,121 +105,243 @@ linux-nightly:
artifacts:
paths:
- target/release/parity
name: "${CI_BUILD_NAME}_parity"
name: "nigthly-x86_64-unknown-linux-gnu_parity"
allow_failure: true
linux-centos:
stage: build
image: ethcore/rust-centos:latest
only:
- master
- beta
- tags
- stable
script:
- export CXX="g++"
- export CC="gcc"
- cargo build --release --verbose
- strip target/release/parity
- 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/parity.md5 --body parity.md5
tags:
- rust
- rust-centos
artifacts:
paths:
- target/release/parity
name: "${CI_BUILD_NAME}_parity"
name: "x86_64-unknown-centos-gnu_parity"
linux-armv7:
stage: build
image: ethcore/rust-arm:latest
image: ethcore/rust-armv7:latest
only:
- beta
- tags
- stable
script:
- export CXX=arm-linux-gnueabihf-g++
- export CC=arm-linux-gnueabihf-gcc
- rm -rf .cargo
- mkdir -p .cargo
- echo "[target.armv7-unknown-linux-gnueabihf]" >> .cargo/config
- echo "linker= \"arm-linux-gnueabihf-gcc\"" >> .cargo/config
- 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 >> 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/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
artifacts:
paths:
- target/armv7-unknown-linux-gnueabihf/release/parity
name: "${CI_BUILD_NAME}_parity"
name: "armv7_unknown_linux_gnueabihf_parity"
allow_failure: true
linux-arm:
stage: build
image: ethcore/rust-arm:latest
only:
- beta
- tags
- stable
script:
- export CXX=arm-linux-gnueabihf-g++
- export CC=arm-linux-gnueabihf-gcc
- rm -rf .cargo
- mkdir -p .cargo
- echo "[target.arm-unknown-linux-gnueabihf]" >> .cargo/config
- echo "linker= \"arm-linux-gnueabihf-gcc\"" >> .cargo/config
- 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 >> 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/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
artifacts:
paths:
- target/arm-unknown-linux-gnueabihf/release/parity
name: "${CI_BUILD_NAME}_parity"
name: "arm-unknown-linux-gnueabihf_parity"
allow_failure: true
linux-armv6:
stage: build
image: ethcore/rust-arm:latest
image: ethcore/rust-armv6:latest
only:
- beta
- tags
- stable
script:
- export CXX=arm-linux-gnueabi-g++
- export CC=arm-linux-gnueabi-gcc
- rm -rf .cargo
- mkdir -p .cargo
- echo "[target.arm-unknown-linux-gnueabi]" >> .cargo/config
- echo "linker= \"arm-linux-gnueabi-gcc\"" >> .cargo/config
- 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 >> 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/parity.md5 --body parity.md5
tags:
- rust
- rust-arm
artifacts:
paths:
- target/arm-unknown-linux-gnueabi/release/parity
name: "${CI_BUILD_NAME}_parity"
name: "arm-unknown-linux-gnueabi_parity"
allow_failure: true
linux-aarch64:
stage: build
image: ethcore/rust-arm:latest
image: ethcore/rust-aarch64:latest
only:
- beta
- tags
- stable
script:
- export CXX=aarch64-linux-gnu-g++
- export CC=aarch64-linux-gnu-gcc
- rm -rf .cargo
- mkdir -p .cargo
- echo "[target.aarch64-unknown-linux-gnu]" >> .cargo/config
- echo "linker= \"aarch64-linux-gnu-gcc\"" >> .cargo/config
- 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 >> 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/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
artifacts:
paths:
- target/aarch64-unknown-linux-gnu/release/parity
name: "${CI_BUILD_NAME}_parity"
name: "aarch64-unknown-linux-gnu_parity"
allow_failure: true
darwin:
stage: build
only:
- master
- beta
- tags
- stable
script:
- cargo build --release --verbose
- 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/parity.md5 --body parity.md5
tags:
- osx
artifacts:
paths:
- target/release/parity
name: "${CI_BUILD_NAME}_parity"
name: "x86_64-apple-darwin_parity"
windows:
stage: build
only:
- master
- beta
- tags
- stable
script:
- 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
- SET
- set RUSTFLAGS=%RUSTFLAGS% -Zorbit=off -D warnings
- rustup default stable-x86_64-pc-windows-msvc
- cargo build --release --verbose
- 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.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
name: "${CI_BUILD_NAME}_parity"
- nsis/InstallParity.exe
name: "x86_64-pc-windows-msvc_parity"
test-linux:
stage: test
before_script:
- git submodule update --init --recursive
script:
- export RUST_BACKTRACE=1
- ./test.sh --verbose
tags:
- rust-test
dependencies:
- linux-stable

334
Cargo.lock generated
View File

@@ -1,12 +1,12 @@
[root]
name = "parity"
version = "1.3.0"
version = "1.3.10"
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,22 +20,22 @@ dependencies = [
"ethcore-logger 1.3.0",
"ethcore-rpc 1.3.0",
"ethcore-signer 1.3.0",
"ethcore-util 1.3.0",
"ethcore-util 1.3.10",
"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)",
"syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex 0.36.0 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -112,9 +112,18 @@ name = "bloomchain"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bloomfilter"
version = "0.0.10"
source = "git+https://github.com/ethcore/rust-bloom-filter#e66a3f20443bc78810877390ad4da00ebdf74d78"
dependencies = [
"bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "byteorder"
version = "0.5.2"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -122,6 +131,14 @@ name = "bytes"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bytes"
version = "0.4.0-dev"
source = "git+https://github.com/carllerche/bytes#6529f6392a9717585b8d67e1db96e6fa0fb6cb1f"
dependencies = [
"stable-heap 0.1.0 (git+https://github.com/carllerche/stable-heap?rev=3c5cd1ca47)",
]
[[package]]
name = "cfg-if"
version = "0.1.0"
@@ -155,7 +172,7 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -175,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)",
@@ -191,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]]
@@ -219,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)",
@@ -241,6 +259,8 @@ version = "1.3.0"
dependencies = [
"bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bloomfilter 0.0.10 (git+https://github.com/ethcore/rust-bloom-filter)",
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy 0.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -250,16 +270,18 @@ dependencies = [
"ethcore-ipc 1.3.0",
"ethcore-ipc-codegen 1.3.0",
"ethcore-ipc-nano 1.3.0",
"ethcore-util 1.3.0",
"ethcore-util 1.3.10",
"ethjson 0.1.0",
"ethstore 0.1.0",
"evmjit 1.3.0",
"heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.9.4 (git+https://github.com/ethcore/hyper)",
"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)",
"lru-cache 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -272,23 +294,23 @@ 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.0",
"ethcore-util 1.3.10",
"hyper 0.9.4 (git+https://github.com/ethcore/hyper)",
"jsonrpc-core 2.0.7 (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-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?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 0.6.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps-home 0.6.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps-status 0.6.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps-wallet 0.6.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps-home 1.4.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps-status 1.4.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps-wallet 1.4.0 (git+https://github.com/ethcore/parity-ui.git)",
"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)",
"serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -314,7 +336,7 @@ name = "ethcore-ipc"
version = "1.3.0"
dependencies = [
"ethcore-devtools 1.3.0",
"ethcore-util 1.3.0",
"ethcore-util 1.3.10",
"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)",
]
@@ -359,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.0",
"ethcore-util 1.3.10",
"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)",
@@ -371,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.0",
"ethcore-util 1.3.10",
"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)",
@@ -386,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.0",
"ethcore-util 1.3.10",
"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)",
@@ -410,12 +432,12 @@ dependencies = [
"ethcore-devtools 1.3.0",
"ethcore-io 1.3.0",
"ethcore-ipc 1.3.0",
"ethcore-util 1.3.0",
"ethcore-util 1.3.10",
"ethjson 0.1.0",
"ethsync 1.3.0",
"json-ipc-server 0.2.4 (git+https://github.com/ethcore/json-ipc-server.git)",
"jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-http-server 6.1.0 (git+https://github.com/ethcore/jsonrpc-http-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?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)",
@@ -433,18 +455,18 @@ 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.0",
"jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-util 1.3.10",
"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 0.6.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps-signer 1.4.0 (git+https://github.com/ethcore/parity-ui.git)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"ws 0.5.0 (git+https://github.com/ethcore/ws-rs.git?branch=stable)",
"ws 0.5.2 (git+https://github.com/ethcore/ws-rs.git?branch=mio-upstream-stable)",
]
[[package]]
name = "ethcore-util"
version = "1.3.0"
version = "1.3.10"
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)",
@@ -477,7 +499,7 @@ dependencies = [
name = "ethjson"
version = "0.1.0"
dependencies = [
"ethcore-util 1.3.0",
"ethcore-util 1.3.10",
"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)",
@@ -525,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.0",
"ethcore-util 1.3.10",
"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)",
@@ -534,6 +556,13 @@ dependencies = [
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "evmjit"
version = "1.3.0"
dependencies = [
"tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fdlimit"
version = "0.1.0"
@@ -543,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"
@@ -614,7 +646,7 @@ dependencies = [
"traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -635,7 +667,7 @@ dependencies = [
"traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -678,36 +710,36 @@ 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)",
"jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 2.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)",
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "jsonrpc-core"
version = "2.0.7"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.3.6 (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)",
"serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[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.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -735,11 +767,24 @@ name = "libc"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "linked-hash-map"
version = "0.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "log"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lru-cache"
version = "0.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"linked-hash-map 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "matches"
version = "0.1.2"
@@ -780,7 +825,7 @@ dependencies = [
"bytes 0.3.0 (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)",
"miow 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -796,7 +841,7 @@ dependencies = [
"bytes 0.3.0 (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)",
"miow 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -804,9 +849,24 @@ dependencies = [
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mio"
version = "0.6.0-dev"
source = "git+https://github.com/carllerche/mio?rev=62ec763c9cc34d8a452ed0392c575c50ddd5fc8d#62ec763c9cc34d8a452ed0392c575c50ddd5fc8d"
dependencies = [
"kernel32-sys 0.2.2 (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)",
"miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.2.0 (git+https://github.com/carllerche/slab?rev=5476efcafb)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "miow"
version = "0.1.2"
version = "0.1.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)",
@@ -829,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)",
]
@@ -854,6 +914,19 @@ dependencies = [
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nix"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.12 (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.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nodrop"
version = "0.1.6"
@@ -943,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)",
@@ -956,8 +1029,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "parity-dapps"
version = "0.6.0"
source = "git+https://github.com/ethcore/parity-ui.git#697e860dedc45003909602a002e7743478ab173a"
version = "1.4.0"
source = "git+https://github.com/ethcore/parity-ui.git#e4dddf36e7c9fa5c6e746790119c71f67438784a"
dependencies = [
"aster 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -970,34 +1043,34 @@ dependencies = [
[[package]]
name = "parity-dapps-home"
version = "0.6.0"
source = "git+https://github.com/ethcore/parity-ui.git#697e860dedc45003909602a002e7743478ab173a"
version = "1.4.0"
source = "git+https://github.com/ethcore/parity-ui.git#e4dddf36e7c9fa5c6e746790119c71f67438784a"
dependencies = [
"parity-dapps 0.6.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)",
]
[[package]]
name = "parity-dapps-signer"
version = "0.6.0"
source = "git+https://github.com/ethcore/parity-ui.git#697e860dedc45003909602a002e7743478ab173a"
version = "1.4.0"
source = "git+https://github.com/ethcore/parity-ui.git#e4dddf36e7c9fa5c6e746790119c71f67438784a"
dependencies = [
"parity-dapps 0.6.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)",
]
[[package]]
name = "parity-dapps-status"
version = "0.6.0"
source = "git+https://github.com/ethcore/parity-ui.git#697e860dedc45003909602a002e7743478ab173a"
version = "1.4.0"
source = "git+https://github.com/ethcore/parity-ui.git#e4dddf36e7c9fa5c6e746790119c71f67438784a"
dependencies = [
"parity-dapps 0.6.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)",
]
[[package]]
name = "parity-dapps-wallet"
version = "0.6.0"
source = "git+https://github.com/ethcore/parity-ui.git#697e860dedc45003909602a002e7743478ab173a"
version = "1.4.0"
source = "git+https://github.com/ethcore/parity-ui.git#e4dddf36e7c9fa5c6e746790119c71f67438784a"
dependencies = [
"parity-dapps 0.6.0 (git+https://github.com/ethcore/parity-ui.git)",
"parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)",
]
[[package]]
@@ -1124,7 +1197,7 @@ dependencies = [
[[package]]
name = "rayon"
version = "0.3.1"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1152,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#eadce7f74cfe92b99ce63a77af425b47857239b8"
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)",
@@ -1161,9 +1234,9 @@ dependencies = [
[[package]]
name = "rocksdb-sys"
version = "0.3.0"
source = "git+https://github.com/ethcore/rust-rocksdb#eadce7f74cfe92b99ce63a77af425b47857239b8"
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)",
]
@@ -1180,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)",
@@ -1194,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)",
@@ -1255,17 +1328,14 @@ dependencies = [
[[package]]
name = "sha1"
version = "0.1.1"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
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]]
@@ -1273,6 +1343,11 @@ name = "slab"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "slab"
version = "0.2.0"
source = "git+https://github.com/carllerche/slab?rev=5476efcafb#5476efcafbc5ef4d7315b1bea3f756d8a1fe975e"
[[package]]
name = "slab"
version = "0.2.0"
@@ -1297,9 +1372,14 @@ name = "spmc"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "stable-heap"
version = "0.1.0"
source = "git+https://github.com/carllerche/stable-heap?rev=3c5cd1ca47#3c5cd1ca4706f167a1de85658b5af0d6d3e65165"
[[package]]
name = "strsim"
version = "0.3.0"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -1310,6 +1390,14 @@ dependencies = [
"syntex_syntax 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syntex"
version = "0.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"syntex_syntax 0.36.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syntex_syntax"
version = "0.33.0"
@@ -1323,6 +1411,19 @@ dependencies = [
"unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syntex_syntax"
version = "0.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.5.0 (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)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "table"
version = "0.1.0"
@@ -1447,7 +1548,7 @@ dependencies = [
[[package]]
name = "url"
version = "1.1.1"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1506,15 +1607,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ws"
version = "0.5.0"
source = "git+https://github.com/ethcore/ws-rs.git?branch=stable#a876fc115c3ef50a17c8822c9bd2f6e94473e005"
version = "0.5.2"
source = "git+https://github.com/ethcore/ws-rs.git?branch=mio-upstream-stable#afbff59776ce16ccec5ee9e218b8891830ee6fdf"
dependencies = [
"bytes 0.4.0-dev (git+https://github.com/carllerche/bytes)",
"httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)",
"mio 0.6.0-dev (git+https://github.com/carllerche/mio?rev=62ec763c9cc34d8a452ed0392c575c50ddd5fc8d)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"sha1 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.2.0 (git+https://github.com/carllerche/slab?rev=5476efcafb)",
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1549,58 +1652,62 @@ dependencies = [
"checksum aster 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07d344974f0a155f091948aa389fb1b912d3a58414fbdb9c8d446d193ee3496a"
"checksum bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c"
"checksum bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5b97c2c8e8bbb4251754f559df8af22fb264853c7d009084a576cdf12565089d"
"checksum bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "32866f4d103c4e438b1db1158aa1b1a80ee078e5d77a59a2f906fd62a577389c"
"checksum bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dead7461c1127cf637931a1e50934eb6eee8bff2f74433ac7909e9afcee04a3"
"checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23"
"checksum bitflags 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "72cd7314bd4ee024071241147222c706e80385a1605ac7d4cd2fcc339da2ae46"
"checksum blastfig 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "09640e0509d97d5cdff03a9f5daf087a8e04c735c3b113a75139634a19cfc7b2"
"checksum bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f421095d2a76fc24cd3fb3f912b90df06be7689912b1bdb423caefae59c258d"
"checksum byteorder 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e68d0b3b234a583993a53d5b0063fb5fe8713590fe733d41b98a2cee6a9c26e"
"checksum bloomfilter 0.0.10 (git+https://github.com/ethcore/rust-bloom-filter)" = "<none>"
"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
"checksum bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c129aff112dcc562970abb69e2508b40850dd24c274761bb50fb8a0067ba6c27"
"checksum bytes 0.4.0-dev (git+https://github.com/carllerche/bytes)" = "<none>"
"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
"checksum chrono 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)" = "a714b6792cb4bb07643c35d2a051d92988d4e296322a60825549dd0764bcd396"
"checksum clippy 0.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "e96469b413984c78285727f94f9c626a1f2006cecdcf813b5d6893c0c85df42f"
"checksum clippy_lints 0.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "f11938c4b10c556903bb1c1e717eb038658324bf7197e4cfc159a16417327345"
"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"
"checksum hpack 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d2da7d3a34cf6406d9d700111b8eafafe9a251de41ae71d8052748259343b58"
"checksum httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46534074dbb80b070d60a5cb8ecadd8963a00a438ae1a95268850a7ef73b67ae"
"checksum hyper 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bb0f4d00bb781e559b6e66ae4b5479df0fdf9ab15949f52fa2f1f5de16d4cc07"
"checksum hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "eb27e8a3e8f17ac43ffa41bbda9cf5ad3f9f13ef66fa4873409d4902310275f7"
"checksum hyper 0.9.4 (git+https://github.com/ethcore/hyper)" = "<none>"
"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11"
"checksum igd 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5b93df68d6152576e9bc9f371e33e00b40738d528b3566ff41ea11d04401dc"
"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 jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "91755680900913f73576065c85359ee793ac3883bc461dbca90fc4a603be84cc"
"checksum jsonrpc-http-server 6.1.0 (git+https://github.com/ethcore/jsonrpc-http-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?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"
"checksum libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "97def9dc7ce1d8e153e693e3a33020bc69972181adb2f871e87e888876feae49"
"checksum linked-hash-map 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "83f7ff3baae999fdf921cccf54b61842bb3b26868d50d02dff48052ebec8dd79"
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
"checksum lru-cache 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "42d50dcb5d9f145df83b1043207e1ac0c37c9c779c4e128ca4655abc3f3cbf8c"
"checksum matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "15305656809ce5a4805b1ff2946892810992197ce1270ff79baded852187942e"
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
"checksum mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a74cc2587bf97c49f3f5bab62860d6abf3902ca73b66b51d9b049fbdcd727bd2"
"checksum mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e50bf542f81754ef69e5cea856946a3819f7c09ea97b4903c8bc8a89f74e7b6"
"checksum mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)" = "<none>"
"checksum mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a637d1ca14eacae06296a008fa7ad955347e34efcb5891cfd8ba05491a37907e"
"checksum miow 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4e93d633d34b8ff65a24566d67d49703e7a5c7ac2844d6139a9fc441a799e89a"
"checksum mio 0.6.0-dev (git+https://github.com/carllerche/mio?rev=62ec763c9cc34d8a452ed0392c575c50ddd5fc8d)" = "<none>"
"checksum miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d5bfc6782530ac8ace97af10a540054a37126b63b0702ddaaa243b73b5745b9a"
"checksum nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)" = "<none>"
"checksum nanomsg-sys 0.5.0 (git+https://github.com/ethcore/nanomsg.rs.git)" = "<none>"
"checksum net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)" = "6a816012ca11cb47009693c1e0c6130e26d39e4d97ee2a13c50e868ec83e3204"
"checksum nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f05c2fc965fc1cd6b73fa57fa7b89f288178737f2f3ce9e63e4a6a141189000e"
"checksum nix 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a7bb1da2be7da3cbffda73fc681d509ffd9e665af478d2bee1907cee0bc64b2"
"checksum nodrop 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4d9a22dbcebdeef7bf275cbf444d6521d4e7a2fee187b72d80dba0817120dd8f"
"checksum nom 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6caab12c5f97aa316cb249725aa32115118e1522b445e26c257dd77cad5ffd4e"
"checksum num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "c04bd954dbf96f76bab6e5bd6cef6f1ce1262d15268ce4f926d2b5b778fa7af2"
@@ -1611,13 +1718,13 @@ 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 0.6.0 (git+https://github.com/ethcore/parity-ui.git)" = "<none>"
"checksum parity-dapps-home 0.6.0 (git+https://github.com/ethcore/parity-ui.git)" = "<none>"
"checksum parity-dapps-signer 0.6.0 (git+https://github.com/ethcore/parity-ui.git)" = "<none>"
"checksum parity-dapps-status 0.6.0 (git+https://github.com/ethcore/parity-ui.git)" = "<none>"
"checksum parity-dapps-wallet 0.6.0 (git+https://github.com/ethcore/parity-ui.git)" = "<none>"
"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>"
"checksum parity-dapps-signer 1.4.0 (git+https://github.com/ethcore/parity-ui.git)" = "<none>"
"checksum parity-dapps-status 1.4.0 (git+https://github.com/ethcore/parity-ui.git)" = "<none>"
"checksum parity-dapps-wallet 1.4.0 (git+https://github.com/ethcore/parity-ui.git)" = "<none>"
"checksum parking_lot 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e0fd1be2c3cf5fef20a6d18fec252c4f3c87c14fc3039002eb7d4ed91e436826"
"checksum phf 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "447d9d45f2e0b4a9b532e808365abf18fc211be6ca217202fcd45236ef12f026"
"checksum phf_codegen 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "8af7ae7c3f75a502292b491e5cc0a1f69e3407744abe6e57e2a3b712bb82f01d"
@@ -1633,13 +1740,13 @@ dependencies = [
"checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c"
"checksum quine-mc_cluskey 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6683b0e23d80813b1a535841f0048c1537d3f86d63c999e8373b39a9b0eb74a"
"checksum rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2791d88c6defac799c3f20d74f094ca33b9332612d9aef9078519c82e4fe04a5"
"checksum rayon 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "941deb43a6254b9867fec1e0caeda38a2ad905ab18c57f7c68c396ca68998c07"
"checksum rayon 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "655df67c314c30fa3055a365eae276eb88aa4f3413a352a1ab32c1320eda41ea"
"checksum regex 0.1.68 (registry+https://github.com/rust-lang/crates.io-index)" = "b4329b8928a284580a1c63ec9d846b12f6d3472317243ff7077aff11f23f2b29"
"checksum regex-syntax 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "841591b1e05609a643e3b4d0045fce04f701daba7151ddcd3ad47b080693d5a9"
"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"
@@ -1648,15 +1755,19 @@ dependencies = [
"checksum serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b76133a8a02f1c6ebd3fb9a2ecaab3d54302565a51320e80931adba571aadb1b"
"checksum serde_codegen 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c5b74ff4fb34013cc0b917dd182fefc05ee9af233b9d0d557078334554284d0e"
"checksum serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c88a751caa8f0000058fb971cd443ed2e6b653f33f5a47f29892a8bd44ca4c1"
"checksum sha1 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a307a40d5834140e4213a6952483b84e9ad53bdcab918b7335a6e305e505a53c"
"checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c"
"checksum slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d807fd58c4181bbabed77cb3b891ba9748241a552bcc5be698faaebefc54f46e"
"checksum slab 0.2.0 (git+https://github.com/carllerche/slab?rev=5476efcafb)" = "<none>"
"checksum slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6dbdd334bd28d328dad1c41b0ea662517883d8880d8533895ef96c8003dec9c4"
"checksum smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fcc8d19212aacecf95e4a7a2179b26f7aeb9732a915cf01f05b0d3e044865410"
"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 strsim 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e4d73a2c36a4d095ed1a6df5cbeac159863173447f7a82b3f4757426844ab825"
"checksum stable-heap 0.1.0 (git+https://github.com/carllerche/stable-heap?rev=3c5cd1ca47)" = "<none>"
"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 0.36.0 (registry+https://github.com/rust-lang/crates.io-index)" = "61dc0bbe1e46dcd53ec50d6600e750152c22e0e9352cadbd413e86fb847ae899"
"checksum syntex_syntax 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44bded3cabafc65c90b663b1071bd2d198a9ab7515e6ce729e4570aaf53c407e"
"checksum syntex_syntax 0.36.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2b92a8c33fad2fa99e14fe499ec17e82b6c6496a7a38a499f33b584ffa1886fa"
"checksum target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c63f48baada5c52e65a29eef93ab4f8982681b67f9e8d29c7b05abcfec2b9ffe"
"checksum term 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "f2077e54d38055cf1ca0fd7933a2e00cd3ec8f6fed352b2a377f06dcdaaf3281"
"checksum termios 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d9cf598a6d7ce700a4e6a9199da127e6819a61e64b68609683cc9a01b5683a"
@@ -1673,7 +1784,7 @@ dependencies = [
"checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172"
"checksum unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "36dff09cafb4ec7c8cf0023eb0b686cb6ce65499116a12201c9e11840ca01beb"
"checksum url 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f6d04073d0fcd045a1cf57aea560d1be5ba812d8f28814e1e1cf0e90ff4d2f03"
"checksum url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8ab4ca6f0107350f41a59a51cb0e71a04d905bc6a29181d2cb42fa4f040c65c9"
"checksum url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afe9ec54bc4db14bc8744b7fed060d785ac756791450959b2248443319d5b119"
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
"checksum uuid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9767696a9e1bc7a73f2d5f8e0f5428b076cecd9199c200c0364aa0b2d57b8dfa"
"checksum vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0795a11576d29ae80525a3fda315bf7b534f8feb9d34101e5fe63fb95bb2fd24"
@@ -1681,8 +1792,7 @@ dependencies = [
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4dfaaa8fbdaa618fa6914b59b2769d690dd7521920a18d84b42d254678dd5fd4"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
"checksum ws 0.5.0 (git+https://github.com/ethcore/ws-rs.git?branch=stable)" = "<none>"
"checksum ws 0.5.2 (git+https://github.com/ethcore/ws-rs.git?branch=mio-upstream-stable)" = "<none>"
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
"checksum xml-rs 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "4bac8fd82b24db2dd3b54aa7b29f336d8b5ca1830065ce3aada71bce6f661519"
"checksum xml-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f11ef7864e55d06a38755beaf03ab70139a04e619acfe94ef800b11bd79eb52c"
"checksum xml-rs 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "65e74b96bd3179209dc70a980da6df843dff09e46eee103a0376c0949257e3ef"
"checksum xmltree 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "472a9d37c7c53ab2391161df5b89b1f3bf76dab6ab150d7941ecbdd832282082"

View File

@@ -1,7 +1,7 @@
[package]
description = "Ethcore client."
name = "parity"
version = "1.3.0"
version = "1.3.10"
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}
@@ -59,6 +59,7 @@ ui = ["dapps", "ethcore-signer/ui"]
use-precompiled-js = ["ethcore-dapps/use-precompiled-js", "ethcore-signer/use-precompiled-js"]
dapps = ["ethcore-dapps"]
ipc = ["ethcore/ipc"]
jit = ["ethcore/jit"]
dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethcore-dapps/dev", "ethcore-signer/dev"]
json-tests = ["ethcore/json-tests"]
@@ -67,6 +68,6 @@ path = "parity/main.rs"
name = "parity"
[profile.release]
debug = true
debug = false
lto = false

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

@@ -10,8 +10,8 @@ build = "build.rs"
[dependencies]
log = "0.3"
jsonrpc-core = "2.0"
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc-http-server.git" }
jsonrpc-core = "2.1"
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"
@@ -21,11 +21,11 @@ serde_json = "0.7.0"
serde_macros = { version = "0.7.0", optional = true }
ethcore-rpc = { path = "../rpc" }
ethcore-util = { path = "../util" }
parity-dapps = { git = "https://github.com/ethcore/parity-ui.git", version = "0.6" }
parity-dapps = { git = "https://github.com/ethcore/parity-ui.git", version = "1.4" }
# List of apps
parity-dapps-status = { git = "https://github.com/ethcore/parity-ui.git", version = "0.6" }
parity-dapps-home = { git = "https://github.com/ethcore/parity-ui.git", version = "0.6" }
parity-dapps-wallet = { git = "https://github.com/ethcore/parity-ui.git", version = "0.6", optional = true }
parity-dapps-status = { git = "https://github.com/ethcore/parity-ui.git", version = "1.4" }
parity-dapps-home = { git = "https://github.com/ethcore/parity-ui.git", version = "1.4" }
parity-dapps-wallet = { git = "https://github.com/ethcore/parity-ui.git", version = "1.4", optional = true }
mime_guess = { version = "1.6.1" }
clippy = { version = "0.0.80", optional = true}

View File

@@ -100,14 +100,26 @@ impl ServerBuilder {
/// Asynchronously start server with no authentication,
/// returns result with `Server` handle on success or an error.
pub fn start_unsecure_http(&self, addr: &SocketAddr) -> Result<Server, ServerError> {
Server::start_http(addr, NoAuth, self.handler.clone(), self.dapps_path.clone())
pub fn start_unsecured_http(&self, addr: &SocketAddr, hosts: Option<Vec<String>>) -> Result<Server, ServerError> {
Server::start_http(
addr,
hosts,
NoAuth,
self.handler.clone(),
self.dapps_path.clone(),
)
}
/// Asynchronously start server with `HTTP Basic Authentication`,
/// return result with `Server` handle on success or an error.
pub fn start_basic_auth_http(&self, addr: &SocketAddr, username: &str, password: &str) -> Result<Server, ServerError> {
Server::start_http(addr, HttpBasicAuth::single_user(username, password), self.handler.clone(), self.dapps_path.clone())
pub fn start_basic_auth_http(&self, addr: &SocketAddr, hosts: Option<Vec<String>>, username: &str, password: &str) -> Result<Server, ServerError> {
Server::start_http(
addr,
hosts,
HttpBasicAuth::single_user(username, password),
self.handler.clone(),
self.dapps_path.clone(),
)
}
}
@@ -118,7 +130,28 @@ pub struct Server {
}
impl Server {
fn start_http<A: Authorization + 'static>(addr: &SocketAddr, authorization: A, handler: Arc<IoHandler>, dapps_path: String) -> Result<Server, ServerError> {
/// Returns a list of allowed hosts or `None` if all hosts are allowed.
fn allowed_hosts(hosts: Option<Vec<String>>, bind_address: String) -> Option<Vec<String>> {
let mut allowed = Vec::new();
match hosts {
Some(hosts) => allowed.extend_from_slice(&hosts),
None => return None,
}
// Add localhost domain as valid too if listening on loopback interface.
allowed.push(bind_address.replace("127.0.0.1", "localhost").into());
allowed.push(bind_address.into());
Some(allowed)
}
fn start_http<A: Authorization + 'static>(
addr: &SocketAddr,
hosts: Option<Vec<String>>,
authorization: A,
handler: Arc<IoHandler>,
dapps_path: String,
) -> Result<Server, ServerError> {
let panic_handler = Arc::new(Mutex::new(None));
let authorization = Arc::new(authorization);
let endpoints = Arc::new(apps::all_endpoints(dapps_path));
@@ -129,7 +162,7 @@ impl Server {
special.insert(router::SpecialEndpoint::Utils, apps::utils());
special
});
let bind_address = format!("{}", addr);
let hosts = Self::allowed_hosts(hosts, format!("{}", addr));
try!(hyper::Server::http(addr))
.handle(move |_| router::Router::new(
@@ -137,7 +170,7 @@ impl Server {
endpoints.clone(),
special.clone(),
authorization.clone(),
bind_address.clone(),
hosts.clone(),
))
.map(|(l, srv)| {
@@ -182,3 +215,24 @@ impl From<hyper::error::Error> for ServerError {
}
}
}
#[cfg(test)]
mod tests {
use super::Server;
#[test]
fn should_return_allowed_hosts() {
// given
let bind_address = "127.0.0.1".to_owned();
// when
let all = Server::allowed_hosts(None, bind_address.clone());
let address = Server::allowed_hosts(Some(Vec::new()), bind_address.clone());
let some = Server::allowed_hosts(Some(vec!["ethcore.io".into()]), bind_address.clone());
// then
assert_eq!(all, None);
assert_eq!(address, Some(vec!["localhost".into(), "127.0.0.1".into()]));
assert_eq!(some, Some(vec!["ethcore.io".into(), "localhost".into(), "127.0.0.1".into()]));
}
}

View File

@@ -22,14 +22,11 @@ use hyper::net::HttpStream;
use jsonrpc_http_server::{is_host_header_valid};
use handlers::ContentHandler;
pub fn is_valid(request: &server::Request<HttpStream>, bind_address: &str, endpoints: Vec<String>) -> bool {
let mut endpoints = endpoints.into_iter()
pub fn is_valid(request: &server::Request<HttpStream>, allowed_hosts: &[String], endpoints: Vec<String>) -> bool {
let mut endpoints = endpoints.iter()
.map(|endpoint| format!("{}{}", endpoint, DAPPS_DOMAIN))
.collect::<Vec<String>>();
// Add localhost domain as valid too if listening on loopback interface.
endpoints.push(bind_address.replace("127.0.0.1", "localhost").into());
endpoints.push(bind_address.into());
endpoints.extend_from_slice(allowed_hosts);
is_host_header_valid(request, &endpoints)
}

View File

@@ -45,7 +45,7 @@ pub struct Router<A: Authorization + 'static> {
endpoints: Arc<Endpoints>,
special: Arc<HashMap<SpecialEndpoint, Box<Endpoint>>>,
authorization: Arc<A>,
bind_address: String,
allowed_hosts: Option<Vec<String>>,
handler: Box<server::Handler<HttpStream> + Send>,
}
@@ -53,9 +53,11 @@ impl<A: Authorization + 'static> server::Handler<HttpStream> for Router<A> {
fn on_request(&mut self, req: server::Request<HttpStream>) -> Next {
// Validate Host header
if !host_validation::is_valid(&req, &self.bind_address, self.endpoints.keys().cloned().collect()) {
self.handler = host_validation::host_invalid_response();
return self.handler.on_request(req);
if let Some(ref hosts) = self.allowed_hosts {
if !host_validation::is_valid(&req, hosts, self.endpoints.keys().cloned().collect()) {
self.handler = host_validation::host_invalid_response();
return self.handler.on_request(req);
}
}
// Check authorization
@@ -114,7 +116,7 @@ impl<A: Authorization> Router<A> {
endpoints: Arc<Endpoints>,
special: Arc<HashMap<SpecialEndpoint, Box<Endpoint>>>,
authorization: Arc<A>,
bind_address: String,
allowed_hosts: Option<Vec<String>>,
) -> Self {
let handler = special.get(&SpecialEndpoint::Rpc).unwrap().to_handler(EndpointPath::default());
@@ -123,7 +125,7 @@ impl<A: Authorization> Router<A> {
endpoints: endpoints,
special: special,
authorization: authorization,
bind_address: bind_address,
allowed_hosts: allowed_hosts,
handler: handler,
}
}

View File

@@ -23,15 +23,9 @@ RUN rustup target add aarch64-unknown-linux-gnu
# show backtraces
ENV RUST_BACKTRACE 1
# set compilers
ENV CXX aarch64-linux-gnu-g++
ENV CC aarch64-linux-gnu-gcc
# show tools
RUN rustc -vV && \
cargo -V && \
gcc -v &&\
g++ -v
cargo -V
# build parity
RUN git clone https://github.com/ethcore/parity && \

View File

@@ -23,15 +23,9 @@ RUN rustup target add armv7-unknown-linux-gnueabihf
# show backtraces
ENV RUST_BACKTRACE 1
# set compilers
ENV CXX arm-linux-gnueabihf-g++
ENV CC arm-linux-gnueabihf-gcc
# show tools
RUN rustc -vV && \
cargo -V && \
gcc -v &&\
g++ -v
cargo -V
# build parity
RUN git clone https://github.com/ethcore/parity && \

View File

@@ -20,7 +20,7 @@ num_cpus = "0.2"
crossbeam = "0.2.9"
lazy_static = "0.2"
bloomchain = "0.1"
rayon = "0.3.1"
rayon = "0.4"
semver = "0.2"
bit-set = "0.4"
time = "0.1"
@@ -35,6 +35,9 @@ ethcore-ipc = { path = "../ipc/rpc" }
ethstore = { path = "../ethstore" }
ethcore-ipc-nano = { path = "../ipc/nano" }
rand = "0.3"
lru-cache = "0.0.7"
bloomfilter = { git = "https://github.com/ethcore/rust-bloom-filter" }
byteorder = "0.5"
[dependencies.hyper]
git = "https://github.com/ethcore/hyper"

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,12 @@
"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97",
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
]
],
"eip150Transition": "0x259518",
"eip155Transition": 2642462,
"eip160Transition": 2642462,
"eip161abcTransition": 2642462,
"eip161dTransition": 2642462
}
}
},

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

@@ -8,8 +8,13 @@
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar": "",
"frontierCompatibilityModeLimit": "0x789b0"
"registrar": "0x8e4e9b13d4b45cb0befc93c3061b1408f67316b2",
"homesteadTransition": "0x789b0",
"eip150Transition": "0x1b34d8",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
}
}
},
@@ -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

@@ -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

@@ -19,11 +19,15 @@
use util::*;
use pod_account::*;
use account_db::*;
use lru_cache::LruCache;
use std::cell::{Ref, RefCell};
use std::cell::{RefCell, Cell};
const STORAGE_CACHE_ITEMS: usize = 8192;
/// Single account in the system.
#[derive(Clone)]
/// 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,
@@ -31,14 +35,22 @@ pub struct Account {
nonce: U256,
// Trie-backed storage.
storage_root: H256,
// Overlay on trie-backed storage - tuple is (<clean>, <value>).
storage_overlay: RefCell<HashMap<H256, (Filth, H256)>>,
// Code hash of the account. If None, means that it's a contract whose code has not yet been set.
code_hash: Option<H256>,
// LRU Cache of the trie-backed storage.
// This is limited to `STORAGE_CACHE_ITEMS` recent queries
storage_cache: RefCell<LruCache<H256, H256>>,
// Modified storage. Accumulates changes to storage made in `set_storage`
// Takes precedence over `storage_cache`.
storage_changes: HashMap<H256, H256>,
// Code hash of the account.
code_hash: H256,
// Size of the accoun code.
code_size: Option<u64>,
// Code cache of the account.
code_cache: Bytes,
// Account is new or has been modified
filth: Filth,
code_cache: Arc<Bytes>,
// Account code new or has been modified.
code_filth: Filth,
// Cached address hash.
address_hash: Cell<Option<H256>>,
}
impl Account {
@@ -49,23 +61,33 @@ impl Account {
balance: balance,
nonce: nonce,
storage_root: SHA3_NULL_RLP,
storage_overlay: RefCell::new(storage.into_iter().map(|(k, v)| (k, (Filth::Dirty, v))).collect()),
code_hash: Some(code.sha3()),
code_cache: code,
filth: Filth::Dirty,
storage_cache: Self::empty_storage_cache(),
storage_changes: storage,
code_hash: code.sha3(),
code_size: Some(code.len() as u64),
code_cache: Arc::new(code),
code_filth: Filth::Dirty,
address_hash: Cell::new(None),
}
}
fn empty_storage_cache() -> RefCell<LruCache<H256, H256>> {
RefCell::new(LruCache::new(STORAGE_CACHE_ITEMS))
}
/// General constructor.
pub fn from_pod(pod: PodAccount) -> Account {
Account {
balance: pod.balance,
nonce: pod.nonce,
storage_root: SHA3_NULL_RLP,
storage_overlay: RefCell::new(pod.storage.into_iter().map(|(k, v)| (k, (Filth::Dirty, v))).collect()),
code_hash: pod.code.as_ref().map(|c| c.sha3()),
code_cache: pod.code.as_ref().map_or_else(|| { warn!("POD account with unknown code is being created! Assuming no code."); vec![] }, |c| c.clone()),
filth: Filth::Dirty,
storage_cache: Self::empty_storage_cache(),
storage_changes: pod.storage.into_iter().collect(),
code_hash: pod.code.as_ref().map_or(SHA3_EMPTY, |c| c.sha3()),
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)),
address_hash: Cell::new(None),
}
}
@@ -75,10 +97,13 @@ impl Account {
balance: balance,
nonce: nonce,
storage_root: SHA3_NULL_RLP,
storage_overlay: RefCell::new(HashMap::new()),
code_hash: Some(SHA3_EMPTY),
code_cache: vec![],
filth: Filth::Dirty,
storage_cache: Self::empty_storage_cache(),
storage_changes: HashMap::new(),
code_hash: SHA3_EMPTY,
code_cache: Arc::new(vec![]),
code_size: Some(0),
code_filth: Filth::Clean,
address_hash: Cell::new(None),
}
}
@@ -89,10 +114,13 @@ impl Account {
nonce: r.val_at(0),
balance: r.val_at(1),
storage_root: r.val_at(2),
storage_overlay: RefCell::new(HashMap::new()),
code_hash: Some(r.val_at(3)),
code_cache: vec![],
filth: Filth::Clean,
storage_cache: Self::empty_storage_cache(),
storage_changes: HashMap::new(),
code_hash: r.val_at(3),
code_cache: Arc::new(vec![]),
code_size: None,
code_filth: Filth::Clean,
address_hash: Cell::new(None),
}
}
@@ -103,47 +131,65 @@ impl Account {
balance: balance,
nonce: nonce,
storage_root: SHA3_NULL_RLP,
storage_overlay: RefCell::new(HashMap::new()),
code_hash: None,
code_cache: vec![],
filth: Filth::Dirty,
storage_cache: Self::empty_storage_cache(),
storage_changes: HashMap::new(),
code_hash: SHA3_EMPTY,
code_cache: Arc::new(vec![]),
code_size: None,
code_filth: Filth::Clean,
address_hash: Cell::new(None),
}
}
/// Set this account's code to the given code.
/// NOTE: Account should have been created with `new_contract()`
pub fn init_code(&mut self, code: Bytes) {
assert!(self.code_hash.is_none());
self.code_cache = code;
self.filth = Filth::Dirty;
self.code_hash = code.sha3();
self.code_cache = Arc::new(code);
self.code_size = Some(self.code_cache.len() as u64);
self.code_filth = Filth::Dirty;
}
/// Reset this account's code to the given code.
pub fn reset_code(&mut self, code: Bytes) {
self.code_hash = None;
self.init_code(code);
}
/// Set (and cache) the contents of the trie's storage at `key` to `value`.
pub fn set_storage(&mut self, key: H256, value: H256) {
self.storage_overlay.borrow_mut().insert(key, (Filth::Dirty, value));
self.filth = Filth::Dirty;
self.storage_changes.insert(key, value);
}
/// Get (and cache) the contents of the trie's storage at `key`.
/// Takes modifed storage into account.
pub fn storage_at(&self, db: &AccountDB, key: &H256) -> H256 {
self.storage_overlay.borrow_mut().entry(key.clone()).or_insert_with(||{
let db = SecTrieDB::new(db, &self.storage_root)
.expect("Account storage_root initially set to zero (valid) and only altered by SecTrieDBMut. \
SecTrieDBMut would not set it to an invalid state root. Therefore the root is valid and DB creation \
using it will not fail.");
if let Some(value) = self.cached_storage_at(key) {
return value;
}
let db = SecTrieDB::new(db, &self.storage_root)
.expect("Account storage_root initially set to zero (valid) and only altered by SecTrieDBMut. \
SecTrieDBMut would not set it to an invalid state root. Therefore the root is valid and DB creation \
using it will not fail.");
let item: U256 = match db.get(key){
Ok(x) => x.map_or_else(U256::zero, decode),
Err(e) => panic!("Encountered potential DB corruption: {}", e),
};
(Filth::Clean, item.into())
}).1.clone()
let item: U256 = match db.get(key){
Ok(x) => x.map_or_else(U256::zero, decode),
Err(e) => panic!("Encountered potential DB corruption: {}", e),
};
let value: H256 = item.into();
self.storage_cache.borrow_mut().insert(key.clone(), value.clone());
value
}
/// Get cached storage value if any. Returns `None` if the
/// key is not in the cache.
pub fn cached_storage_at(&self, key: &H256) -> Option<H256> {
if let Some(value) = self.storage_changes.get(key) {
return Some(value.clone())
}
if let Some(value) = self.storage_cache.borrow_mut().get_mut(key) {
return Some(value.clone())
}
None
}
/// return the balance associated with this account.
@@ -152,49 +198,52 @@ impl Account {
/// return the nonce associated with this account.
pub fn nonce(&self) -> &U256 { &self.nonce }
#[cfg(test)]
/// return the code hash associated with this account.
pub fn code_hash(&self) -> H256 {
self.code_hash.clone().unwrap_or(SHA3_EMPTY)
self.code_hash.clone()
}
/// return the code hash associated with this account.
pub fn address_hash(&self, address: &Address) -> H256 {
let hash = self.address_hash.get();
hash.unwrap_or_else(|| {
let hash = address.sha3();
self.address_hash.set(Some(hash.clone()));
hash
})
}
/// returns the account's code. If `None` then the code cache isn't available -
/// get someone who knows to call `note_code`.
pub fn code(&self) -> Option<&[u8]> {
match self.code_hash {
Some(c) if c == SHA3_EMPTY && self.code_cache.is_empty() => Some(&self.code_cache),
Some(_) if !self.code_cache.is_empty() => Some(&self.code_cache),
None => Some(&self.code_cache),
_ => None,
pub fn code(&self) -> Option<Arc<Bytes>> {
if self.code_hash != SHA3_EMPTY && self.code_cache.is_empty() {
return None;
}
Some(self.code_cache.clone())
}
/// returns the account's code size. If `None` then the code cache or code size cache isn't available -
/// get someone who knows to call `note_code`.
pub fn code_size(&self) -> Option<u64> {
self.code_size.clone()
}
#[cfg(test)]
/// Provide a byte array which hashes to the `code_hash`. returns the hash as a result.
pub fn note_code(&mut self, code: Bytes) -> Result<(), H256> {
let h = code.sha3();
match self.code_hash {
Some(ref i) if h == *i => {
self.code_cache = code;
Ok(())
},
_ => Err(h)
if self.code_hash == h {
self.code_cache = Arc::new(code);
self.code_size = Some(self.code_cache.len() as u64);
Ok(())
} else {
Err(h)
}
}
/// Is `code_cache` valid; such that code is going to return Some?
pub fn is_cached(&self) -> bool {
!self.code_cache.is_empty() || (self.code_cache.is_empty() && self.code_hash == Some(SHA3_EMPTY))
}
/// Is this a new or modified account?
pub fn is_dirty(&self) -> bool {
self.filth == Filth::Dirty
}
/// Mark account as clean.
pub fn set_clean(&mut self) {
self.filth = Filth::Clean
!self.code_cache.is_empty() || (self.code_cache.is_empty() && self.code_hash == SHA3_EMPTY)
}
/// Provide a database to get `code_hash`. Should not be called if it is a contract without code.
@@ -202,79 +251,115 @@ impl Account {
// TODO: fill out self.code_cache;
trace!("Account::cache_code: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty());
self.is_cached() ||
match self.code_hash {
Some(ref h) => match db.get(h) {
Some(x) => { self.code_cache = x.to_vec(); true },
match db.get(&self.code_hash) {
Some(x) => {
self.code_cache = Arc::new(x.to_vec());
self.code_size = Some(x.len() as u64);
true
},
_ => {
warn!("Failed reverse get of {}", self.code_hash);
false
},
}
}
/// Provide a database to get `code_size`. Should not be called if it is a contract without code.
pub fn cache_code_size(&mut self, db: &AccountDB) -> bool {
// TODO: fill out self.code_cache;
trace!("Account::cache_code_size: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty());
self.code_size.is_some() ||
if self.code_hash != SHA3_EMPTY {
match db.get(&self.code_hash) {
Some(x) => {
self.code_size = Some(x.len() as u64);
true
},
_ => {
warn!("Failed reverse get of {}", h);
warn!("Failed reverse get of {}", self.code_hash);
false
},
},
_ => false,
}
} else {
false
}
}
#[cfg(test)]
/// Determine whether there are any un-`commit()`-ed storage-setting operations.
pub fn storage_is_clean(&self) -> bool { self.storage_overlay.borrow().iter().find(|&(_, &(f, _))| f == Filth::Dirty).is_none() }
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} }
/// return the storage overlay.
pub fn storage_overlay(&self) -> Ref<HashMap<H256, (Filth, H256)>> { self.storage_overlay.borrow() }
pub fn storage_changes(&self) -> &HashMap<H256, H256> { &self.storage_changes }
/// 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) {
self.balance = self.balance + *x;
self.filth = Filth::Dirty;
}
/// 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) {
assert!(self.balance >= *x);
self.balance = self.balance - *x;
self.filth = Filth::Dirty;
}
/// Commit the `storage_overlay` to the backing DB and update `storage_root`.
/// Commit the `storage_changes` to the backing DB and update `storage_root`.
pub fn commit_storage(&mut self, trie_factory: &TrieFactory, db: &mut AccountDBMut) {
let mut t = trie_factory.from_existing(db, &mut self.storage_root)
.expect("Account storage_root initially set to zero (valid) and only altered by SecTrieDBMut. \
SecTrieDBMut would not set it to an invalid state root. Therefore the root is valid and DB creation \
using it will not fail.");
for (k, &mut (ref mut f, ref mut v)) in self.storage_overlay.borrow_mut().iter_mut() {
if f == &Filth::Dirty {
// cast key and value to trait type,
// so we can call overloaded `to_bytes` method
let res = match v.is_zero() {
true => t.remove(k),
false => t.insert(k, &encode(&U256::from(v.as_slice()))),
};
for (k, v) in self.storage_changes.drain() {
// cast key and value to trait type,
// so we can call overloaded `to_bytes` method
let res = match v.is_zero() {
true => t.remove(k.as_slice()),
false => t.insert(k.as_slice(), &encode(&U256::from(v.as_slice()))),
};
if let Err(e) = res {
warn!("Encountered potential DB corruption: {}", e);
}
*f = Filth::Clean;
if let Err(e) = res {
warn!("Encountered potential DB corruption: {}", e);
}
self.storage_cache.borrow_mut().insert(k, v);
}
}
/// Commit any unsaved code. `code_hash` will always return the hash of the `code_cache` after this.
pub fn commit_code(&mut self, db: &mut AccountDBMut) {
trace!("Commiting code of {:?} - {:?}, {:?}", self, self.code_hash.is_none(), self.code_cache.is_empty());
match (self.code_hash.is_none(), self.code_cache.is_empty()) {
(true, true) => self.code_hash = Some(SHA3_EMPTY),
trace!("Commiting code of {:?} - {:?}, {:?}", self, self.code_filth == Filth::Dirty, self.code_cache.is_empty());
match (self.code_filth == Filth::Dirty, self.code_cache.is_empty()) {
(true, true) => {
self.code_size = Some(0);
self.code_filth = Filth::Clean;
},
(true, false) => {
self.code_hash = Some(db.insert(&self.code_cache));
db.emplace(self.code_hash.clone(), (*self.code_cache).clone());
self.code_size = Some(self.code_cache.len() as u64);
self.code_filth = Filth::Clean;
},
(false, _) => {},
}
@@ -286,9 +371,59 @@ impl Account {
stream.append(&self.nonce);
stream.append(&self.balance);
stream.append(&self.storage_root);
stream.append(self.code_hash.as_ref().expect("Cannot form RLP of contract account without code."));
stream.append(&self.code_hash);
stream.out()
}
/// Clone basic account data
pub fn clone_basic(&self) -> Account {
Account {
balance: self.balance.clone(),
nonce: self.nonce.clone(),
storage_root: self.storage_root.clone(),
storage_cache: Self::empty_storage_cache(),
storage_changes: HashMap::new(),
code_hash: self.code_hash.clone(),
code_size: self.code_size.clone(),
code_cache: self.code_cache.clone(),
code_filth: self.code_filth,
address_hash: self.address_hash.clone(),
}
}
/// Clone account data and dirty storage keys
pub fn clone_dirty(&self) -> Account {
let mut account = self.clone_basic();
account.storage_changes = self.storage_changes.clone();
account.code_cache = self.code_cache.clone();
account
}
/// Clone account data, dirty storage keys and cached storage keys.
pub fn clone_all(&self) -> Account {
let mut account = self.clone_dirty();
account.storage_cache = self.storage_cache.clone();
account
}
/// 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;
self.code_hash = other.code_hash;
self.code_filth = other.code_filth;
self.code_cache = other.code_cache;
self.code_size = other.code_size;
self.address_hash = other.address_hash;
let mut cache = self.storage_cache.borrow_mut();
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;
}
}
impl fmt::Debug for Account {
@@ -383,7 +518,8 @@ mod tests {
let mut db = MemoryDB::new();
let mut db = AccountDBMut::new(&mut db, &Address::new());
a.init_code(vec![0x55, 0x44, 0xffu8]);
assert_eq!(a.code_hash(), SHA3_EMPTY);
assert_eq!(a.code_filth, Filth::Dirty);
assert_eq!(a.code_size(), Some(3));
a.commit_code(&mut db);
assert_eq!(a.code_hash().hex(), "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb");
}
@@ -394,11 +530,12 @@ mod tests {
let mut db = MemoryDB::new();
let mut db = AccountDBMut::new(&mut db, &Address::new());
a.init_code(vec![0x55, 0x44, 0xffu8]);
assert_eq!(a.code_hash(), SHA3_EMPTY);
assert_eq!(a.code_filth, Filth::Dirty);
a.commit_code(&mut db);
assert_eq!(a.code_filth, Filth::Clean);
assert_eq!(a.code_hash().hex(), "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb");
a.reset_code(vec![0x55]);
assert_eq!(a.code_hash(), SHA3_EMPTY);
assert_eq!(a.code_filth, Filth::Dirty);
a.commit_code(&mut db);
assert_eq!(a.code_hash().hex(), "37bf2238b11b68cdc8382cece82651b59d3c3988873b6e0f33d79694aa45f1be");
}

View File

@@ -43,6 +43,8 @@ impl ActionValue {
pub struct ActionParams {
/// Address of currently executed code.
pub code_address: Address,
/// Hash of currently executed code.
pub code_hash: H256,
/// Receive address. Usually equal to code_address,
/// except when called using CALLCODE.
pub address: Address,
@@ -57,7 +59,7 @@ pub struct ActionParams {
/// Transaction value.
pub value: ActionValue,
/// Code being executed.
pub code: Option<Bytes>,
pub code: Option<Arc<Bytes>>,
/// Input data.
pub data: Option<Bytes>,
/// Type of call
@@ -70,6 +72,7 @@ impl Default for ActionParams {
fn default() -> ActionParams {
ActionParams {
code_address: Address::new(),
code_hash: SHA3_EMPTY,
address: Address::new(),
sender: Address::new(),
origin: Address::new(),
@@ -88,10 +91,11 @@ impl From<ethjson::vm::Transaction> for ActionParams {
let address: Address = t.address.into();
ActionParams {
code_address: Address::new(),
code_hash: (&*t.code).sha3(),
address: address,
sender: t.sender.into(),
origin: t.origin.into(),
code: Some(t.code.into()),
code: Some(Arc::new(t.code.into())),
data: Some(t.data.into()),
gas: t.gas.into(),
gas_price: t.gas_price.into(),

View File

@@ -19,6 +19,7 @@
use common::*;
use engines::Engine;
use state::*;
use state_db::StateDB;
use verification::PreverifiedBlock;
use trace::FlatTrace;
use evm::Factory as EvmFactory;
@@ -178,7 +179,7 @@ pub trait IsBlock {
/// Trait for a object that has a state database.
pub trait Drain {
/// Drop this object and return the underlieing database.
fn drain(self) -> Box<JournalDB>;
fn drain(self) -> StateDB;
}
impl IsBlock for ExecutedBlock {
@@ -233,7 +234,7 @@ impl<'x> OpenBlock<'x> {
vm_factory: &'x EvmFactory,
trie_factory: TrieFactory,
tracing: bool,
db: Box<JournalDB>,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
author: Address,
@@ -394,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> {
@@ -465,7 +470,9 @@ impl LockedBlock {
impl Drain for LockedBlock {
/// Drop this object and return the underlieing database.
fn drain(self) -> Box<JournalDB> { self.block.state.drop().1 }
fn drain(self) -> StateDB {
self.block.state.drop().1
}
}
impl SealedBlock {
@@ -481,7 +488,9 @@ impl SealedBlock {
impl Drain for SealedBlock {
/// Drop this object and return the underlieing database.
fn drain(self) -> Box<JournalDB> { self.block.state.drop().1 }
fn drain(self) -> StateDB {
self.block.state.drop().1
}
}
impl IsBlock for SealedBlock {
@@ -496,7 +505,7 @@ pub fn enact(
uncles: &[Header],
engine: &Engine,
tracing: bool,
db: Box<JournalDB>,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
vm_factory: &EvmFactory,
@@ -505,7 +514,7 @@ pub fn enact(
{
if ::log::max_log_level() >= ::log::LogLevel::Trace {
let s = try!(State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce(), trie_factory.clone()));
trace!("enact(): root={}, author={}, author_balance={}\n", s.root(), header.author(), s.balance(&header.author()));
trace!(target: "enact", "num={}, root={}, author={}, author_balance={}\n", header.number(), s.root(), header.author(), s.balance(&header.author()));
}
}
@@ -529,7 +538,7 @@ pub fn enact_bytes(
block_bytes: &[u8],
engine: &Engine,
tracing: bool,
db: Box<JournalDB>,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
vm_factory: &EvmFactory,
@@ -546,7 +555,7 @@ pub fn enact_verified(
block: &PreverifiedBlock,
engine: &Engine,
tracing: bool,
db: Box<JournalDB>,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
vm_factory: &EvmFactory,
@@ -562,7 +571,7 @@ pub fn enact_and_seal(
block_bytes: &[u8],
engine: &Engine,
tracing: bool,
db: Box<JournalDB>,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
vm_factory: &EvmFactory,
@@ -582,75 +591,74 @@ mod tests {
fn open_block() {
use spec::*;
let spec = Spec::new_test();
let engine = &spec.engine;
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
spec.ensure_db_good(&mut db).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = OpenBlock::new(&*spec.engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close_and_lock();
let _ = b.seal(engine.deref(), vec![]);
let _ = b.seal(&*spec.engine, vec![]);
}
#[test]
fn enact_block() {
use spec::*;
let spec = Spec::new_test();
let engine = &spec.engine;
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
spec.ensure_db_good(&mut db).unwrap();
let vm_factory = Default::default();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap()
.close_and_lock().seal(engine.deref(), vec![]).unwrap();
let b = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap()
.close_and_lock().seal(engine, vec![]).unwrap();
let orig_bytes = b.rlp_bytes();
let orig_db = b.drain();
let mut db_result = get_temp_journal_db();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, last_hashes, &Default::default(), Default::default()).unwrap();
spec.ensure_db_good(&mut db).unwrap();
let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, &Default::default(), Default::default()).unwrap();
assert_eq!(e.rlp_bytes(), orig_bytes);
let db = e.drain();
assert_eq!(orig_db.keys(), db.keys());
assert!(orig_db.keys().iter().filter(|k| orig_db.get(k.0) != db.get(k.0)).next() == None);
assert_eq!(orig_db.journal_db().keys(), db.journal_db().keys());
assert!(orig_db.journal_db().keys().iter().filter(|k| orig_db.journal_db().get(k.0) != db.journal_db().get(k.0)).next() == None);
}
#[test]
fn enact_block_with_uncle() {
use spec::*;
let spec = Spec::new_test();
let engine = &spec.engine;
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
spec.ensure_db_good(&mut db).unwrap();
let vm_factory = Default::default();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut open_block = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut uncle1_header = Header::new();
uncle1_header.extra_data = b"uncle1".to_vec();
let mut uncle2_header = Header::new();
uncle2_header.extra_data = b"uncle2".to_vec();
open_block.push_uncle(uncle1_header).unwrap();
open_block.push_uncle(uncle2_header).unwrap();
let b = open_block.close_and_lock().seal(engine.deref(), vec![]).unwrap();
let b = open_block.close_and_lock().seal(engine, vec![]).unwrap();
let orig_bytes = b.rlp_bytes();
let orig_db = b.drain();
let mut db_result = get_temp_journal_db();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, last_hashes, &Default::default(), Default::default()).unwrap();
spec.ensure_db_good(&mut db).unwrap();
let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, &Default::default(), Default::default()).unwrap();
let bytes = e.rlp_bytes();
assert_eq!(bytes, orig_bytes);
@@ -658,7 +666,7 @@ mod tests {
assert_eq!(uncles[1].extra_data, b"uncle2");
let db = e.drain();
assert_eq!(orig_db.keys(), db.keys());
assert!(orig_db.keys().iter().filter(|k| orig_db.get(k.0) != db.get(k.0)).next() == None);
assert_eq!(orig_db.journal_db().keys(), db.journal_db().keys());
assert!(orig_db.journal_db().keys().iter().filter(|k| orig_db.journal_db().get(k.0) != db.journal_db().get(k.0)).next() == None);
}
}

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

@@ -31,7 +31,7 @@ pub struct BlockInfo {
}
/// Describes location of newly inserted block.
#[derive(Clone)]
#[derive(Debug, Clone)]
pub enum BlockLocation {
/// It's part of the canon chain.
CanonChain,
@@ -43,7 +43,7 @@ pub enum BlockLocation {
BranchBecomingCanonChain(BranchBecomingCanonChainData),
}
#[derive(Clone)]
#[derive(Debug, Clone)]
pub struct BranchBecomingCanonChainData {
/// Hash of the newest common ancestor with old canon chain.
pub ancestor: H256,

View File

@@ -133,8 +133,9 @@ enum CacheID {
impl bc::group::BloomGroupDatabase for BlockChain {
fn blooms_at(&self, position: &bc::group::GroupPosition) -> Option<bc::group::BloomGroup> {
let position = LogGroupPosition::from(position.clone());
self.note_used(CacheID::BlocksBlooms(position.clone()));
self.db.read_with_cache(DB_COL_EXTRA, &self.blocks_blooms, &position).map(Into::into)
let result = self.db.read_with_cache(DB_COL_EXTRA, &self.blocks_blooms, &position).map(Into::into);
self.note_used(CacheID::BlocksBlooms(position));
result
}
}
@@ -164,7 +165,7 @@ pub struct BlockChain {
pending_best_block: RwLock<Option<BestBlock>>,
pending_block_hashes: RwLock<HashMap<BlockNumber, H256>>,
pending_transaction_addresses: RwLock<HashMap<H256, TransactionAddress>>,
pending_transaction_addresses: RwLock<HashMap<H256, Option<TransactionAddress>>>,
}
impl BlockProvider for BlockChain {
@@ -211,9 +212,7 @@ impl BlockProvider for BlockChain {
let opt = self.db.get(DB_COL_HEADERS, hash)
.expect("Low level database error. Some issue with disk?");
self.note_used(CacheID::BlockHeader(hash.clone()));
match opt {
let result = match opt {
Some(b) => {
let bytes: Bytes = UntrustedRlp::new(&b).decompress(RlpType::Blocks).to_vec();
let mut write = self.block_headers.write();
@@ -221,7 +220,10 @@ impl BlockProvider for BlockChain {
Some(bytes)
},
None => None
}
};
self.note_used(CacheID::BlockHeader(hash.clone()));
result
}
/// Get block body data
@@ -246,9 +248,7 @@ impl BlockProvider for BlockChain {
let opt = self.db.get(DB_COL_BODIES, hash)
.expect("Low level database error. Some issue with disk?");
self.note_used(CacheID::BlockBody(hash.clone()));
match opt {
let result = match opt {
Some(b) => {
let bytes: Bytes = UntrustedRlp::new(&b).decompress(RlpType::Blocks).to_vec();
let mut write = self.block_bodies.write();
@@ -256,31 +256,39 @@ impl BlockProvider for BlockChain {
Some(bytes)
},
None => None
}
};
self.note_used(CacheID::BlockBody(hash.clone()));
result
}
/// Get the familial details concerning a block.
fn block_details(&self, hash: &H256) -> Option<BlockDetails> {
let result = self.db.read_with_cache(DB_COL_EXTRA, &self.block_details, hash);
self.note_used(CacheID::BlockDetails(hash.clone()));
self.db.read_with_cache(DB_COL_EXTRA, &self.block_details, hash)
result
}
/// Get the hash of given block's number.
fn block_hash(&self, index: BlockNumber) -> Option<H256> {
let result = self.db.read_with_cache(DB_COL_EXTRA, &self.block_hashes, &index);
self.note_used(CacheID::BlockHashes(index));
self.db.read_with_cache(DB_COL_EXTRA, &self.block_hashes, &index)
result
}
/// Get the address of transaction with given hash.
fn transaction_address(&self, hash: &H256) -> Option<TransactionAddress> {
let result = self.db.read_with_cache(DB_COL_EXTRA, &self.transaction_addresses, hash);
self.note_used(CacheID::TransactionAddresses(hash.clone()));
self.db.read_with_cache(DB_COL_EXTRA, &self.transaction_addresses, hash)
result
}
/// Get receipts of block with given hash.
fn block_receipts(&self, hash: &H256) -> Option<BlockReceipts> {
let result = self.db.read_with_cache(DB_COL_EXTRA, &self.block_receipts, hash);
self.note_used(CacheID::BlockReceipts(hash.clone()));
self.db.read_with_cache(DB_COL_EXTRA, &self.block_receipts, hash)
result
}
/// Returns numbers of blocks containing given bloom.
@@ -576,8 +584,8 @@ impl BlockChain {
block_hashes: self.prepare_block_hashes_update(bytes, &info),
block_details: self.prepare_block_details_update(bytes, &info),
block_receipts: self.prepare_block_receipts_update(receipts, &info),
transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
blocks_blooms: self.prepare_block_blooms_update(bytes, &info),
transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
info: info,
block: bytes
}, is_best);
@@ -610,8 +618,8 @@ impl BlockChain {
block_hashes: self.prepare_block_hashes_update(bytes, &info),
block_details: update,
block_receipts: self.prepare_block_receipts_update(receipts, &info),
transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
blocks_blooms: self.prepare_block_blooms_update(bytes, &info),
transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
info: info,
block: bytes,
}, is_best);
@@ -635,11 +643,12 @@ impl BlockChain {
let mut update = HashMap::new();
update.insert(block_hash, parent_details);
self.note_used(CacheID::BlockDetails(block_hash));
let mut write_details = self.block_details.write();
batch.extend_with_cache(DB_COL_EXTRA, &mut *write_details, update, CacheUpdatePolicy::Overwrite);
self.note_used(CacheID::BlockDetails(block_hash));
self.db.write(batch).unwrap();
}
@@ -678,8 +687,8 @@ impl BlockChain {
block_hashes: self.prepare_block_hashes_update(bytes, &info),
block_details: self.prepare_block_details_update(bytes, &info),
block_receipts: self.prepare_block_receipts_update(receipts, &info),
transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
blocks_blooms: self.prepare_block_blooms_update(bytes, &info),
transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
info: info.clone(),
block: bytes,
}, true);
@@ -730,12 +739,15 @@ impl BlockChain {
/// Prepares extras update.
fn prepare_update(&self, batch: &DBTransaction, update: ExtrasUpdate, is_best: bool) {
{
for hash in update.block_details.keys().cloned() {
self.note_used(CacheID::BlockDetails(hash));
}
let block_hashes: Vec<_> = update.block_details.keys().cloned().collect();
let mut write_details = self.block_details.write();
batch.extend_with_cache(DB_COL_EXTRA, &mut *write_details, update.block_details, CacheUpdatePolicy::Overwrite);
let mut cache_man = self.cache_man.write();
for hash in block_hashes.into_iter() {
cache_man.note_used(CacheID::BlockDetails(hash));
}
}
{
@@ -769,25 +781,45 @@ impl BlockChain {
let mut write_txs = self.pending_transaction_addresses.write();
batch.extend_with_cache(DB_COL_EXTRA, &mut *write_hashes, update.block_hashes, CacheUpdatePolicy::Overwrite);
batch.extend_with_cache(DB_COL_EXTRA, &mut *write_txs, update.transactions_addresses, CacheUpdatePolicy::Overwrite);
batch.extend_with_option_cache(DB_COL_EXTRA, &mut *write_txs, update.transactions_addresses, CacheUpdatePolicy::Overwrite);
}
}
/// Applt pending insertion updates
/// Apply pending insertion updates
pub fn commit(&self) {
let mut best_block = self.best_block.write();
let mut write_hashes = self.block_hashes.write();
let mut write_txs = self.transaction_addresses.write();
let mut pending_best_block = self.pending_best_block.write();
let mut pending_write_hashes = self.pending_block_hashes.write();
let mut pending_write_txs = self.pending_transaction_addresses.write();
let mut best_block = self.best_block.write();
let mut write_hashes = self.block_hashes.write();
let mut write_txs = self.transaction_addresses.write();
// update best block
if let Some(block) = pending_best_block.take() {
*best_block = block;
}
let pending_txs = mem::replace(&mut *pending_write_txs, HashMap::new());
let (retracted_txs, enacted_txs) = pending_txs.into_iter().partition::<HashMap<_, _>, _>(|&(_, ref value)| value.is_none());
let pending_hashes_keys: Vec<_> = pending_write_hashes.keys().cloned().collect();
let enacted_txs_keys: Vec<_> = enacted_txs.keys().cloned().collect();
write_hashes.extend(mem::replace(&mut *pending_write_hashes, HashMap::new()));
write_txs.extend(mem::replace(&mut *pending_write_txs, HashMap::new()));
write_txs.extend(enacted_txs.into_iter().map(|(k, v)| (k, v.expect("Transactions were partitioned; qed"))));
for hash in retracted_txs.keys() {
write_txs.remove(hash);
}
let mut cache_man = self.cache_man.write();
for n in pending_hashes_keys.into_iter() {
cache_man.note_used(CacheID::BlockHashes(n));
}
for hash in enacted_txs_keys {
cache_man.note_used(CacheID::TransactionAddresses(hash));
}
}
/// Iterator that lists `first` and then all of `first`'s ancestors, by hash.
@@ -887,19 +919,56 @@ impl BlockChain {
}
/// This function returns modified transaction addresses.
fn prepare_transaction_addresses_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap<H256, TransactionAddress> {
fn prepare_transaction_addresses_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap<H256, Option<TransactionAddress>> {
let block = BlockView::new(block_bytes);
let transaction_hashes = block.transaction_hashes();
transaction_hashes.into_iter()
.enumerate()
.fold(HashMap::new(), |mut acc, (i ,tx_hash)| {
acc.insert(tx_hash, TransactionAddress {
block_hash: info.hash.clone(),
index: i
match info.location {
BlockLocation::CanonChain => {
transaction_hashes.into_iter()
.enumerate()
.map(|(i ,tx_hash)| {
(tx_hash, Some(TransactionAddress {
block_hash: info.hash.clone(),
index: i
}))
})
.collect()
},
BlockLocation::BranchBecomingCanonChain(ref data) => {
let addresses = data.enacted.iter()
.flat_map(|hash| {
let bytes = self.block_body(hash).expect("Enacted block must be in database.");
let hashes = BodyView::new(&bytes).transaction_hashes();
hashes.into_iter()
.enumerate()
.map(|(i, tx_hash)| (tx_hash, Some(TransactionAddress {
block_hash: hash.clone(),
index: i,
})))
.collect::<HashMap<H256, Option<TransactionAddress>>>()
});
let current_addresses = transaction_hashes.into_iter()
.enumerate()
.map(|(i ,tx_hash)| {
(tx_hash, Some(TransactionAddress {
block_hash: info.hash.clone(),
index: i
}))
});
let retracted = data.retracted.iter().flat_map(|hash| {
let bytes = self.block_body(hash).expect("Retracted block must be in database.");
let hashes = BodyView::new(&bytes).transaction_hashes();
hashes.into_iter().map(|hash| (hash, None)).collect::<HashMap<H256, Option<TransactionAddress>>>()
});
acc
})
// The order here is important! Don't remove transaction if it was part of enacted blocks as well.
retracted.chain(addresses).chain(current_addresses).collect()
},
BlockLocation::Branch => HashMap::new(),
}
}
/// This functions returns modified blocks blooms.
@@ -992,16 +1061,18 @@ impl BlockChain {
/// Ticks our cache system and throws out any old data.
pub fn collect_garbage(&self) {
let mut cache_man = self.cache_man.write();
cache_man.collect_garbage(|| self.cache_size().total(), | ids | {
let mut block_headers = self.block_headers.write();
let mut block_bodies = self.block_bodies.write();
let mut block_details = self.block_details.write();
let mut block_hashes = self.block_hashes.write();
let mut transaction_addresses = self.transaction_addresses.write();
let mut blocks_blooms = self.blocks_blooms.write();
let mut block_receipts = self.block_receipts.write();
let current_size = self.cache_size().total();
let mut block_headers = self.block_headers.write();
let mut block_bodies = self.block_bodies.write();
let mut block_details = self.block_details.write();
let mut block_hashes = self.block_hashes.write();
let mut transaction_addresses = self.transaction_addresses.write();
let mut blocks_blooms = self.blocks_blooms.write();
let mut block_receipts = self.block_receipts.write();
let mut cache_man = self.cache_man.write();
cache_man.collect_garbage(current_size, | ids | {
for id in &ids {
match *id {
CacheID::BlockHeader(ref h) => { block_headers.remove(h); },
@@ -1013,6 +1084,7 @@ impl BlockChain {
CacheID::BlockReceipts(ref h) => { block_receipts.remove(h); }
}
}
block_headers.shrink_to_fit();
block_bodies.shrink_to_fit();
block_details.shrink_to_fit();
@@ -1020,6 +1092,14 @@ impl BlockChain {
transaction_addresses.shrink_to_fit();
blocks_blooms.shrink_to_fit();
block_receipts.shrink_to_fit();
block_headers.heap_size_of_children() +
block_bodies.heap_size_of_children() +
block_details.heap_size_of_children() +
block_hashes.heap_size_of_children() +
transaction_addresses.heap_size_of_children() +
blocks_blooms.heap_size_of_children() +
block_receipts.heap_size_of_children()
});
}
@@ -1036,7 +1116,6 @@ impl BlockChain {
#[cfg(test)]
mod tests {
#![cfg_attr(feature="dev", allow(similar_names))]
use std::str::FromStr;
use std::sync::Arc;
use rustc_serialize::hex::FromHex;
use util::{Database, DatabaseConfig};
@@ -1047,8 +1126,10 @@ mod tests {
use tests::helpers::*;
use devtools::*;
use blockchain::generator::{ChainGenerator, ChainIterator, BlockFinalizer};
use blockchain::extras::TransactionAddress;
use views::BlockView;
use client;
use transaction::{Transaction, Action};
fn new_db(path: &str) -> Arc<Database> {
Arc::new(Database::open(&DatabaseConfig::with_columns(client::DB_NO_OF_COLUMNS), path).unwrap())
@@ -1183,6 +1264,170 @@ mod tests {
// TODO: insert block that already includes one of them as an uncle to check it's not allowed.
}
#[test]
fn test_fork_transaction_addresses() {
let mut canon_chain = ChainGenerator::default();
let mut finalizer = BlockFinalizer::default();
let genesis = canon_chain.generate(&mut finalizer).unwrap();
let mut fork_chain = canon_chain.fork(1);
let mut fork_finalizer = finalizer.fork();
let t1 = Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 100_000.into(),
action: Action::Create,
value: 100.into(),
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
}.sign(&"".sha3(), None);
let b1a = canon_chain
.with_transaction(t1.clone())
.generate(&mut finalizer).unwrap();
// Empty block
let b1b = fork_chain
.generate(&mut fork_finalizer).unwrap();
let b2 = fork_chain
.generate(&mut fork_finalizer).unwrap();
let b1a_hash = BlockView::new(&b1a).header_view().sha3();
let b2_hash = BlockView::new(&b2).header_view().sha3();
let t1_hash = t1.hash();
let temp = RandomTempPath::new();
let db = new_db(temp.as_str());
let bc = BlockChain::new(Config::default(), &genesis, db.clone());
let mut batch = db.transaction();
let _ = bc.insert_block(&mut batch, &b1a, vec![]);
bc.commit();
let _ = bc.insert_block(&mut batch, &b1b, vec![]);
bc.commit();
db.write(batch).unwrap();
assert_eq!(bc.best_block_hash(), b1a_hash);
assert_eq!(bc.transaction_address(&t1_hash), Some(TransactionAddress {
block_hash: b1a_hash.clone(),
index: 0,
}));
// now let's make forked chain the canon chain
let mut batch = db.transaction();
let _ = bc.insert_block(&mut batch, &b2, vec![]);
bc.commit();
db.write(batch).unwrap();
// Transaction should be retracted
assert_eq!(bc.best_block_hash(), b2_hash);
assert_eq!(bc.transaction_address(&t1_hash), None);
}
#[test]
fn test_overwriting_transaction_addresses() {
let mut canon_chain = ChainGenerator::default();
let mut finalizer = BlockFinalizer::default();
let genesis = canon_chain.generate(&mut finalizer).unwrap();
let mut fork_chain = canon_chain.fork(1);
let mut fork_finalizer = finalizer.fork();
let t1 = Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 100_000.into(),
action: Action::Create,
value: 100.into(),
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
}.sign(&"".sha3(), None);
let t2 = Transaction {
nonce: 1.into(),
gas_price: 0.into(),
gas: 100_000.into(),
action: Action::Create,
value: 100.into(),
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
}.sign(&"".sha3(), None);
let t3 = Transaction {
nonce: 2.into(),
gas_price: 0.into(),
gas: 100_000.into(),
action: Action::Create,
value: 100.into(),
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
}.sign(&"".sha3(), None);
let b1a = canon_chain
.with_transaction(t1.clone())
.with_transaction(t2.clone())
.generate(&mut finalizer).unwrap();
// insert transactions in different order
let b1b = fork_chain
.with_transaction(t2.clone())
.with_transaction(t1.clone())
.generate(&mut fork_finalizer).unwrap();
let b2 = fork_chain
.with_transaction(t3.clone())
.generate(&mut fork_finalizer).unwrap();
let b1a_hash = BlockView::new(&b1a).header_view().sha3();
let b1b_hash = BlockView::new(&b1b).header_view().sha3();
let b2_hash = BlockView::new(&b2).header_view().sha3();
let t1_hash = t1.hash();
let t2_hash = t2.hash();
let t3_hash = t3.hash();
let temp = RandomTempPath::new();
let db = new_db(temp.as_str());
let bc = BlockChain::new(Config::default(), &genesis, db.clone());
let mut batch = db.transaction();
let _ = bc.insert_block(&mut batch, &b1a, vec![]);
bc.commit();
let _ = bc.insert_block(&mut batch, &b1b, vec![]);
bc.commit();
db.write(batch).unwrap();
assert_eq!(bc.best_block_hash(), b1a_hash);
assert_eq!(bc.transaction_address(&t1_hash), Some(TransactionAddress {
block_hash: b1a_hash.clone(),
index: 0,
}));
assert_eq!(bc.transaction_address(&t2_hash), Some(TransactionAddress {
block_hash: b1a_hash.clone(),
index: 1,
}));
// now let's make forked chain the canon chain
let mut batch = db.transaction();
let _ = bc.insert_block(&mut batch, &b2, vec![]);
bc.commit();
db.write(batch).unwrap();
assert_eq!(bc.best_block_hash(), b2_hash);
assert_eq!(bc.transaction_address(&t1_hash), Some(TransactionAddress {
block_hash: b1b_hash.clone(),
index: 1,
}));
assert_eq!(bc.transaction_address(&t2_hash), Some(TransactionAddress {
block_hash: b1b_hash.clone(),
index: 0,
}));
assert_eq!(bc.transaction_address(&t3_hash), Some(TransactionAddress {
block_hash: b2_hash.clone(),
index: 0,
}));
}
#[test]
#[cfg_attr(feature="dev", allow(cyclomatic_complexity))]
fn test_small_fork() {
@@ -1383,7 +1628,7 @@ mod tests {
fn find_transaction_by_hash() {
let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0af81e09f8c46ca322193edfda764fa7e88e81923f802f1d325ec0b0308ac2cd0a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200008083023e38808454c98c8142a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421880102030405060708c0c0".from_hex().unwrap();
let b1 = "f904a8f901faa0ce1f26f798dd03c8782d63b3e42e79a64eaea5694ea686ac5d7ce3df5171d1aea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0a65c2364cd0f1542d761823dc0109c6b072f14c20459598c5455c274601438f4a070616ebd7ad2ed6fb7860cf7e9df00163842351c38a87cac2c1cb193895035a2a05c5b4fc43c2d45787f54e1ae7d27afdb4ad16dfc567c5692070d5c4556e0b1d7b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200000183023ec683021536845685109780a029f07836e4e59229b3a065913afc27702642c683bba689910b2b2fd45db310d3888957e6d004a31802f902a7f85f800a8255f094aaaf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca0575da4e21b66fa764be5f74da9389e67693d066fb0d1312e19e17e501da00ecda06baf5a5327595f6619dfc2fcb3f2e6fb410b5810af3cb52d0e7508038e91a188f85f010a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba04fa966bf34b93abc1bcd665554b7f316b50f928477b50be0f3285ead29d18c5ba017bba0eeec1625ab433746955e125d46d80b7fdc97386c51266f842d8e02192ef85f020a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca004377418ae981cc32b1312b4a427a1d69a821b28db8584f5f2bd8c6d42458adaa053a1dba1af177fac92f3b6af0a9fa46a22adf56e686c93794b6a012bf254abf5f85f030a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca04fe13febd28a05f4fcb2f451d7ddc2dda56486d9f8c79a62b0ba4da775122615a0651b2382dd402df9ebc27f8cb4b2e0f3cea68dda2dca0ee9603608f0b6f51668f85f040a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba078e6a0ba086a08f8450e208a399bb2f2d2a0d984acd2517c7c7df66ccfab567da013254002cd45a97fac049ae00afbc43ed0d9961d0c56a3b2382c80ce41c198ddf85f050a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba0a7174d8f43ea71c8e3ca9477691add8d80ac8e0ed89d8d8b572041eef81f4a54a0534ea2e28ec4da3b5b944b18c51ec84a5cf35f5b3343c5fb86521fd2d388f506f85f060a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba034bd04065833536a10c77ee2a43a5371bc6d34837088b861dd9d4b7f44074b59a078807715786a13876d3455716a6b9cb2186b7a4887a5c31160fc877454958616c0".from_hex().unwrap();
let b1_hash = H256::from_str("f53f268d23a71e85c7d6d83a9504298712b84c1a2ba220441c86eeda0bf0b6e3").unwrap();
let b1_hash: H256 = "f53f268d23a71e85c7d6d83a9504298712b84c1a2ba220441c86eeda0bf0b6e3".into();
let temp = RandomTempPath::new();
let db = new_db(temp.as_str());
@@ -1411,11 +1656,11 @@ mod tests {
#[test]
fn test_bloom_filter_simple() {
// TODO: From here
let bloom_b1 = H2048::from_str("00000020000000000000000000000000000000000000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000002000").unwrap();
let bloom_b1: H2048 = "00000020000000000000000000000000000000000000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000002000".into();
let bloom_b2 = H2048::from_str("00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
let bloom_b2: H2048 = "00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into();
let bloom_ba = H2048::from_str("00000000000000000000000000000000000000000000020000000800000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
let bloom_ba: H2048 = "00000000000000000000000000000000000000000000020000000800000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into();
let mut canon_chain = ChainGenerator::default();
let mut finalizer = BlockFinalizer::default();

View File

@@ -176,7 +176,7 @@ impl Encodable for BlockDetails {
}
/// Represents address of certain transaction within block
#[derive(Clone)]
#[derive(Debug, PartialEq, Clone)]
pub struct TransactionAddress {
/// Block hash
pub block_hash: H256,

View File

@@ -16,7 +16,6 @@
use util::rlp::*;
use util::{H256, H2048};
use util::U256;
use util::bytes::Bytes;
use header::Header;
use transaction::SignedTransaction;
@@ -24,6 +23,7 @@ use transaction::SignedTransaction;
use super::fork::Forkable;
use super::bloom::WithBloom;
use super::complete::CompleteBlock;
use super::transaction::WithTransaction;
/// Helper structure, used for encoding blocks.
#[derive(Default)]
@@ -44,7 +44,8 @@ impl Encodable for Block {
impl Forkable for Block {
fn fork(mut self, fork_number: usize) -> Self where Self: Sized {
self.header.difficulty = self.header.difficulty - U256::from(fork_number);
let difficulty = self.header.difficulty().clone() - fork_number.into();
self.header.difficulty = difficulty;
self
}
}
@@ -56,6 +57,13 @@ impl WithBloom for Block {
}
}
impl WithTransaction for Block {
fn with_transaction(mut self, transaction: SignedTransaction) -> Self where Self: Sized {
self.transactions.push(transaction);
self
}
}
impl CompleteBlock for Block {
fn complete(mut self, parent_hash: H256) -> Bytes {
self.header.parent_hash = parent_hash;

View File

@@ -18,10 +18,12 @@ use util::hash::H2048;
use util::numbers::U256;
use util::bytes::Bytes;
use header::BlockNumber;
use transaction::SignedTransaction;
use super::fork::Fork;
use super::bloom::Bloom;
use super::complete::{BlockFinalizer, CompleteBlock, Complete};
use super::block::Block;
use super::transaction::Transaction;
/// Chain iterator interface.
pub trait ChainIterator: Iterator + Sized {
@@ -30,6 +32,8 @@ pub trait ChainIterator: Iterator + Sized {
fn fork(&self, fork_number: usize) -> Fork<Self> where Self: Clone;
/// Should be called to make every consecutive block have given bloom.
fn with_bloom(&mut self, bloom: H2048) -> Bloom<Self>;
/// Should be called to make every consecutive block have given transaction.
fn with_transaction(&mut self, transaction: SignedTransaction) -> Transaction<Self>;
/// Should be called to complete block. Without complete, block may have incorrect hash.
fn complete<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Complete<'a, Self>;
/// Completes and generates block.
@@ -51,6 +55,13 @@ impl<I> ChainIterator for I where I: Iterator + Sized {
}
}
fn with_transaction(&mut self, transaction: SignedTransaction) -> Transaction<Self> {
Transaction {
iter: self,
transaction: transaction,
}
}
fn complete<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Complete<'a, Self> {
Complete {
iter: self,
@@ -85,7 +96,7 @@ impl Default for ChainGenerator {
fn default() -> Self {
ChainGenerator {
number: 0,
difficulty: U256::from(1000),
difficulty: 1000.into(),
}
}
}

View File

@@ -21,6 +21,7 @@ mod block;
mod complete;
mod fork;
pub mod generator;
mod transaction;
pub use self::complete::BlockFinalizer;
pub use self::generator::{ChainIterator, ChainGenerator};

View File

@@ -0,0 +1,35 @@
// 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 transaction::SignedTransaction;
pub trait WithTransaction {
fn with_transaction(self, transaction: SignedTransaction) -> Self where Self: Sized;
}
pub struct Transaction<'a, I> where I: 'a {
pub iter: &'a mut I,
pub transaction: SignedTransaction,
}
impl <'a, I> Iterator for Transaction<'a, I> where I: Iterator, <I as Iterator>::Item: WithTransaction {
type Item = <I as Iterator>::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|item| item.with_transaction(self.transaction.clone()))
}
}

View File

@@ -17,8 +17,8 @@ pub struct ExtrasUpdate<'a> {
pub block_details: HashMap<H256, BlockDetails>,
/// Modified block receipts.
pub block_receipts: HashMap<H256, BlockReceipts>,
/// Modified transaction addresses.
pub transactions_addresses: HashMap<H256, TransactionAddress>,
/// Modified blocks blooms.
pub blocks_blooms: HashMap<LogGroupPosition, BloomGroup>,
/// Modified transaction addresses (None signifies removed transactions).
pub transactions_addresses: HashMap<H256, Option<TransactionAddress>>,
}

View File

@@ -45,16 +45,19 @@ impl<T> CacheManager<T> where T: Eq + Hash {
}
}
pub fn collect_garbage<C, F>(&mut self, current_size: C, mut notify_unused: F) where C: Fn() -> usize, F: FnMut(HashSet<T>) {
if current_size() < self.pref_cache_size {
/// Collects unused objects from cache.
/// First params is the current size of the cache.
/// Second one is an with objects to remove. It should also return new size of the cache.
pub fn collect_garbage<F>(&mut self, current_size: usize, mut notify_unused: F) where F: FnMut(HashSet<T>) -> usize {
if current_size < self.pref_cache_size {
self.rotate_cache_if_needed();
return;
}
for _ in 0..COLLECTION_QUEUE_SIZE {
notify_unused(self.cache_usage.pop_back().unwrap());
let current_size = notify_unused(self.cache_usage.pop_back().unwrap());
self.cache_usage.push_front(Default::default());
if current_size() < self.max_cache_size {
if current_size < self.max_cache_size {
break;
}
}

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

@@ -13,17 +13,17 @@
// 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::{HashSet, HashMap, VecDeque};
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;
// util
use util::{journaldb, rlp, Bytes, View, PerfTimer, Itertools, Mutex, RwLock};
use util::journaldb::JournalDB;
use util::rlp::{UntrustedRlp};
use util::numbers::*;
use util::sha3::*;
@@ -34,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;
@@ -49,8 +49,11 @@ use types::filter::Filter;
use log_entry::LocalizedLogEntry;
use block_queue::{BlockQueue, BlockQueueInfo};
use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute};
use client::{BlockID, TransactionID, UncleID, TraceId, ClientConfig, BlockChainClient, MiningBlockChainClient,
TraceFilter, CallAnalytics, BlockImportError, Mode, ChainNotify};
use client::{
BlockID, TransactionID, UncleID, TraceId, ClientConfig, BlockChainClient,
MiningBlockChainClient, TraceFilter, CallAnalytics, BlockImportError, Mode,
ChainNotify
};
use client::Error as ClientError;
use env_info::EnvInfo;
use executive::{Executive, Executed, TransactOptions, contract_address};
@@ -62,6 +65,7 @@ use evm::Factory as EvmFactory;
use miner::{Miner, MinerService};
use util::TrieFactory;
use snapshot::{self, io as snapshot_io};
use state_db::StateDB;
// re-export
pub use types::blockchain_info::BlockChainInfo;
@@ -70,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 {
@@ -121,7 +126,7 @@ pub struct Client {
tracedb: Arc<TraceDB<BlockChain>>,
engine: Arc<Engine>,
db: Arc<Database>,
state_db: Mutex<Box<JournalDB>>,
state_db: Mutex<StateDB>,
block_queue: BlockQueue,
report: RwLock<ClientReport>,
import_lock: Mutex<()>,
@@ -136,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);
@@ -151,15 +155,10 @@ pub const DB_COL_BODIES: Option<u32> = Some(2);
pub const DB_COL_EXTRA: Option<u32> = Some(3);
/// Column for Traces
pub const DB_COL_TRACE: Option<u32> = Some(4);
/// Column for Traces
pub const DB_COL_ACCOUNT_BLOOM: Option<u32> = Some(5);
/// Number of columns in DB
pub const DB_NO_OF_COLUMNS: Option<u32> = Some(5);
/// 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()
}
pub const DB_NO_OF_COLUMNS: Option<u32> = Some(6);
impl Client {
/// Create a new client with given spec and DB path and custom verifier.
@@ -177,18 +176,32 @@ 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())));
let mut state_db = journaldb::new(db.clone(), config.pruning, DB_COL_STATE);
if state_db.is_empty() && try!(spec.ensure_db_good(state_db.as_hashdb_mut())) {
let journal_db = journaldb::new(db.clone(), config.pruning, DB_COL_STATE);
let mut state_db = StateDB::new(journal_db);
if state_db.journal_db().is_empty() && try!(spec.ensure_db_good(&mut state_db)) {
let batch = DBTransaction::new(&db);
try!(state_db.commit(&batch, 0, &spec.genesis_header().hash(), None));
try!(db.write(batch).map_err(ClientError::Database));
}
if !chain.block_header(&chain.best_block_hash()).map_or(true, |h| state_db.contains(h.state_root())) {
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());
}
@@ -220,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))
}
@@ -245,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();
@@ -276,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(());
}
@@ -289,31 +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 db = 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>) {
@@ -344,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;
@@ -366,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);
}
@@ -420,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
};
@@ -435,12 +464,12 @@ 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.
// TODO: Prove it with a test.
block.drain().commit(&batch, number, hash, ancient).expect("DB commit failed.");
let mut state = block.drain();
state.commit(&batch, number, hash, ancient).expect("DB commit failed.");
let route = self.chain.insert_block(&batch, block_data, receipts);
self.tracedb.import(&batch, TraceImportRequest {
@@ -450,10 +479,11 @@ 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();
self.update_last_hashes(&parent, hash);
route
}
@@ -498,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;
}
@@ -525,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.")
@@ -594,19 +626,37 @@ impl Client {
}
}
/// Take a snapshot.
pub fn take_snapshot<W: snapshot_io::SnapshotWriter + Send>(&self, writer: W) -> Result<(), ::error::Error> {
let db = self.state_db.lock().boxed_clone();
/// Take a snapshot at the given block.
/// If the ID given is "latest", this will default to 1000 blocks behind.
pub fn take_snapshot<W: snapshot_io::SnapshotWriter + Send>(&self, writer: W, at: BlockID, p: &snapshot::Progress) -> Result<(), ::error::Error> {
let db = self.state_db.lock().journal_db().boxed_clone();
let best_block_number = self.chain_info().best_block_number;
let start_block_number = if best_block_number > 1000 {
best_block_number - 1000
} else {
0
};
let start_hash = self.block_hash(BlockID::Number(start_block_number))
.expect("blocks within HISTORY are always stored.");
let block_number = try!(self.block_number(at).ok_or(snapshot::Error::InvalidStartingBlock(at)));
try!(snapshot::take_snapshot(&self.chain, start_hash, db.as_hashdb(), writer));
if best_block_number > self.history + block_number && db.is_pruned() {
return Err(snapshot::Error::OldBlockPrunedDB.into());
}
let start_hash = match at {
BlockID::Latest => {
let start_num = if best_block_number > 1000 {
best_block_number - 1000
} else {
0
};
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,
None => return Err(snapshot::Error::InvalidStartingBlock(at).into()),
},
};
try!(snapshot::take_snapshot(&self.chain, start_hash, db.as_hashdb(), writer, p));
Ok(())
}
@@ -680,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));
@@ -784,8 +834,8 @@ impl BlockChainClient for Client {
Self::block_hash(&self.chain, id)
}
fn code(&self, address: &Address) -> Option<Bytes> {
self.state().code(address)
fn code(&self, address: &Address, id: BlockID) -> Option<Option<Bytes>> {
self.state_at(id).map(|s| s.code(address).map(|c| (*c).clone()))
}
fn balance(&self, address: &Address, id: BlockID) -> Option<U256> {
@@ -810,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();
@@ -833,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,
@@ -862,7 +913,7 @@ impl BlockChainClient for Client {
}
fn state_data(&self, hash: &H256) -> Option<Bytes> {
self.state_db.lock().state(hash)
self.state_db.lock().journal_db().state(hash)
}
fn block_receipts(&self, hash: &H256) -> Option<Bytes> {
@@ -900,6 +951,10 @@ impl BlockChainClient for Client {
}
}
fn additional_params(&self) -> BTreeMap<String, String> {
self.engine.additional_params().into_iter().collect()
}
fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockID, to_block: BlockID) -> Option<Vec<BlockNumber>> {
match (self.block_number(from_block), self.block_number(to_block)) {
(Some(from), Some(to)) => Some(self.chain.blocks_with_bloom(bloom, from, to)),
@@ -952,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,
}
}
@@ -1009,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())
}
}
@@ -1023,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,
@@ -1034,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
@@ -1057,8 +1121,10 @@ impl MiningBlockChainClient for Client {
let number = block.header().number();
let block_data = block.rlp_bytes();
// Clear canonical state 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

@@ -21,9 +21,11 @@ use util::*;
use devtools::*;
use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action};
use blockchain::TreeRoute;
use client::{BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockID,
TransactionID, UncleID, TraceId, TraceFilter, LastHashes, CallAnalytics,
BlockImportError};
use client::{
BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockID,
TransactionID, UncleID, TraceId, TraceFilter, LastHashes, CallAnalytics, BlockImportError,
DB_NO_OF_COLUMNS, DB_COL_STATE,
};
use header::{Header as BlockHeader, BlockNumber};
use filter::Filter;
use log_entry::LocalizedLogEntry;
@@ -39,6 +41,7 @@ use block::{OpenBlock, SealedBlock};
use executive::Executed;
use error::CallError;
use trace::LocalizedTrace;
use state_db::StateDB;
/// Test client.
pub struct TestBlockChainClient {
@@ -50,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.
@@ -96,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()),
@@ -118,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);
@@ -163,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);
@@ -190,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()
},
@@ -246,27 +258,28 @@ impl TestBlockChainClient {
}
}
pub fn get_temp_journal_db() -> GuardedTempResult<Box<JournalDB>> {
pub fn get_temp_state_db() -> GuardedTempResult<StateDB> {
let temp = RandomTempPath::new();
let db = Database::open_default(temp.as_str()).unwrap();
let journal_db = journaldb::new(Arc::new(db), journaldb::Algorithm::EarlyMerge, None);
let db = Database::open(&DatabaseConfig::with_columns(DB_NO_OF_COLUMNS), temp.as_str()).unwrap();
let journal_db = journaldb::new(Arc::new(db), journaldb::Algorithm::EarlyMerge, DB_COL_STATE);
let state_db = StateDB::new(journal_db);
GuardedTempResult {
_temp: temp,
result: Some(journal_db)
result: Some(state_db)
}
}
impl MiningBlockChainClient for TestBlockChainClient {
fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock {
let engine = &self.spec.engine;
let engine = &*self.spec.engine;
let genesis_header = self.spec.genesis_header();
let mut db_result = get_temp_journal_db();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
self.spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
self.spec.ensure_db_good(&mut db).unwrap();
let last_hashes = vec![genesis_header.hash()];
let mut open_block = OpenBlock::new(
engine.deref(),
engine,
self.vm_factory(),
Default::default(),
false,
@@ -319,8 +332,11 @@ impl BlockChainClient for TestBlockChainClient {
self.nonce(address, BlockID::Latest).unwrap()
}
fn code(&self, address: &Address) -> Option<Bytes> {
self.code.read().get(address).cloned()
fn code(&self, address: &Address, id: BlockID) -> Option<Option<Bytes>> {
match id {
BlockID::Latest => Some(self.code.read().get(address).cloned()),
_ => None,
}
}
fn balance(&self, address: &Address, id: BlockID) -> Option<U256> {
@@ -344,11 +360,11 @@ impl BlockChainClient for TestBlockChainClient {
}
fn transaction(&self, _id: TransactionID) -> Option<LocalizedTransaction> {
unimplemented!();
None
}
fn uncle(&self, _id: UncleID) -> Option<Bytes> {
unimplemented!();
None
}
fn transaction_receipt(&self, id: TransactionID) -> Option<LocalizedReceipt> {
@@ -479,9 +495,9 @@ impl BlockChainClient for TestBlockChainClient {
if number == len {
{
let mut difficulty = self.difficulty.write();
*difficulty.deref_mut() = *difficulty.deref() + header.difficulty;
*difficulty = *difficulty + header.difficulty;
}
mem::replace(self.last_hash.write().deref_mut(), h.clone());
mem::replace(&mut *self.last_hash.write(), h.clone());
self.blocks.write().insert(h.clone(), b);
self.numbers.write().insert(number, h.clone());
let mut parent_hash = header.parent_hash;
@@ -514,6 +530,10 @@ impl BlockChainClient for TestBlockChainClient {
fn clear_queue(&self) {
}
fn additional_params(&self) -> BTreeMap<String, String> {
Default::default()
}
fn chain_info(&self) -> BlockChainInfo {
BlockChainInfo {
total_difficulty: *self.difficulty.read(),
@@ -547,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

@@ -14,6 +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::collections::{BTreeMap};
use util::bytes::Bytes;
use util::hash::{Address, H256, H2048};
use util::numbers::U256;
@@ -36,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 {
@@ -81,8 +79,14 @@ pub trait BlockChainClient : Sync + Send {
/// Get block hash.
fn block_hash(&self, id: BlockID) -> Option<H256>;
/// Get address code.
fn code(&self, address: &Address) -> Option<Bytes>;
/// Get address code at given block's state.
fn code(&self, address: &Address, id: BlockID) -> Option<Option<Bytes>>;
/// Get address code at the latest block's state.
fn latest_code(&self, address: &Address) -> Option<Bytes> {
self.code(address, BlockID::Latest)
.expect("code will return Some if given BlockID::Latest; qed")
}
/// Get address balance at the given block's state.
///
@@ -144,6 +148,9 @@ pub trait BlockChainClient : Sync + Send {
/// Get blockchain information.
fn chain_info(&self) -> BlockChainInfo;
/// Get the registrar address, if it exists.
fn additional_params(&self) -> BTreeMap<String, String>;
/// Get the best block header.
fn best_block_header(&self) -> Bytes;
@@ -205,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

@@ -64,6 +64,9 @@ pub trait Writable {
/// Writes the value into the database.
fn write<T, R>(&self, col: Option<u32>, key: &Key<T, Target = R>, value: &T) where T: Encodable, R: Deref<Target = [u8]>;
/// Deletes key from the databse.
fn delete<T, R>(&self, col: Option<u32>, key: &Key<T, Target = R>) where T: Encodable, R: Deref<Target = [u8]>;
/// Writes the value into the database and updates the cache.
fn write_with_cache<K, T, R>(&self, col: Option<u32>, cache: &mut Cache<K, T>, key: K, value: T, policy: CacheUpdatePolicy) where
K: Key<T, Target = R> + Hash + Eq,
@@ -100,6 +103,34 @@ pub trait Writable {
},
}
}
/// Writes and removes the values into the database and updates the cache.
fn extend_with_option_cache<K, T, R>(&self, col: Option<u32>, cache: &mut Cache<K, Option<T>>, values: HashMap<K, Option<T>>, policy: CacheUpdatePolicy) where
K: Key<T, Target = R> + Hash + Eq,
T: Encodable,
R: Deref<Target = [u8]> {
match policy {
CacheUpdatePolicy::Overwrite => {
for (key, value) in values.into_iter() {
match value {
Some(ref v) => self.write(col, &key, v),
None => self.delete(col, &key),
}
cache.insert(key, value);
}
},
CacheUpdatePolicy::Remove => {
for (key, value) in values.into_iter() {
match value {
Some(v) => self.write(col, &key, &v),
None => self.delete(col, &key),
}
cache.remove(&key);
}
},
}
}
}
/// Should be used to read values from database.
@@ -154,6 +185,13 @@ impl Writable for DBTransaction {
panic!("db put failed, key: {:?}, err: {:?}", &key.key() as &[u8], err);
}
}
fn delete<T, R>(&self, col: Option<u32>, key: &Key<T, Target = R>) where T: Encodable, R: Deref<Target = [u8]> {
let result = DBTransaction::delete(self, col, &key.key());
if let Err(err) = result {
panic!("db delete failed, key: {:?}, err: {:?}", &key.key() as &[u8], err);
}
}
}
impl Readable for Database {

View File

@@ -246,16 +246,16 @@ mod tests {
tap.unlock_account_permanently(addr, "".into()).unwrap();
let spec = new_test_authority();
let engine = &spec.engine;
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
spec.ensure_db_good(&mut db).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close_and_lock();
let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap();
assert!(b.try_seal(engine.deref(), seal).is_ok());
assert!(b.try_seal(engine, seal).is_ok());
}
}

View File

@@ -80,18 +80,18 @@ mod tests {
let addr = tap.insert_account("".sha3(), "").unwrap();
let spec = new_test_instant();
let engine = &spec.engine;
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
spec.ensure_db_good(&mut db).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close_and_lock();
// Seal with empty AccountProvider.
let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap();
assert!(b.try_seal(engine.deref(), seal).is_ok());
assert!(b.try_seal(engine, seal).is_ok());
}
#[test]

View File

@@ -44,6 +44,9 @@ pub trait Engine : Sync + Send {
/// Additional engine-specific information for the user/developer concerning `header`.
fn extra_info(&self, _header: &Header) -> HashMap<String, String> { HashMap::new() }
/// Additional information.
fn additional_params(&self) -> HashMap<String, String> { HashMap::new() }
/// Get the general parameters of the chain.
fn params(&self) -> &CommonParams;
@@ -95,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,29 @@ 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,
}
impl From<ethjson::spec::EthashParams> for EthashParams {
@@ -56,10 +73,18 @@ 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),
homestead_transition: p.homestead_transition.map_or(0, Into::into),
dao_hardfork_transition: p.dao_hardfork_transition.map_or(0x7fffffffffffffff, 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(0x7fffffffffffffff, 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(0x7fffffffffffffff, 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(0x7fffffffffffffff, Into::into),
}
}
}
@@ -92,6 +117,7 @@ impl Engine for Ethash {
fn seal_fields(&self) -> usize { 2 }
fn params(&self) -> &CommonParams { &self.params }
fn additional_params(&self) -> HashMap<String, String> { hash_map!["registrar".to_owned() => self.ethash_params.registrar.hex()] }
fn builtins(&self) -> &BTreeMap<Address, Builtin> {
&self.builtins
@@ -103,12 +129,26 @@ 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(
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
}
}
@@ -143,7 +183,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);
}
// }
}
@@ -156,12 +196,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);
@@ -245,9 +285,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(())
}
@@ -267,7 +314,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 {
@@ -350,14 +397,14 @@ mod tests {
#[test]
fn on_close_block() {
let spec = new_morden();
let engine = &spec.engine;
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
spec.ensure_db_good(&mut db).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close();
assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap());
}
@@ -365,14 +412,14 @@ mod tests {
#[test]
fn on_close_block_with_uncle() {
let spec = new_morden();
let engine = &spec.engine;
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
spec.ensure_db_good(&mut db).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let vm_factory = Default::default();
let mut b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut b = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut uncle = Header::new();
let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106");
uncle.author = uncle_author.clone();

View File

@@ -44,8 +44,14 @@ 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")) }
@@ -65,9 +71,9 @@ mod tests {
let spec = new_morden();
let engine = &spec.engine;
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
spec.ensure_db_good(&mut db).unwrap();
let s = State::from_existing(db, genesis_header.state_root.clone(), engine.account_start_nonce(), Default::default()).unwrap();
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000001")), U256::from(1u64));
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000002")), U256::from(1u64));

View File

@@ -151,10 +151,14 @@ impl CostType for usize {
}
fn from_u256(val: U256) -> Result<Self> {
if U256::from(val.low_u64()) != val {
let res = val.low_u64() as usize;
// validate if value fits into usize
if U256::from(res) != val {
return Err(Error::OutOfGas);
}
Ok(val.low_u64() as usize)
Ok(res)
}
fn as_usize(&self) -> usize {
@@ -191,6 +195,7 @@ pub trait Evm {
#[test]
#[cfg(test)]
fn should_calculate_overflow_mul_shr_without_overflow() {
// given
let num = 1048576;
@@ -207,6 +212,7 @@ fn should_calculate_overflow_mul_shr_without_overflow() {
}
#[test]
#[cfg(test)]
fn should_calculate_overflow_mul_shr_with_overflow() {
// given
let max = ::std::u64::MAX;
@@ -225,3 +231,15 @@ fn should_calculate_overflow_mul_shr_with_overflow() {
assert!(o1);
}
#[test]
#[cfg(test)]
fn should_validate_u256_to_usize_conversion() {
// given
let v = U256::from(::std::usize::MAX) + U256::from(1);
// when
let res = usize::from_u256(v);
// then
assert!(res.is_err());
}

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;
@@ -81,7 +87,10 @@ pub trait Ext {
) -> MessageCallResult;
/// Returns code at given address
fn extcode(&self, address: &Address) -> Bytes;
fn extcode(&self, address: &Address) -> Arc<Bytes>;
/// Returns code length in bytes at given address
fn extcode_len(&self, address: &Address) -> u64;
/// Creates log entry with given topics and data
fn log(&mut self, topics: Vec<H256>, data: &[u8]);

View File

@@ -18,8 +18,10 @@
//!
//! TODO: consider spliting it into two separate files.
use std::fmt;
use std::sync::Arc;
use evm::Evm;
use util::{U256, Uint};
use super::interpreter::SharedCache;
#[derive(Debug, PartialEq, Clone)]
/// Type of EVM to use.
@@ -81,7 +83,8 @@ impl VMType {
/// Evm factory. Creates appropriate Evm.
pub struct Factory {
evm: VMType
evm: VMType,
evm_cache: Arc<SharedCache>,
}
impl Factory {
@@ -94,9 +97,9 @@ impl Factory {
Box::new(super::jit::JitEvm::default())
},
VMType::Interpreter => if Self::can_fit_in_usize(gas) {
Box::new(super::interpreter::Interpreter::<usize>::default())
Box::new(super::interpreter::Interpreter::<usize>::new(self.evm_cache.clone()))
} else {
Box::new(super::interpreter::Interpreter::<U256>::default())
Box::new(super::interpreter::Interpreter::<U256>::new(self.evm_cache.clone()))
}
}
}
@@ -107,9 +110,9 @@ impl Factory {
pub fn create(&self, gas: U256) -> Box<Evm> {
match self.evm {
VMType::Interpreter => if Self::can_fit_in_usize(gas) {
Box::new(super::interpreter::Interpreter::<usize>::default())
Box::new(super::interpreter::Interpreter::<usize>::new(self.evm_cache.clone()))
} else {
Box::new(super::interpreter::Interpreter::<U256>::default())
Box::new(super::interpreter::Interpreter::<U256>::new(self.evm_cache.clone()))
}
}
}
@@ -117,7 +120,8 @@ impl Factory {
/// Create new instance of specific `VMType` factory
pub fn new(evm: VMType) -> Self {
Factory {
evm: evm
evm: evm,
evm_cache: Arc::new(SharedCache::default()),
}
}
@@ -131,7 +135,8 @@ impl Default for Factory {
#[cfg(feature = "jit")]
fn default() -> Factory {
Factory {
evm: VMType::Jit
evm: VMType::Jit,
evm_cache: Arc::new(SharedCache::default()),
}
}
@@ -139,7 +144,8 @@ impl Default for Factory {
#[cfg(not(feature = "jit"))]
fn default() -> Factory {
Factory {
evm: VMType::Interpreter
evm: VMType::Interpreter,
evm_cache: Arc::new(SharedCache::default()),
}
}
}

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

@@ -31,10 +31,12 @@ macro_rules! evm_debug {
mod gasometer;
mod stack;
mod memory;
mod shared_cache;
use self::gasometer::Gasometer;
use self::stack::{Stack, VecStack};
use self::memory::Memory;
pub use self::shared_cache::SharedCache;
use std::marker::PhantomData;
use common::*;
@@ -53,6 +55,17 @@ fn color(instruction: Instruction, name: &'static str) -> String {
type CodePosition = usize;
type ProgramCounter = usize;
const ONE: U256 = U256([1, 0, 0, 0]);
const TWO: U256 = U256([2, 0, 0, 0]);
const TWO_POW_5: U256 = U256([0x20, 0, 0, 0]);
const TWO_POW_8: U256 = U256([0x100, 0, 0, 0]);
const TWO_POW_16: U256 = U256([0x10000, 0, 0, 0]);
const TWO_POW_24: U256 = U256([0x1000000, 0, 0, 0]);
const TWO_POW_64: U256 = U256([0, 0x1, 0, 0]); // 0x1 00000000 00000000
const TWO_POW_96: U256 = U256([0, 0x100000000, 0, 0]); //0x1 00000000 00000000 00000000
const TWO_POW_224: U256 = U256([0, 0, 0, 0x100000000]); //0x1 00000000 00000000 00000000 00000000 00000000 00000000 00000000
const TWO_POW_248: U256 = U256([0, 0, 0, 0x100000000000000]); //0x1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 000000
/// Abstraction over raw vector of Bytes. Easier state management of PC.
struct CodeReader<'a> {
position: ProgramCounter,
@@ -76,8 +89,6 @@ impl<'a> CodeReader<'a> {
enum InstructionResult<Gas> {
Ok,
UseAllGas,
GasLeft(Gas),
UnusedGas(Gas),
JumpToPosition(U256),
// gas left, init_orf, init_size
@@ -87,9 +98,9 @@ enum InstructionResult<Gas> {
/// Intepreter EVM implementation
#[derive(Default)]
pub struct Interpreter<Cost: CostType> {
mem: Vec<u8>,
cache: Arc<SharedCache>,
_type: PhantomData<Cost>,
}
@@ -98,7 +109,7 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
self.mem.clear();
let code = &params.code.as_ref().unwrap();
let valid_jump_destinations = self.find_jump_destinations(code);
let valid_jump_destinations = self.cache.jump_destinations(&params.code_hash, code);
let mut gasometer = Gasometer::<Cost>::new(try!(Cost::from_u256(params.gas)));
let mut stack = VecStack::with_capacity(ext.schedule().stack_limit, U256::zero());
@@ -116,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());
@@ -142,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;
@@ -169,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,
_ => {},
}
}
@@ -177,6 +183,14 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
}
impl<Cost: CostType> Interpreter<Cost> {
/// Create a new `Interpreter` instance with shared cache.
pub fn new(cache: Arc<SharedCache>) -> Interpreter<Cost> {
Interpreter {
mem: Vec::new(),
cache: cache,
_type: PhantomData::default(),
}
}
fn verify_instruction(&self, ext: &evm::Ext, instruction: Instruction, info: &InstructionInfo, stack: &Stack<U256>) -> evm::Result<()> {
let schedule = ext.schedule();
@@ -243,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 => {
@@ -268,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);
@@ -310,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
@@ -471,14 +487,14 @@ impl<Cost: CostType> Interpreter<Cost> {
},
instructions::EXTCODESIZE => {
let address = u256_to_address(&stack.pop_back());
let len = ext.extcode(&address).len();
let len = ext.extcode_len(&address);
stack.push(U256::from(len));
},
instructions::CALLDATACOPY => {
self.copy_data_to_memory(stack, &params.data.clone().unwrap_or_else(|| vec![]));
self.copy_data_to_memory(stack, params.data.as_ref().map_or_else(|| &[] as &[u8], |d| &*d as &[u8]));
},
instructions::CODECOPY => {
self.copy_data_to_memory(stack, &params.code.clone().unwrap_or_else(|| vec![]));
self.copy_data_to_memory(stack, params.code.as_ref().map_or_else(|| &[] as &[u8], |c| &**c as &[u8]));
},
instructions::EXTCODECOPY => {
let address = u256_to_address(&stack.pop_back());
@@ -515,11 +531,11 @@ impl<Cost: CostType> Interpreter<Cost> {
Ok(InstructionResult::Ok)
}
fn copy_data_to_memory(&mut self, stack: &mut Stack<U256>, data: &[u8]) {
fn copy_data_to_memory(&mut self, stack: &mut Stack<U256>, source: &[u8]) {
let dest_offset = stack.pop_back();
let source_offset = stack.pop_back();
let size = stack.pop_back();
let source_size = U256::from(data.len());
let source_size = U256::from(source.len());
let output_end = match source_offset > source_size || size > source_size || source_offset + size > source_size {
true => {
@@ -531,14 +547,14 @@ impl<Cost: CostType> Interpreter<Cost> {
for i in zero_slice.iter_mut() {
*i = 0;
}
data.len()
source.len()
},
false => (size.low_u64() + source_offset.low_u64()) as usize
};
if source_offset < source_size {
let output_begin = source_offset.low_u64() as usize;
self.mem.write_slice(dest_offset, &data[output_begin..output_end]);
self.mem.write_slice(dest_offset, &source[output_begin..output_end]);
}
}
@@ -599,7 +615,19 @@ impl<Cost: CostType> Interpreter<Cost> {
let a = stack.pop_back();
let b = stack.pop_back();
stack.push(if !self.is_zero(&b) {
a.overflowing_div(b).0
match b {
ONE => a,
TWO => a >> 1,
TWO_POW_5 => a >> 5,
TWO_POW_8 => a >> 8,
TWO_POW_16 => a >> 16,
TWO_POW_24 => a >> 24,
TWO_POW_64 => a >> 64,
TWO_POW_96 => a >> 96,
TWO_POW_224 => a >> 224,
TWO_POW_248 => a >> 248,
_ => a.overflowing_div(b).0,
}
} else {
U256::zero()
});
@@ -767,23 +795,6 @@ impl<Cost: CostType> Interpreter<Cost> {
Ok(())
}
fn find_jump_destinations(&self, code: &[u8]) -> BitSet {
let mut jump_dests = BitSet::with_capacity(code.len());
let mut position = 0;
while position < code.len() {
let instruction = code[position];
if instruction == instructions::JUMPDEST {
jump_dests.insert(position);
} else if instructions::is_push(instruction) {
position += instructions::get_push_bytes(instruction);
}
position += 1;
}
jump_dests
}
}
fn get_and_reset_sign(value: U256) -> (U256, bool) {
@@ -810,15 +821,3 @@ fn address_to_u256(value: Address) -> U256 {
U256::from(H256::from(value).as_slice())
}
#[test]
fn test_find_jump_destinations() {
// given
let interpreter = Interpreter::<U256>::default();
let code = "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b01600055".from_hex().unwrap();
// when
let valid_jump_destinations = interpreter.find_jump_destinations(&code);
// then
assert!(valid_jump_destinations.contains(66));
}

View File

@@ -0,0 +1,84 @@
// 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 std::sync::Arc;
use lru_cache::LruCache;
use util::{H256, Mutex};
use util::sha3::*;
use bit_set::BitSet;
use super::super::instructions;
const CACHE_CODE_ITEMS: usize = 65536;
/// GLobal cache for EVM interpreter
pub struct SharedCache {
jump_destinations: Mutex<LruCache<H256, Arc<BitSet>>>
}
impl SharedCache {
/// Get jump destincations bitmap for a contract.
pub fn jump_destinations(&self, code_hash: &H256, code: &[u8]) -> Arc<BitSet> {
if code_hash == &SHA3_EMPTY {
return Self::find_jump_destinations(code);
}
if let Some(d) = self.jump_destinations.lock().get_mut(code_hash) {
return d.clone();
}
let d = Self::find_jump_destinations(code);
self.jump_destinations.lock().insert(code_hash.clone(), d.clone());
d
}
fn find_jump_destinations(code: &[u8]) -> Arc<BitSet> {
let mut jump_dests = BitSet::with_capacity(code.len());
let mut position = 0;
while position < code.len() {
let instruction = code[position];
if instruction == instructions::JUMPDEST {
jump_dests.insert(position);
} else if instructions::is_push(instruction) {
position += instructions::get_push_bytes(instruction);
}
position += 1;
}
Arc::new(jump_dests)
}
}
impl Default for SharedCache {
fn default() -> SharedCache {
SharedCache {
jump_destinations: Mutex::new(LruCache::new(CACHE_CODE_ITEMS)),
}
}
}
#[test]
fn test_find_jump_destinations() {
use util::FromHex;
// given
let code = "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b01600055".from_hex().unwrap();
// when
let valid_jump_destinations = SharedCache::find_jump_destinations(&code);
// then
assert!(valid_jump_destinations.contains(66));
}

View File

@@ -18,6 +18,7 @@
use common::*;
use evmjit;
use evm::{self, GasLeft};
use types::executed::CallType;
/// Should be used to convert jit types to ethcore
trait FromJit<T>: Sized {
@@ -77,10 +78,11 @@ impl IntoJit<evmjit::I256> for U256 {
impl IntoJit<evmjit::I256> for H256 {
fn into_jit(self) -> evmjit::I256 {
let mut ret = [0; 4];
for i in 0..self.bytes().len() {
let rev = self.bytes().len() - 1 - i;
let len = self.len();
for i in 0..len {
let rev = len - 1 - i;
let pos = rev / 8;
ret[pos] += (self.bytes()[i] as u64) << ((rev % 8) * 8);
ret[pos] += (self[i] as u64) << ((rev % 8) * 8);
}
evmjit::I256 { words: ret }
}
@@ -194,6 +196,7 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> {
receive_address: *const evmjit::H256,
code_address: *const evmjit::H256,
transfer_value: *const evmjit::I256,
// Ignoring apparent value - it's handled correctly in executive.
_apparent_value: *const evmjit::I256,
in_beg: *const u8,
in_size: u64,
@@ -207,10 +210,12 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> {
let receive_address = unsafe { Address::from_jit(&*receive_address) };
let code_address = unsafe { Address::from_jit(&*code_address) };
let transfer_value = unsafe { U256::from_jit(&*transfer_value) };
let value = Some(transfer_value);
// receive address and code address are the same in normal calls
let is_callcode = receive_address != code_address;
let is_delegatecall = is_callcode && sender_address != receive_address;
let value = if is_delegatecall { None } else { Some(transfer_value) };
if !is_callcode && !self.ext.exists(&code_address) {
gas_cost = gas_cost + U256::from(self.ext.schedule().call_new_account_gas);
@@ -239,6 +244,12 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> {
}
}
let call_type = match (is_callcode, is_delegatecall) {
(_, true) => CallType::DelegateCall,
(true, false) => CallType::CallCode,
(false, false) => CallType::Call,
};
match self.ext.call(
&call_gas,
&sender_address,
@@ -246,7 +257,9 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> {
value,
unsafe { slice::from_raw_parts(in_beg, in_size as usize) },
&code_address,
unsafe { slice::from_raw_parts_mut(out_beg, out_size as usize) }) {
unsafe { slice::from_raw_parts_mut(out_beg, out_size as usize) },
call_type,
) {
evm::MessageCallResult::Success(gas_left) => unsafe {
*io_gas = (gas + gas_left).low_u64();
true

View File

@@ -80,6 +80,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 +110,53 @@ impl Schedule {
Self::new(true, true, 53000)
}
/// Schedule for the post-EIP-150-era of the Ethereum main net.
pub fn new_post_eip150(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,
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,
@@ -126,6 +188,14 @@ impl Schedule {
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

@@ -49,7 +49,7 @@ pub struct FakeExt {
depth: usize,
store: HashMap<H256, H256>,
blockhashes: HashMap<U256, H256>,
codes: HashMap<Address, Bytes>,
codes: HashMap<Address, Arc<Bytes>>,
logs: Vec<FakeLogEntry>,
_suicides: HashSet<Address>,
info: EnvInfo,
@@ -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()
}
@@ -136,8 +144,12 @@ impl Ext for FakeExt {
MessageCallResult::Success(*gas)
}
fn extcode(&self, address: &Address) -> Bytes {
self.codes.get(address).unwrap_or(&Bytes::new()).clone()
fn extcode(&self, address: &Address) -> Arc<Bytes> {
self.codes.get(address).unwrap_or(&Arc::new(Bytes::new())).clone()
}
fn extcode_len(&self, address: &Address) -> u64 {
self.codes.get(address).map_or(0, |c| c.len() as u64)
}
fn log(&mut self, topics: Vec<H256>, data: &[u8]) {
@@ -180,11 +192,11 @@ fn test_stack_underflow() {
let mut params = ActionParams::default();
params.address = address.clone();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let err = {
let mut vm : Box<evm::Evm> = Box::new(super::interpreter::Interpreter::<usize>::default());
let mut vm : Box<evm::Evm> = Box::new(super::interpreter::Interpreter::<usize>::new(Arc::new(super::interpreter::SharedCache::default())));
test_finalize(vm.exec(params, &mut ext)).unwrap_err()
};
@@ -207,7 +219,7 @@ fn test_add(factory: super::Factory) {
let mut params = ActionParams::default();
params.address = address.clone();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -227,7 +239,7 @@ fn test_sha3(factory: super::Factory) {
let mut params = ActionParams::default();
params.address = address.clone();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -247,7 +259,7 @@ fn test_address(factory: super::Factory) {
let mut params = ActionParams::default();
params.address = address.clone();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -269,7 +281,7 @@ fn test_origin(factory: super::Factory) {
params.address = address.clone();
params.origin = origin.clone();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -291,7 +303,7 @@ fn test_sender(factory: super::Factory) {
params.address = address.clone();
params.sender = sender.clone();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -325,9 +337,9 @@ fn test_extcodecopy(factory: super::Factory) {
params.address = address.clone();
params.sender = sender.clone();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
ext.codes.insert(sender, sender_code);
ext.codes.insert(sender, Arc::new(sender_code));
let gas_left = {
let mut vm = factory.create(params.gas);
@@ -346,7 +358,7 @@ fn test_log_empty(factory: super::Factory) {
let mut params = ActionParams::default();
params.address = address.clone();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -378,7 +390,7 @@ fn test_log_sender(factory: super::Factory) {
params.address = address.clone();
params.sender = sender.clone();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -402,7 +414,7 @@ fn test_blockhash(factory: super::Factory) {
let mut params = ActionParams::default();
params.address = address.clone();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
ext.blockhashes.insert(U256::zero(), blockhash.clone());
@@ -424,7 +436,7 @@ fn test_calldataload(factory: super::Factory) {
let mut params = ActionParams::default();
params.address = address.clone();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
params.data = Some(data);
let mut ext = FakeExt::new();
@@ -445,7 +457,7 @@ fn test_author(factory: super::Factory) {
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
ext.info.author = author;
@@ -465,7 +477,7 @@ fn test_timestamp(factory: super::Factory) {
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
ext.info.timestamp = timestamp;
@@ -485,7 +497,7 @@ fn test_number(factory: super::Factory) {
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
ext.info.number = number;
@@ -505,7 +517,7 @@ fn test_difficulty(factory: super::Factory) {
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
ext.info.difficulty = difficulty;
@@ -525,7 +537,7 @@ fn test_gas_limit(factory: super::Factory) {
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
ext.info.gas_limit = gas_limit;
@@ -544,7 +556,7 @@ fn test_mul(factory: super::Factory) {
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -562,7 +574,7 @@ fn test_sub(factory: super::Factory) {
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -580,7 +592,7 @@ fn test_div(factory: super::Factory) {
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -598,7 +610,7 @@ fn test_div_zero(factory: super::Factory) {
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -616,7 +628,7 @@ fn test_mod(factory: super::Factory) {
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -635,7 +647,7 @@ fn test_smod(factory: super::Factory) {
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -654,7 +666,7 @@ fn test_sdiv(factory: super::Factory) {
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -673,7 +685,7 @@ fn test_exp(factory: super::Factory) {
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -693,7 +705,7 @@ fn test_comparison(factory: super::Factory) {
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -714,7 +726,7 @@ fn test_signed_comparison(factory: super::Factory) {
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -735,7 +747,7 @@ fn test_bitops(factory: super::Factory) {
let mut params = ActionParams::default();
params.gas = U256::from(150_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -758,7 +770,7 @@ fn test_addmod_mulmod(factory: super::Factory) {
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -779,7 +791,7 @@ fn test_byte(factory: super::Factory) {
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -798,7 +810,7 @@ fn test_signextend(factory: super::Factory) {
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -818,7 +830,7 @@ fn test_badinstruction_int() {
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let err = {
@@ -838,7 +850,7 @@ fn test_pop(factory: super::Factory) {
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -858,7 +870,7 @@ fn test_extops(factory: super::Factory) {
params.gas = U256::from(150_000);
params.gas_price = U256::from(0x32);
params.value = ActionValue::Transfer(U256::from(0x99));
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -881,7 +893,7 @@ fn test_jumps(factory: super::Factory) {
let mut params = ActionParams::default();
params.gas = U256::from(150_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new();
let gas_left = {
@@ -904,7 +916,7 @@ fn test_calls(factory: super::Factory) {
let code_address = Address::from(0x998);
let mut params = ActionParams::default();
params.gas = U256::from(150_000);
params.code = Some(code);
params.code = Some(Arc::new(code));
params.address = address.clone();
let mut ext = FakeExt::new();
ext.balances = {

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.
@@ -167,13 +168,14 @@ impl<'a> Executive<'a> {
let new_address = contract_address(&sender, &nonce);
let params = ActionParams {
code_address: new_address.clone(),
code_hash: t.data.sha3(),
address: new_address,
sender: sender.clone(),
origin: sender.clone(),
gas: init_gas,
gas_price: t.gas_price,
value: ActionValue::Transfer(t.value),
code: Some(t.data.clone()),
code: Some(Arc::new(t.data.clone())),
data: None,
call_type: CallType::None,
};
@@ -189,6 +191,7 @@ impl<'a> Executive<'a> {
gas_price: t.gas_price,
value: ActionValue::Transfer(t.value),
code: self.state.code(address),
code_hash: self.state.code_hash(address),
data: Some(t.data.clone()),
call_type: CallType::Call,
};
@@ -210,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);
@@ -246,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);
@@ -263,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 {
@@ -283,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![]);
@@ -329,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)
@@ -354,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);
@@ -395,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>,
@@ -411,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;
@@ -421,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(_) => {
@@ -471,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);
}
}
@@ -493,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() {
@@ -510,11 +537,11 @@ mod tests {
params.address = address.clone();
params.sender = sender.clone();
params.gas = U256::from(100_000);
params.code = Some("3331600055".from_hex().unwrap());
params.code = Some(Arc::new("3331600055".from_hex().unwrap()));
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();
@@ -569,11 +596,11 @@ mod tests {
params.sender = sender.clone();
params.origin = sender.clone();
params.gas = U256::from(100_000);
params.code = Some(code.clone());
params.code = Some(Arc::new(code));
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();
@@ -624,12 +651,12 @@ mod tests {
params.sender = sender.clone();
params.origin = sender.clone();
params.gas = U256::from(100_000);
params.code = Some(code.clone());
params.code = Some(Arc::new(code));
params.value = ActionValue::Transfer(U256::from(100));
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();
@@ -687,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() }) }) }
],
@@ -734,11 +761,11 @@ mod tests {
params.sender = sender.clone();
params.origin = sender.clone();
params.gas = U256::from(100_000);
params.code = Some(code.clone());
params.code = Some(Arc::new(code));
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();
@@ -822,11 +849,11 @@ mod tests {
params.sender = sender.clone();
params.origin = sender.clone();
params.gas = U256::from(100_000);
params.code = Some(code.clone());
params.code = Some(Arc::new(code));
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();
@@ -874,11 +901,11 @@ mod tests {
params.sender = sender.clone();
params.origin = sender.clone();
params.gas = U256::from(100_000);
params.code = Some(code.clone());
params.code = Some(Arc::new(code));
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();
@@ -931,14 +958,14 @@ mod tests {
params.address = address_a.clone();
params.sender = sender.clone();
params.gas = U256::from(100_000);
params.code = Some(code_a.clone());
params.code = Some(Arc::new(code_a.clone()));
params.value = ActionValue::Transfer(U256::from(100_000));
let mut state_result = get_temp_state();
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);
@@ -981,10 +1008,10 @@ mod tests {
let mut params = ActionParams::default();
params.address = address.clone();
params.gas = U256::from(100_000);
params.code = Some(code.clone());
params.code = Some(Arc::new(code.clone()));
let mut state_result = get_temp_state();
let mut state = state_result.reference_mut();
state.init_code(&address, code.clone());
state.init_code(&address, code);
let info = EnvInfo::default();
let engine = TestEngine::new(0);
let mut substate = Substate::new();
@@ -1011,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);
@@ -1078,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);
@@ -1111,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);
@@ -1146,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);
@@ -1182,11 +1209,11 @@ mod tests {
params.sender = sender.clone();
params.origin = sender.clone();
params.gas = U256::from(0x0186a0);
params.code = Some(code.clone());
params.code = Some(Arc::new(code));
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)
}
@@ -147,7 +153,8 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
gas: *gas,
gas_price: self.origin_info.gas_price,
value: ActionValue::Transfer(*value),
code: Some(code.to_vec()),
code: Some(Arc::new(code.to_vec())),
code_hash: code.sha3(),
data: None,
call_type: CallType::None,
};
@@ -186,6 +193,7 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
gas: *gas,
gas_price: self.origin_info.gas_price,
code: self.state.code(code_address),
code_hash: self.state.code_hash(code_address),
data: Some(data.to_vec()),
call_type: call_type,
};
@@ -202,8 +210,12 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
}
}
fn extcode(&self, address: &Address) -> Bytes {
self.state.code(address).unwrap_or_else(|| vec![])
fn extcode(&self, address: &Address) -> Arc<Bytes> {
self.state.code(address).unwrap_or_else(|| Arc::new(vec![]))
}
fn extcode_len(&self, address: &Address) -> u64 {
self.state.code_size(address).unwrap_or(0)
}
#[cfg_attr(feature="dev", allow(match_ref_pats))]
@@ -260,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)
}
@@ -128,10 +136,14 @@ impl<'a, T, V> Ext for TestExt<'a, T, V> where T: Tracer, V: VMTracer {
MessageCallResult::Success(*gas)
}
fn extcode(&self, address: &Address) -> Bytes {
fn extcode(&self, address: &Address) -> Arc<Bytes> {
self.ext.extcode(address)
}
fn extcode_len(&self, address: &Address) -> u64 {
self.ext.extcode_len(address)
}
fn log(&mut self, topics: Vec<H256>, data: &[u8]) {
self.ext.log(topics, data)
}
@@ -229,7 +241,7 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
for (address, account) in vm.post_state.unwrap().into_iter() {
let address = address.into();
let code: Vec<u8> = account.code.into();
fail_unless(state.code(&address).unwrap_or_else(Vec::new) == code, "code is incorrect");
fail_unless(state.code(&address).as_ref().map_or_else(|| code.is_empty(), |c| &**c == &code), "code is incorrect");
fail_unless(state.balance(&address) == account.balance.into(), "balance is incorrect");
fail_unless(state.nonce(&address) == account.nonce.into(), "nonce is incorrect");
account.storage.into_iter().foreach(|(k, v)| {

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

@@ -26,6 +26,8 @@
#![cfg_attr(feature="dev", allow(match_bool))]
// Keeps consistency (all lines with `.clone()`).
#![cfg_attr(feature="dev", allow(clone_on_copy))]
// Complains on Box<E> when implementing From<Box<E>>
#![cfg_attr(feature="dev", allow(boxed_local))]
// TODO [todr] a lot of warnings to be fixed
#![cfg_attr(feature="dev", allow(assign_op_pattern))]
@@ -98,8 +100,12 @@ extern crate ethcore_ipc_nano as nanoipc;
extern crate ethcore_devtools as devtools;
extern crate rand;
extern crate bit_set;
extern crate lru_cache;
extern crate bloomfilter;
extern crate byteorder;
#[cfg(feature = "jit" )] extern crate evmjit;
#[cfg(feature = "jit" )]
extern crate evmjit;
pub mod account_provider;
pub mod engines;
@@ -128,6 +134,7 @@ mod basic_types;
mod env_info;
mod pod_account;
mod state;
mod state_db;
mod account;
mod account_db;
mod builtin;

View File

@@ -0,0 +1,104 @@
// 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/>.
//! Bloom upgrade
use client::{DB_COL_EXTRA, DB_COL_HEADERS, DB_NO_OF_COLUMNS, DB_COL_STATE, DB_COL_ACCOUNT_BLOOM};
use state_db::{ACCOUNT_BLOOM_SPACE, DEFAULT_ACCOUNT_PRESET, StateDB, ACCOUNT_BLOOM_HASHCOUNT_KEY};
use util::trie::TrieDB;
use views::HeaderView;
use bloomfilter::Bloom;
use util::migration::Error;
use util::journaldb;
use util::{H256, FixedHash, BytesConvertable};
use util::{Database, DatabaseConfig, DBTransaction, CompactionProfile};
use std::path::Path;
fn check_bloom_exists(db: &Database) -> bool {
let hash_count_entry = db.get(DB_COL_ACCOUNT_BLOOM, ACCOUNT_BLOOM_HASHCOUNT_KEY)
.expect("Low-level database error");
hash_count_entry.is_some()
}
/// Account bloom upgrade routine. If bloom already present, does nothing.
/// If database empty (no best block), does nothing.
/// Can be called on upgraded database with no issues (will do nothing).
pub fn upgrade_account_bloom(db_path: &Path) -> Result<(), Error> {
let path = try!(db_path.to_str().ok_or(Error::MigrationImpossible));
trace!(target: "migration", "Account bloom upgrade at {:?}", db_path);
let source = try!(Database::open(&DatabaseConfig {
max_open_files: 64,
cache_size: None,
compaction: CompactionProfile::default(),
columns: DB_NO_OF_COLUMNS,
wal: true,
}, path));
let best_block_hash = match try!(source.get(DB_COL_EXTRA, b"best")) {
// no migration needed
None => {
trace!(target: "migration", "No best block hash, skipping");
return Ok(());
},
Some(hash) => hash,
};
let best_block_header = match try!(source.get(DB_COL_HEADERS, &best_block_hash)) {
// no best block, nothing to do
None => {
trace!(target: "migration", "No best block header, skipping");
return Ok(())
},
Some(x) => x,
};
let state_root = HeaderView::new(&best_block_header).state_root();
if check_bloom_exists(&source) {
// bloom already exists, nothing to do
trace!(target: "migration", "Bloom already present, skipping");
return Ok(())
}
println!("Adding accounts bloom (one-time upgrade)");
let db = ::std::sync::Arc::new(source);
let bloom_journal = {
let mut bloom = Bloom::new(ACCOUNT_BLOOM_SPACE, DEFAULT_ACCOUNT_PRESET);
// no difference what algorithm is passed, since there will be no writes
let state_db = journaldb::new(
db.clone(),
journaldb::Algorithm::OverlayRecent,
DB_COL_STATE);
let account_trie = try!(TrieDB::new(state_db.as_hashdb(), &state_root).map_err(|e| Error::Custom(format!("Cannot open trie: {:?}", e))));
for (ref account_key, _) in account_trie.iter() {
let account_key_hash = H256::from_slice(&account_key);
bloom.set(account_key_hash.as_slice());
}
bloom.drain_journal()
};
trace!(target: "migration", "Generated {} bloom updates", bloom_journal.entries.len());
let batch = DBTransaction::new(&db);
try!(StateDB::commit_bloom(&batch, bloom_journal).map_err(|_| Error::Custom("Failed to commit bloom".to_owned())));
try!(db.write(batch));
trace!(target: "migration", "Finished bloom update");
Ok(())
}

View File

@@ -23,3 +23,9 @@ pub mod extras;
mod v9;
pub use self::v9::ToV9;
pub use self::v9::Extract;
mod account_bloom;
pub use self::account_bloom::upgrade_account_bloom;
mod v10;
pub use self::v10::ToV10;

View File

@@ -0,0 +1,35 @@
// 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/>.
//! This migration compresses the state db.
use util::migration::SimpleMigration;
/// Compressing migration.
#[derive(Default)]
pub struct ToV10;
impl SimpleMigration for ToV10 {
fn version(&self) -> u32 {
10
}
fn columns(&self) -> Option<u32> { Some(6) }
fn simple_migrate(&mut self, key: Vec<u8>, value: Vec<u8>) -> Option<(Vec<u8>, Vec<u8>)> {
Some((key, value))
}
}

View File

@@ -21,15 +21,17 @@ use util::*;
use util::using_queue::{UsingQueue, GetAction};
use account_provider::AccountProvider;
use views::{BlockView, HeaderView};
use state::State;
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::SignedTransaction;
use receipt::Receipt;
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;
@@ -46,6 +48,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 {
@@ -63,12 +76,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 {
@@ -79,11 +96,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,
}
}
}
@@ -168,12 +187,11 @@ pub struct Miner {
// NOTE [ToDr] When locking always lock in this order!
transaction_queue: Arc<Mutex<TransactionQueue>>,
sealing_work: Mutex<SealingWork>,
next_allowed_reseal: Mutex<Instant>,
sealing_block_last_request: Mutex<u64>,
// for sealing...
options: MinerOptions,
next_allowed_reseal: Mutex<Instant>,
sealing_block_last_request: Mutex<u64>,
gas_range_target: RwLock<(U256, U256)>,
author: RwLock<Address>,
extra_data: RwLock<Bytes>,
@@ -188,7 +206,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 +224,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 +267,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 +278,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();
@@ -286,13 +312,20 @@ impl Miner {
};
let mut invalid_transactions = HashSet::new();
let mut transactions_to_penalize = HashSet::new();
let block_number = open_block.block().fields().header.number();
// TODO: push new uncles, too.
for tx in transactions {
let hash = tx.hash();
match open_block.push_transaction(tx, None) {
Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, .. })) => {
debug!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?}", hash);
Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, gas })) => {
debug!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?} (limit: {:?}, used: {:?}, gas: {:?})", hash, gas_limit, gas_used, gas);
// Penalize transaction if it's above current gas limit
if gas > gas_limit {
transactions_to_penalize.insert(hash);
}
// Exit early if gas left is smaller then min_tx_gas
let min_tx_gas: U256 = 21000.into(); // TODO: figure this out properly.
if gas_limit - gas_used < min_tx_gas {
@@ -301,8 +334,8 @@ impl Miner {
},
// Invalid nonce error can happen only if previous transaction is skipped because of gas limit.
// If there is errornous state of transaction queue it will be fixed when next block is imported.
Err(Error::Execution(ExecutionError::InvalidNonce { .. })) => {
debug!(target: "miner", "Skipping adding transaction to block because of invalid nonce: {:?}", hash);
Err(Error::Execution(ExecutionError::InvalidNonce { expected, got })) => {
debug!(target: "miner", "Skipping adding transaction to block because of invalid nonce: {:?} (expected: {:?}, got: {:?})", hash, expected, got);
},
// already have transaction - ignore
Err(Error::Transaction(TransactionError::AlreadyImported)) => {},
@@ -328,6 +361,9 @@ impl Miner {
for hash in invalid_transactions.into_iter() {
queue.remove_invalid(&hash, &fetch_account);
}
for hash in transactions_to_penalize {
queue.penalize(&hash);
}
}
if !block.transactions().is_empty() {
@@ -385,6 +421,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
@@ -434,6 +474,21 @@ impl Miner {
/// 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;
@@ -489,7 +544,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));
@@ -506,29 +561,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.code(address), |b| b.block().fields().state.code(address))
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) {
@@ -673,50 +734,103 @@ 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_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_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())
.position(|t| t == *hash)
.map(|index| {
let prev_gas = if index == 0 { Default::default() } else { pending.receipts()[index - 1].gas_used };
let ref tx = txs[index];
let ref receipt = pending.receipts()[index];
RichReceipt {
transaction_hash: hash.clone(),
transaction_index: index,
cumulative_gas_used: receipt.gas_used,
gas_used: receipt.gas_used - prev_gas,
contract_address: match tx.action {
Action::Call(_) => None,
Action::Create => Some(contract_address(&tx.sender().unwrap(), &tx.nonce)),
},
logs: receipt.logs.clone(),
}
})
}
)
}
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());
@@ -724,9 +838,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> {
@@ -736,11 +849,11 @@ impl MinerService for Miner {
fn update_sealing(&self, chain: &MiningBlockChainClient) {
trace!(target: "miner", "update_sealing");
let requires_reseal = {
let has_local_transactions = self.transaction_queue.lock().has_local_pending_transactions();
let mut sealing_work = self.sealing_work.lock();
if sealing_work.enabled {
trace!(target: "miner", "update_sealing: sealing enabled");
let current_no = chain.chain_info().best_block_number;
let has_local_transactions = self.transaction_queue.lock().has_local_pending_transactions();
let last_request = *self.sealing_block_last_request.lock();
let should_disable_sealing = !self.forced_sealing()
&& !has_local_transactions
@@ -840,7 +953,7 @@ impl MinerService for Miner {
out_of_chain.for_each(|txs| {
let mut transaction_queue = self.transaction_queue.lock();
let _ = self.add_transactions_to_queue(
chain, txs, TransactionOrigin::External, &mut transaction_queue
chain, txs, TransactionOrigin::RetractedBlock, &mut transaction_queue
);
});
}
@@ -879,7 +992,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};
@@ -930,6 +1043,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,
@@ -954,22 +1069,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
@@ -984,18 +1127,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,7 +56,8 @@ use std::collections::BTreeMap;
use util::{H256, U256, Address, Bytes};
use client::{MiningBlockChainClient, Executed, CallAnalytics};
use block::ClosedBlock;
use receipt::Receipt;
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,16 +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, best_block: BlockNumber, hash: &H256) -> Option<RichReceipt>;
/// Returns highest transaction nonce for given address.
fn last_nonce(&self, address: &Address) -> Option<U256>;

File diff suppressed because it is too large Load Diff

View File

@@ -47,7 +47,7 @@ impl PodAccount {
PodAccount {
balance: *acc.balance(),
nonce: *acc.nonce(),
storage: acc.storage_overlay().iter().fold(BTreeMap::new(), |mut m, (k, &(_, ref v))| {m.insert(k.clone(), v.clone()); m}),
storage: acc.storage_changes().iter().fold(BTreeMap::new(), |mut m, (k, v)| {m.insert(k.clone(), v.clone()); m}),
code: acc.code().map(|x| x.to_vec()),
}
}

View File

@@ -143,7 +143,7 @@ impl Account {
#[cfg(test)]
mod tests {
use account_db::{AccountDB, AccountDBMut};
use tests::helpers::get_temp_journal_db;
use tests::helpers::get_temp_state_db;
use snapshot::tests::helpers::fill_storage;
use util::{SHA3_NULL_RLP, SHA3_EMPTY};
@@ -154,8 +154,7 @@ mod tests {
#[test]
fn encoding_basic() {
let mut db = get_temp_journal_db();
let mut db = &mut **db;
let mut db = get_temp_state_db();
let addr = Address::random();
let account = Account {
@@ -175,8 +174,7 @@ mod tests {
#[test]
fn encoding_storage() {
let mut db = get_temp_journal_db();
let mut db = &mut **db;
let mut db = get_temp_state_db();
let addr = Address::random();
let account = {
@@ -198,4 +196,4 @@ mod tests {
let fat_rlp = UntrustedRlp::new(&fat_rlp);
assert_eq!(Account::from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp).unwrap(), account);
}
}
}

View File

@@ -18,6 +18,8 @@
use std::fmt;
use ids::BlockID;
use util::H256;
use util::trie::TrieError;
use util::rlp::DecoderError;
@@ -26,9 +28,13 @@ use util::rlp::DecoderError;
#[derive(Debug)]
pub enum Error {
/// Invalid starting block for snapshot.
InvalidStartingBlock(H256),
InvalidStartingBlock(BlockID),
/// Block not found.
BlockNotFound(H256),
/// Incomplete chain.
IncompleteChain,
/// Old starting block in a pruned database.
OldBlockPrunedDB,
/// Trie error.
Trie(TrieError),
/// Decoder error.
@@ -40,8 +46,11 @@ pub enum Error {
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::InvalidStartingBlock(ref hash) => write!(f, "Invalid starting block hash: {}", hash),
Error::InvalidStartingBlock(ref id) => write!(f, "Invalid starting block: {:?}", id),
Error::BlockNotFound(ref hash) => write!(f, "Block not found in chain: {}", hash),
Error::IncompleteChain => write!(f, "Cannot create snapshot due to incomplete chain."),
Error::OldBlockPrunedDB => write!(f, "Attempted to create a snapshot at an old block while using \
a pruned database. Please re-run with the --pruning archive flag."),
Error::Io(ref err) => err.fmt(f),
Error::Decoder(ref err) => err.fmt(f),
Error::Trie(ref err) => err.fmt(f),
@@ -55,9 +64,9 @@ impl From<::std::io::Error> for Error {
}
}
impl From<Box<TrieError>> for Error {
fn from(err: Box<TrieError>) -> Self {
Error::Trie(*err)
impl From<TrieError> for Error {
fn from(err: TrieError) -> Self {
Error::Trie(err)
}
}
@@ -65,4 +74,10 @@ impl From<DecoderError> for Error {
fn from(err: DecoderError) -> Self {
Error::Decoder(err)
}
}
}
impl<E> From<Box<E>> for Error where Error: From<E> {
fn from(err: Box<E>) -> Self {
Error::from(*err)
}
}

View File

@@ -18,13 +18,16 @@
use std::collections::VecDeque;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use account_db::{AccountDB, AccountDBMut};
use blockchain::{BlockChain, BlockProvider};
use engines::Engine;
use ids::BlockID;
use views::BlockView;
use super::state_db::StateDB;
use util::{Bytes, Hashable, HashDB, snappy, TrieDB, TrieDBMut, TrieMut};
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};
@@ -36,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};
@@ -58,9 +63,39 @@ const PREFERRED_CHUNK_SIZE: usize = 4 * 1024 * 1024;
// How many blocks to include in a snapshot, starting from the head of the chain.
const SNAPSHOT_BLOCKS: u64 = 30000;
/// A progress indicator for snapshots.
#[derive(Debug, Default)]
pub struct Progress {
accounts: AtomicUsize,
blocks: AtomicUsize,
size: AtomicUsize, // Todo [rob] use Atomicu64 when it stabilizes.
done: AtomicBool,
}
impl Progress {
/// Get the number of accounts snapshotted thus far.
pub fn accounts(&self) -> usize { self.accounts.load(Ordering::Relaxed) }
/// Get the number of blocks snapshotted thus far.
pub fn blocks(&self) -> usize { self.blocks.load(Ordering::Relaxed) }
/// Get the written size of the snapshot in bytes.
pub fn size(&self) -> usize { self.size.load(Ordering::Relaxed) }
/// Whether the snapshot is complete.
pub fn done(&self) -> bool { self.done.load(Ordering::SeqCst) }
}
/// Take a snapshot using the given blockchain, starting block hash, and database, writing into the given writer.
pub fn take_snapshot<W: SnapshotWriter + Send>(chain: &BlockChain, start_block_hash: H256, state_db: &HashDB, writer: W) -> Result<(), Error> {
let start_header = try!(chain.block_header(&start_block_hash).ok_or(Error::InvalidStartingBlock(start_block_hash)));
pub fn take_snapshot<W: SnapshotWriter + Send>(
chain: &BlockChain,
block_at: H256,
state_db: &HashDB,
writer: W,
p: &Progress
) -> Result<(), Error> {
let start_header = try!(chain.block_header(&block_at)
.ok_or(Error::InvalidStartingBlock(BlockID::Hash(block_at))));
let state_root = start_header.state_root();
let number = start_header.number();
@@ -68,8 +103,8 @@ pub fn take_snapshot<W: SnapshotWriter + Send>(chain: &BlockChain, start_block_h
let writer = Mutex::new(writer);
let (state_hashes, block_hashes) = try!(scope(|scope| {
let block_guard = scope.spawn(|| chunk_blocks(chain, (number, start_block_hash), &writer));
let state_res = chunk_state(state_db, state_root, &writer);
let block_guard = scope.spawn(|| chunk_blocks(chain, (number, block_at), &writer, p));
let state_res = chunk_state(state_db, state_root, &writer, p);
state_res.and_then(|state_hashes| {
block_guard.join().map(|block_hashes| (state_hashes, block_hashes))
@@ -83,11 +118,13 @@ pub fn take_snapshot<W: SnapshotWriter + Send>(chain: &BlockChain, start_block_h
block_hashes: block_hashes,
state_root: *state_root,
block_number: number,
block_hash: start_block_hash,
block_hash: block_at,
};
try!(writer.into_inner().finish(manifest_data));
p.done.store(true, Ordering::SeqCst);
Ok(())
}
@@ -100,6 +137,7 @@ struct BlockChunker<'a> {
hashes: Vec<H256>,
snappy_buffer: Vec<u8>,
writer: &'a Mutex<SnapshotWriter + 'a>,
progress: &'a Progress,
}
impl<'a> BlockChunker<'a> {
@@ -162,7 +200,8 @@ impl<'a> BlockChunker<'a> {
let parent_total_difficulty = parent_details.total_difficulty;
let mut rlp_stream = RlpStream::new_list(3 + self.rlps.len());
let num_entries = self.rlps.len();
let mut rlp_stream = RlpStream::new_list(3 + num_entries);
rlp_stream.append(&parent_number).append(&parent_hash).append(&parent_total_difficulty);
for pair in self.rlps.drain(..) {
@@ -178,6 +217,9 @@ impl<'a> BlockChunker<'a> {
try!(self.writer.lock().write_block_chunk(hash, compressed));
trace!(target: "snapshot", "wrote block chunk. hash: {}, size: {}, uncompressed size: {}", hash.hex(), size, raw_data.len());
self.progress.size.fetch_add(size, Ordering::SeqCst);
self.progress.blocks.fetch_add(num_entries, Ordering::SeqCst);
self.hashes.push(hash);
Ok(())
}
@@ -189,7 +231,7 @@ impl<'a> BlockChunker<'a> {
/// The path parameter is the directory to store the block chunks in.
/// This function assumes the directory exists already.
/// Returns a list of chunk hashes, with the first having the blocks furthest from the genesis.
pub fn chunk_blocks<'a>(chain: &'a BlockChain, start_block_info: (u64, H256), writer: &Mutex<SnapshotWriter + 'a>) -> Result<Vec<H256>, Error> {
pub fn chunk_blocks<'a>(chain: &'a BlockChain, start_block_info: (u64, H256), writer: &Mutex<SnapshotWriter + 'a>, progress: &'a Progress) -> Result<Vec<H256>, Error> {
let (start_number, start_hash) = start_block_info;
let first_hash = if start_number < SNAPSHOT_BLOCKS {
@@ -197,8 +239,7 @@ pub fn chunk_blocks<'a>(chain: &'a BlockChain, start_block_info: (u64, H256), wr
chain.genesis_hash()
} else {
let first_num = start_number - SNAPSHOT_BLOCKS;
chain.block_hash(first_num)
.expect("number before best block number; whole chain is stored; qed")
try!(chain.block_hash(first_num).ok_or(Error::IncompleteChain))
};
let mut chunker = BlockChunker {
@@ -208,6 +249,7 @@ pub fn chunk_blocks<'a>(chain: &'a BlockChain, start_block_info: (u64, H256), wr
hashes: Vec::new(),
snappy_buffer: vec![0; snappy::max_compressed_len(PREFERRED_CHUNK_SIZE)],
writer: writer,
progress: progress,
};
try!(chunker.chunk_all(first_hash));
@@ -222,6 +264,7 @@ struct StateChunker<'a> {
cur_size: usize,
snappy_buffer: Vec<u8>,
writer: &'a Mutex<SnapshotWriter + 'a>,
progress: &'a Progress,
}
impl<'a> StateChunker<'a> {
@@ -249,7 +292,8 @@ impl<'a> StateChunker<'a> {
// Write out the buffer to disk, pushing the created chunk's hash to
// the list.
fn write_chunk(&mut self) -> Result<(), Error> {
let mut stream = RlpStream::new_list(self.rlps.len());
let num_entries = self.rlps.len();
let mut stream = RlpStream::new_list(num_entries);
for rlp in self.rlps.drain(..) {
stream.append_raw(&rlp, 1);
}
@@ -263,6 +307,9 @@ impl<'a> StateChunker<'a> {
try!(self.writer.lock().write_state_chunk(hash, compressed));
trace!(target: "snapshot", "wrote state chunk. size: {}, uncompressed size: {}", compressed_size, raw_data.len());
self.progress.accounts.fetch_add(num_entries, Ordering::SeqCst);
self.progress.size.fetch_add(compressed_size, Ordering::SeqCst);
self.hashes.push(hash);
self.cur_size = 0;
@@ -275,7 +322,7 @@ impl<'a> StateChunker<'a> {
///
/// Returns a list of hashes of chunks created, or any error it may
/// have encountered.
pub fn chunk_state<'a>(db: &HashDB, root: &H256, writer: &Mutex<SnapshotWriter + 'a>) -> Result<Vec<H256>, Error> {
pub fn chunk_state<'a>(db: &HashDB, root: &H256, writer: &Mutex<SnapshotWriter + 'a>, progress: &'a Progress) -> Result<Vec<H256>, Error> {
let account_trie = try!(TrieDB::new(db, &root));
let mut chunker = StateChunker {
@@ -284,10 +331,9 @@ pub fn chunk_state<'a>(db: &HashDB, root: &H256, writer: &Mutex<SnapshotWriter +
cur_size: 0,
snappy_buffer: vec![0; snappy::max_compressed_len(PREFERRED_CHUNK_SIZE)],
writer: writer,
progress: progress,
};
trace!(target: "snapshot", "beginning state chunking");
// account_key here is the address' hash.
for (account_key, account_data) in account_trie.iter() {
let account = Account::from_thin_rlp(account_data);
@@ -373,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();
@@ -383,6 +430,7 @@ impl StateRebuilder {
let chunk_size = account_fat_rlps.len() / ::num_cpus::get() + 1;
// build account tries in parallel.
// Todo [rob] keep a thread pool around so we don't do this per-chunk.
try!(scope(|scope| {
let mut handles = Vec::new();
for (account_chunk, out_pairs_chunk) in account_fat_rlps.chunks(chunk_size).zip(pairs.chunks_mut(chunk_size)) {
@@ -409,7 +457,7 @@ impl StateRebuilder {
Ok::<_, ::error::Error>(())
}));
let mut bloom = StateDB::load_bloom(&backing);
// batch trie writes
{
let mut account_trie = if self.state_root != SHA3_NULL_RLP {
@@ -419,11 +467,16 @@ impl StateRebuilder {
};
for (hash, thin_rlp) in pairs {
if &thin_rlp[..] != &empty_rlp[..] {
bloom.set(hash.as_slice());
}
try!(account_trie.insert(&hash, &thin_rlp));
}
}
let bloom_journal = bloom.drain_journal();
let batch = backing.transaction();
try!(StateDB::commit_bloom(&batch, bloom_journal));
try!(self.db.inject(&batch));
try!(backing.write(batch).map_err(::util::UtilError::SimpleString));
trace!(target: "snapshot", "current state root: {:?}", self.state_root);
@@ -456,12 +509,12 @@ fn rebuild_account_trie(db: &mut HashDB, account_chunk: &[&[u8]], out_chunk: &mu
Ok(())
}
/// Proportion of blocks which we will verify PoW for.
/// Proportion of blocks which we will verify `PoW` for.
const POW_VERIFY_RATE: f32 = 0.02;
/// Rebuilds the blockchain from chunks.
///
/// Does basic verification for all blocks, but PoW verification for some.
/// Does basic verification for all blocks, but `PoW` verification for some.
/// Blocks must be fed in-order.
///
/// The first block in every chunk is disconnected from the last block in the

View File

@@ -101,7 +101,7 @@ impl Restoration {
fn new(manifest: &ManifestData, pruning: Algorithm, path: &Path, gb: &[u8]) -> Result<Self, Error> {
let cfg = DatabaseConfig::with_columns(::client::DB_NO_OF_COLUMNS);
let raw_db = Arc::new(try!(Database::open(&cfg, &*path.to_string_lossy())
.map_err(|s| UtilError::SimpleString(s))));
.map_err(UtilError::SimpleString)));
let chain = BlockChain::new(Default::default(), gb, raw_db.clone());
let blocks = try!(BlockRebuilder::new(chain, manifest.block_number));
@@ -207,23 +207,17 @@ impl Service {
};
// create the snapshot dir if it doesn't exist.
match fs::create_dir_all(service.snapshot_dir()) {
Err(e) => {
if e.kind() != ErrorKind::AlreadyExists {
return Err(e.into())
}
if let Err(e) = fs::create_dir_all(service.snapshot_dir()) {
if e.kind() != ErrorKind::AlreadyExists {
return Err(e.into())
}
_ => {}
}
// delete the temporary restoration dir if it does exist.
match fs::remove_dir_all(service.restoration_dir()) {
Err(e) => {
if e.kind() != ErrorKind::NotFound {
return Err(e.into())
}
if let Err(e) = fs::remove_dir_all(service.restoration_dir()) {
if e.kind() != ErrorKind::NotFound {
return Err(e.into())
}
_ => {}
}
Ok(service)
@@ -434,4 +428,4 @@ impl SnapshotService for Service {
self.io_channel.send(ClientIoMessage::FeedBlockChunk(hash, chunk))
.expect("snapshot service and io service are kept alive by client service; qed");
}
}
}

View File

@@ -20,7 +20,7 @@ use devtools::RandomTempPath;
use blockchain::generator::{ChainGenerator, ChainIterator, BlockFinalizer};
use blockchain::BlockChain;
use snapshot::{chunk_blocks, BlockRebuilder};
use snapshot::{chunk_blocks, BlockRebuilder, Progress};
use snapshot::io::{PackedReader, PackedWriter, SnapshotReader, SnapshotWriter};
use util::{Mutex, snappy};
@@ -55,7 +55,7 @@ fn chunk_and_restore(amount: u64) {
// snapshot it.
let writer = Mutex::new(PackedWriter::new(&snapshot_path).unwrap());
let block_hashes = chunk_blocks(&bc, (amount, best_hash), &writer).unwrap();
let block_hashes = chunk_blocks(&bc, (amount, best_hash), &writer, &Progress::default()).unwrap();
writer.into_inner().finish(::snapshot::ManifestData {
state_hashes: Vec::new(),
block_hashes: block_hashes,
@@ -88,4 +88,4 @@ fn chunk_and_restore(amount: u64) {
fn chunk_and_restore_500() { chunk_and_restore(500) }
#[test]
fn chunk_and_restore_40k() { chunk_and_restore(40000) }
fn chunk_and_restore_40k() { chunk_and_restore(40000) }

View File

@@ -116,7 +116,7 @@ pub fn fill_storage(mut db: AccountDBMut, root: &mut H256, seed: &mut H256) {
pub fn compare_dbs(one: &HashDB, two: &HashDB) {
let keys = one.keys();
for (key, _) in keys {
for key in keys.keys() {
assert_eq!(one.get(&key).unwrap(), two.get(&key).unwrap());
}
}
}

View File

@@ -16,7 +16,7 @@
//! State snapshotting tests.
use snapshot::{chunk_state, StateRebuilder};
use snapshot::{chunk_state, Progress, StateRebuilder};
use snapshot::io::{PackedReader, PackedWriter, SnapshotReader, SnapshotWriter};
use super::helpers::{compare_dbs, StateProducer};
@@ -48,7 +48,7 @@ fn snap_and_restore() {
let state_root = producer.state_root();
let writer = Mutex::new(PackedWriter::new(&snap_file).unwrap());
let state_hashes = chunk_state(&old_db, &state_root, &writer).unwrap();
let state_hashes = chunk_state(&old_db, &state_root, &writer, &Progress::default()).unwrap();
writer.into_inner().finish(::snapshot::ManifestData {
state_hashes: state_hashes,
@@ -79,4 +79,4 @@ fn snap_and_restore() {
let new_db = journaldb::new(db, Algorithm::Archive, ::client::DB_COL_STATE);
compare_dbs(&old_db, new_db.as_hashdb());
}
}

View File

@@ -20,6 +20,7 @@ use common::*;
use engines::{Engine, NullEngine, InstantSeal, BasicAuthority};
use pod_state::*;
use account_db::*;
use state_db::StateDB;
use super::genesis::Genesis;
use super::seal::Generic as GenericSeal;
use ethereum;
@@ -36,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.
@@ -49,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 },
}
@@ -154,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 }
@@ -229,19 +233,20 @@ impl Spec {
}
/// Ensure that the given state DB has the trie nodes in for the genesis state.
pub fn ensure_db_good(&self, db: &mut HashDB) -> Result<bool, Box<TrieError>> {
if !db.contains(&self.state_root()) {
pub fn ensure_db_good(&self, db: &mut StateDB) -> Result<bool, Box<TrieError>> {
if !db.as_hashdb().contains(&self.state_root()) {
let mut root = H256::new();
{
let mut t = SecTrieDBMut::new(db, &mut root);
let mut t = SecTrieDBMut::new(db.as_hashdb_mut(), &mut root);
for (address, account) in self.genesis_state.get().iter() {
try!(t.insert(address.as_slice(), &account.rlp()));
}
}
for (address, account) in self.genesis_state.get().iter() {
account.insert_additional(&mut AccountDBMut::new(db, address));
db.note_non_null_account(address);
account.insert_additional(&mut AccountDBMut::new(db.as_hashdb_mut(), address));
}
assert!(db.contains(&self.state_root()));
assert!(db.as_hashdb().contains(&self.state_root()));
Ok(true)
} else { Ok(false) }
}

File diff suppressed because it is too large Load Diff

474
ethcore/src/state_db.rs Normal file
View File

@@ -0,0 +1,474 @@
// 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 std::collections::{VecDeque, HashSet};
use lru_cache::LruCache;
use util::journaldb::JournalDB;
use util::hash::{H256};
use util::hashdb::HashDB;
use account::Account;
use header::BlockNumber;
use util::{Arc, Address, Database, DBTransaction, UtilError, Mutex, Hashable, BytesConvertable};
use bloomfilter::{Bloom, BloomJournal};
use client::DB_COL_ACCOUNT_BLOOM;
use byteorder::{LittleEndian, ByteOrder};
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.
/// Manages shared global state cache.
/// A clone of `StateDB` may be created as canonical or not.
/// For canonical clones cache changes are accumulated and applied
/// 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>>,
/// 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;
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");
if hash_count_entry.is_none() {
return Bloom::new(ACCOUNT_BLOOM_SPACE, DEFAULT_ACCOUNT_PRESET);
}
let hash_count_bytes = hash_count_entry.unwrap();
assert_eq!(hash_count_bytes.len(), 1);
let hash_count = hash_count_bytes[0];
let mut bloom_parts = vec![0u64; ACCOUNT_BLOOM_SPACE / 8];
let mut key = [0u8; 8];
for i in 0..ACCOUNT_BLOOM_SPACE / 8 {
LittleEndian::write_u64(&mut key, i as u64);
bloom_parts[i] = db.get(DB_COL_ACCOUNT_BLOOM, &key).expect("low-level database error")
.and_then(|val| Some(LittleEndian::read_u64(&val[..])))
.unwrap_or(0u64);
}
let bloom = Bloom::from_parts(&bloom_parts, hash_count as u32);
trace!(target: "account_bloom", "Bloom is {:?} full, hash functions count = {:?}", bloom.how_full(), hash_count);
bloom
}
/// Create a new instance wrapping `JournalDB`
pub fn new(db: Box<JournalDB>) -> StateDB {
let bloom = Self::load_bloom(db.backing());
StateDB {
db: db,
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_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_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());
}
pub fn commit_bloom(batch: &DBTransaction, journal: BloomJournal) -> Result<(), UtilError> {
assert!(journal.hash_functions <= 255);
try!(batch.put(DB_COL_ACCOUNT_BLOOM, ACCOUNT_BLOOM_HASHCOUNT_KEY, &vec![journal.hash_functions as u8]));
let mut key = [0u8; 8];
let mut val = [0u8; 8];
for (bloom_part_index, bloom_part_value) in journal.entries {
LittleEndian::write_u64(&mut key, bloom_part_index as u64);
LittleEndian::write_u64(&mut val, bloom_part_value);
try!(batch.put(DB_COL_ACCOUNT_BLOOM, &key, &val));
}
Ok(())
}
/// Commit all recent insert operations and canonical historical commits' removals from the
/// old era to the backing database, reverting any non-canonical historical commit's inserts.
pub fn commit(&mut self, batch: &DBTransaction, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result<u32, UtilError> {
{
let mut bloom_lock = self.account_bloom.lock();
try!(Self::commit_bloom(batch, bloom_lock.drain_journal()));
}
let records = try!(self.db.commit(batch, now, id, end));
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()
}
/// Returns an interface to mutable HashDB.
pub fn as_hashdb_mut(&mut self) -> &mut HashDB {
self.db.as_hashdb_mut()
}
/// Clone the database.
pub fn boxed_clone(&self) -> StateDB {
StateDB {
db: self.db.boxed_clone(),
account_cache: self.account_cache.clone(),
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, parent: &H256) -> StateDB {
StateDB {
db: self.db.boxed_clone(),
account_cache: self.account_cache.clone(),
cache_buffer: Vec::new(),
account_bloom: self.account_bloom.clone(),
parent_hash: Some(parent.clone()),
commit_hash: None,
commit_number: None,
}
}
/// Check if pruning is enabled on the database.
pub fn is_pruned(&self) -> bool {
self.db.is_pruned()
}
/// Heap size used.
pub fn mem_used(&self) -> usize {
self.db.mem_used() //TODO: + self.account_cache.lock().heap_size_of_children()
}
/// Returns underlying `JournalDB`.
pub fn journal_db(&self) -> &JournalDB {
&*self.db
}
/// Returns underlying `JournalDB`.
pub fn journal_db_mut(&mut self) -> &mut JournalDB {
&mut *self.db
}
/// 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 cache is disabled or if the account is not cached.
pub fn get_cached_account(&self, addr: &Address) -> Option<Option<Account>> {
let mut cache = self.account_cache.lock();
if !Self::is_allowed(addr, &self.parent_hash, &cache.modifications) {
return None;
}
cache.accounts.get_mut(&addr).map(|a| a.as_ref().map(|a| a.clone_basic()))
}
/// Get value from a cached account.
/// 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 {
let mut cache = self.account_cache.lock();
if !Self::is_allowed(a, &self.parent_hash, &cache.modifications) {
return None;
}
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,11 +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() {
@@ -31,6 +34,14 @@ fn imports_from_empty() {
client.flush_queue();
}
#[test]
fn should_return_registrar() {
let dir = RandomTempPath::new();
let spec = ethereum::new_morden();
let client = Client::new(ClientConfig::default(), &spec, dir.as_path(), Arc::new(Miner::with_spec(&spec)), IoChannel::disconnected()).unwrap();
assert_eq!(client.additional_params().get("registrar"), Some(&"8e4e9b13d4b45cb0befc93c3061b1408f67316b2".to_owned()));
}
#[test]
fn returns_state_root_basic() {
let client_result = generate_dummy_client(6);
@@ -142,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);
@@ -158,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

@@ -18,6 +18,7 @@ use io::*;
use client::{self, BlockChainClient, Client, ClientConfig};
use common::*;
use spec::*;
use state_db::StateDB;
use block::{OpenBlock, Drain};
use blockchain::{BlockChain, Config as BlockChainConfig};
use state::*;
@@ -31,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,
}
}
}
@@ -134,11 +137,11 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
let test_spec = get_test_spec();
let client = Client::new(ClientConfig::default(), &test_spec, dir.as_path(), Arc::new(Miner::with_spec(&test_spec)), IoChannel::disconnected()).unwrap();
let test_engine = &test_spec.engine;
let test_engine = &*test_spec.engine;
let mut db_result = get_temp_journal_db();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
test_spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
test_spec.ensure_db_good(&mut db).unwrap();
let vm_factory = Default::default();
let genesis_header = test_spec.genesis_header();
@@ -155,7 +158,7 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
// forge block.
let mut b = OpenBlock::new(
test_engine.deref(),
test_engine,
&vm_factory,
Default::default(),
false,
@@ -179,11 +182,11 @@ 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;
}
let b = b.close_and_lock().seal(test_engine.deref(), vec![]).unwrap();
let b = b.close_and_lock().seal(test_engine, vec![]).unwrap();
if let Err(e) = client.import_block(b.rlp_bytes()) {
panic!("error importing block which is valid by definition: {:?}", e);
@@ -303,9 +306,9 @@ pub fn generate_dummy_empty_blockchain() -> GuardedTempResult<BlockChain> {
}
}
pub fn get_temp_journal_db() -> GuardedTempResult<Box<JournalDB>> {
pub fn get_temp_state_db() -> GuardedTempResult<StateDB> {
let temp = RandomTempPath::new();
let journal_db = get_temp_journal_db_in(temp.as_path());
let journal_db = get_temp_state_db_in(temp.as_path());
GuardedTempResult {
_temp: temp,
@@ -315,7 +318,7 @@ pub fn get_temp_journal_db() -> GuardedTempResult<Box<JournalDB>> {
pub fn get_temp_state() -> GuardedTempResult<State> {
let temp = RandomTempPath::new();
let journal_db = get_temp_journal_db_in(temp.as_path());
let journal_db = get_temp_state_db_in(temp.as_path());
GuardedTempResult {
_temp: temp,
@@ -323,13 +326,14 @@ pub fn get_temp_state() -> GuardedTempResult<State> {
}
}
pub fn get_temp_journal_db_in(path: &Path) -> Box<JournalDB> {
pub fn get_temp_state_db_in(path: &Path) -> StateDB {
let db = new_db(path.to_str().expect("Only valid utf8 paths for tests."));
journaldb::new(db.clone(), journaldb::Algorithm::EarlyMerge, None)
let journal_db = journaldb::new(db.clone(), journaldb::Algorithm::EarlyMerge, client::DB_COL_STATE);
StateDB::new(journal_db)
}
pub fn get_temp_state_in(path: &Path) -> State {
let journal_db = get_temp_journal_db_in(path);
let journal_db = get_temp_state_db_in(path);
State::new(journal_db, U256::from(0), Default::default())
}

View File

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

View File

@@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Trace database.
use std::ops::{Deref, DerefMut};
use std::ops::Deref;
use std::collections::HashMap;
use std::sync::Arc;
use bloomchain::{Number, Config as BloomConfig};
@@ -119,8 +119,9 @@ pub struct TraceDB<T> where T: DatabaseExtras {
impl<T> BloomGroupDatabase for TraceDB<T> where T: DatabaseExtras {
fn blooms_at(&self, position: &GroupPosition) -> Option<BloomGroup> {
let position = TraceGroupPosition::from(position.clone());
self.note_used(CacheID::Bloom(position.clone()));
self.tracesdb.read_with_cache(DB_COL_TRACE, &self.blooms, &position).map(Into::into)
let result = self.tracesdb.read_with_cache(DB_COL_TRACE, &self.blooms, &position).map(Into::into);
self.note_used(CacheID::Bloom(position));
result
}
}
@@ -174,11 +175,13 @@ impl<T> TraceDB<T> where T: DatabaseExtras {
/// Ticks our cache system and throws out any old data.
pub fn collect_garbage(&self) {
let mut cache_manager = self.cache_manager.write();
cache_manager.collect_garbage(|| self.cache_size(), | ids | {
let mut traces = self.traces.write();
let mut blooms = self.blooms.write();
let current_size = self.cache_size();
let mut traces = self.traces.write();
let mut blooms = self.blooms.write();
let mut cache_manager = self.cache_manager.write();
cache_manager.collect_garbage(current_size, | ids | {
for id in &ids {
match *id {
CacheID::Trace(ref h) => { traces.remove(h); },
@@ -187,13 +190,16 @@ impl<T> TraceDB<T> where T: DatabaseExtras {
}
traces.shrink_to_fit();
blooms.shrink_to_fit();
traces.heap_size_of_children() + blooms.heap_size_of_children()
});
}
/// Returns traces for block with hash.
fn traces(&self, block_hash: &H256) -> Option<FlatBlockTraces> {
let result = self.tracesdb.read_with_cache(DB_COL_TRACE, &self.traces, block_hash);
self.note_used(CacheID::Trace(block_hash.clone()));
self.tracesdb.read_with_cache(DB_COL_TRACE, &self.traces, block_hash)
result
}
/// Returns vector of transaction traces for given block.
@@ -262,16 +268,6 @@ impl<T> TraceDatabase for TraceDB<T> where T: DatabaseExtras {
return;
}
// at first, let's insert new block traces
{
// note_used must be called before locking traces to avoid cache/traces deadlock on garbage collection
self.note_used(CacheID::Trace(request.block_hash.clone()));
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, traces.deref_mut(), request.block_hash, request.traces, CacheUpdatePolicy::Overwrite);
}
// now let's rebuild the blooms
{
let range_start = request.block_number as Number + 1 - request.enacted.len();
@@ -282,24 +278,38 @@ 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()
.map(|p| (From::from(p.0), From::from(p.1)))
.collect::<HashMap<TraceGroupPosition, blooms::BloomGroup>>();
// note_used must be called before locking blooms to avoid cache/traces deadlock on garbage collection
for key in blooms_to_insert.keys() {
self.note_used(CacheID::Bloom(key.clone()));
}
let blooms_keys: Vec<_> = blooms_to_insert.keys().cloned().collect();
let mut blooms = self.blooms.write();
batch.extend_with_cache(DB_COL_TRACE, blooms.deref_mut(), blooms_to_insert, CacheUpdatePolicy::Remove);
batch.extend_with_cache(DB_COL_TRACE, &mut *blooms, blooms_to_insert, CacheUpdatePolicy::Remove);
// note_used must be called after locking blooms to avoid cache/traces deadlock on garbage collection
for key in blooms_keys.into_iter() {
self.note_used(CacheID::Bloom(key));
}
}
}

View File

@@ -52,11 +52,12 @@ fn update_trace_address(traces: Vec<FlatTrace>) -> Vec<FlatTrace> {
let mut subtrace_subtraces_left = 0;
traces.into_iter().map(|mut trace| {
let is_top_subtrace = trace.trace_address.is_empty();
let is_subtrace = trace.trace_address.len() == 1;
trace.trace_address.push_front(top_subtrace_index);
if is_top_subtrace {
subtrace_subtraces_left = trace.subtraces;
} else {
} else if is_subtrace {
subtrace_subtraces_left -= 1;
}

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

@@ -80,6 +80,23 @@ impl HeapSizeOf for Receipt {
}
}
/// Receipt with additional info.
#[derive(Debug, Clone, PartialEq, Binary)]
pub struct RichReceipt {
/// Transaction hash.
pub transaction_hash: H256,
/// Transaction index.
pub transaction_index: usize,
/// The total gas used in the block following execution of the transaction.
pub cumulative_gas_used: U256,
/// The gas used in the execution of the transaction. Note the difference of meaning to `Receipt::gas_used`.
pub gas_used: U256,
/// Contract address.
pub contract_address: Option<Address>,
/// Logs
pub logs: Vec<LogEntry>,
}
/// Receipt with additional info.
#[derive(Debug, Clone, PartialEq, Binary)]
pub struct LocalizedReceipt {

View File

@@ -181,7 +181,7 @@ impl From<ActionParams> for Create {
from: p.sender,
value: p.value.value(),
gas: p.gas,
init: p.code.unwrap_or_else(Vec::new),
init: p.code.map_or_else(Vec::new, |c| (*c).clone()),
}
}
}

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

@@ -40,7 +40,8 @@ pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &Engine) -> Res
try!(verify_header(&header, engine));
try!(verify_block_integrity(bytes, &header.transactions_root, &header.uncles_hash));
try!(engine.verify_block_basic(&header, Some(bytes)));
for u in Rlp::new(bytes).at(2).iter().map(|rlp| rlp.as_val::<Header>()) {
for u in try!(UntrustedRlp::new(bytes).at(2)).iter().map(|rlp| rlp.as_val::<Header>()) {
let u = try!(u);
try!(verify_header(&u, engine));
try!(engine.verify_block_basic(&u, None));
}
@@ -58,8 +59,8 @@ pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &Engine) -> Res
/// Returns a `PreverifiedBlock` structure populated with transactions
pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> Result<PreverifiedBlock, Error> {
try!(engine.verify_block_unordered(&header, Some(&bytes)));
for u in Rlp::new(&bytes).at(2).iter().map(|rlp| rlp.as_val::<Header>()) {
try!(engine.verify_block_unordered(&u, None));
for u in try!(UntrustedRlp::new(&bytes).at(2)).iter().map(|rlp| rlp.as_val::<Header>()) {
try!(engine.verify_block_unordered(&try!(u), None));
}
// Verify transactions.
let mut transactions = Vec::new();
@@ -84,7 +85,7 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &
try!(verify_parent(&header, &parent));
try!(engine.verify_block_family(&header, &parent, Some(bytes)));
let num_uncles = Rlp::new(bytes).at(2).item_count();
let num_uncles = try!(UntrustedRlp::new(bytes).at(2)).item_count();
if num_uncles != 0 {
if num_uncles > engine.maximum_uncle_count() {
return Err(From::from(BlockError::TooManyUncles(OutOfBounds { min: None, max: Some(engine.maximum_uncle_count()), found: num_uncles })));
@@ -106,7 +107,8 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &
}
}
for uncle in Rlp::new(bytes).at(2).iter().map(|rlp| rlp.as_val::<Header>()) {
for uncle in try!(UntrustedRlp::new(bytes).at(2)).iter().map(|rlp| rlp.as_val::<Header>()) {
let uncle = try!(uncle);
if excluded.contains(&uncle.hash()) {
return Err(From::from(BlockError::UncleInChain(uncle.hash())))
}
@@ -210,13 +212,13 @@ fn verify_parent(header: &Header, parent: &Header) -> Result<(), Error> {
/// Verify block data against header: transactions root and uncles hash.
fn verify_block_integrity(block: &[u8], transactions_root: &H256, uncles_hash: &H256) -> Result<(), Error> {
let block = Rlp::new(block);
let tx = block.at(1);
let block = UntrustedRlp::new(block);
let tx = try!(block.at(1));
let expected_root = &ordered_trie_root(tx.iter().map(|r| r.as_raw().to_vec()).collect()); //TODO: get rid of vectors here
if expected_root != transactions_root {
return Err(From::from(BlockError::InvalidTransactionsRoot(Mismatch { expected: expected_root.clone(), found: transactions_root.clone() })))
}
let expected_uncles = &block.at(2).as_raw().sha3();
let expected_uncles = &try!(block.at(2)).as_raw().sha3();
if expected_uncles != uncles_hash {
return Err(From::from(BlockError::InvalidUnclesHash(Mismatch { expected: expected_uncles.clone(), found: uncles_hash.clone() })))
}
@@ -342,7 +344,7 @@ mod tests {
// Test against morden
let mut good = Header::new();
let spec = Spec::new_test();
let engine = &spec.engine;
let engine = &*spec.engine;
let min_gas_limit = engine.params().min_gas_limit;
good.gas_limit = min_gas_limit;
@@ -358,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,
@@ -367,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() ];
@@ -423,69 +425,69 @@ mod tests {
bc.insert(create_test_block(&parent7));
bc.insert(create_test_block(&parent8));
check_ok(basic_test(&create_test_block(&good), engine.deref()));
check_ok(basic_test(&create_test_block(&good), engine));
let mut header = good.clone();
header.transactions_root = good_transactions_root.clone();
header.uncles_hash = good_uncles_hash.clone();
check_ok(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine.deref()));
check_ok(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine));
header.gas_limit = min_gas_limit - From::from(1);
check_fail(basic_test(&create_test_block(&header), engine.deref()),
check_fail(basic_test(&create_test_block(&header), engine),
InvalidGasLimit(OutOfBounds { min: Some(min_gas_limit), max: None, found: header.gas_limit }));
header = good.clone();
header.number = BlockNumber::max_value();
check_fail(basic_test(&create_test_block(&header), engine.deref()),
check_fail(basic_test(&create_test_block(&header), engine),
RidiculousNumber(OutOfBounds { max: Some(BlockNumber::max_value()), min: None, found: header.number }));
header = good.clone();
header.gas_used = header.gas_limit + From::from(1);
check_fail(basic_test(&create_test_block(&header), engine.deref()),
check_fail(basic_test(&create_test_block(&header), engine),
TooMuchGasUsed(OutOfBounds { max: Some(header.gas_limit), min: None, found: header.gas_used }));
header = good.clone();
header.extra_data.resize(engine.maximum_extra_data_size() + 1, 0u8);
check_fail(basic_test(&create_test_block(&header), engine.deref()),
check_fail(basic_test(&create_test_block(&header), engine),
ExtraDataOutOfBounds(OutOfBounds { max: Some(engine.maximum_extra_data_size()), min: None, found: header.extra_data.len() }));
header = good.clone();
header.extra_data.resize(engine.maximum_extra_data_size() + 1, 0u8);
check_fail(basic_test(&create_test_block(&header), engine.deref()),
check_fail(basic_test(&create_test_block(&header), engine),
ExtraDataOutOfBounds(OutOfBounds { max: Some(engine.maximum_extra_data_size()), min: None, found: header.extra_data.len() }));
header = good.clone();
header.uncles_hash = good_uncles_hash.clone();
check_fail(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine.deref()),
check_fail(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine),
InvalidTransactionsRoot(Mismatch { expected: good_transactions_root.clone(), found: header.transactions_root }));
header = good.clone();
header.transactions_root = good_transactions_root.clone();
check_fail(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine.deref()),
check_fail(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine),
InvalidUnclesHash(Mismatch { expected: good_uncles_hash.clone(), found: header.uncles_hash }));
check_ok(family_test(&create_test_block(&good), engine.deref(), &bc));
check_ok(family_test(&create_test_block_with_data(&good, &good_transactions, &good_uncles), engine.deref(), &bc));
check_ok(family_test(&create_test_block(&good), engine, &bc));
check_ok(family_test(&create_test_block_with_data(&good, &good_transactions, &good_uncles), engine, &bc));
header = good.clone();
header.parent_hash = H256::random();
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine.deref(), &bc),
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc),
UnknownParent(header.parent_hash));
header = good.clone();
header.timestamp = 10;
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine.deref(), &bc),
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc),
InvalidTimestamp(OutOfBounds { max: None, min: Some(parent.timestamp + 1), found: header.timestamp }));
header = good.clone();
header.number = 9;
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine.deref(), &bc),
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc),
InvalidNumber(Mismatch { expected: parent.number + 1, found: header.number }));
header = good.clone();
let mut bad_uncles = good_uncles.clone();
bad_uncles.push(good_uncle1.clone());
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &bad_uncles), engine.deref(), &bc),
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &bad_uncles), engine, &bc),
TooManyUncles(OutOfBounds { max: Some(engine.maximum_uncle_count()), min: None, found: bad_uncles.len() }));
// TODO: some additional uncle checks

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;
}
},
}

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