Compare commits

...

216 Commits

Author SHA1 Message Date
Marek Kotewicz
a9a41a03c5 Merge pull request #1782 from ethcore/beta-staging
BETA: fixed trace_transaction crash when block contained suicide
2016-07-31 17:26:15 +02:00
arkpar
73376f0c3a Removed test 2016-07-31 14:49:23 +02:00
arkpar
e4f6871646 Updated json-ipc-server 2016-07-31 14:40:12 +02:00
arkpar
282e7d10d0 Version 1.2.3 2016-07-31 14:39:37 +02:00
debris
bdd04d10af fixed trace_transaction crash when block contained suicide 2016-07-31 13:18:56 +02:00
Tomasz Drwięga
8b658b257f [beta] Updating UI (#1778)
* Updating UI

* Fix for building without UI
2016-07-31 12:54:02 +02:00
Marek Kotewicz
03fad0869e tracing backport (#1770)
* Suicides tracing (#1688)

* tracing suicide

* fixed #1635

* fixed typo

* Stackoverflow #1686 (#1698)

* flat trace serialization

* tracing finds transaction which creates contract

* flatten traces before inserting them to the db

* Trace other types of calls (#1727)

* Trace through DELEGATECALL and CALLCODE

Add them to the JSON output and RLP database store.

* Fix tests.

* Fix all tests.

* Fix one more test.

* filtering transactions toAddress includes contract creation (#1697)

* tracing finds transaction which creates contract

* comma cleanup

Remove when following `}`s, add to final entries.

* Various improvements to tracing & diagnostics. (#1707)

* Various improvements to tracing & diagnostics.

- Manage possibility of `Account` not having code for `PodAccount`
- New RPC: `trace_sendRawTransaction`
- See raw transaction dump when inspecting over RPC

* Fix test

* Remove one of the dupe error messages

* Remove unneeded `&`s

* Reformat and extremely minor optimisation

* Minor optimisation

* Remove unneeded let

* Fix tests.

* Additional fix.

* Minor rename.

[ci:skip]

* Bowing to the pressure.

* Stackoverflow fix (#1742)

* executive tracer builds flat traces without intermediate struct

* temporarilt commented out tests for traces

* fixed new way of building trace address

* fixed new way of building trace address

* updating state tests with flat tracing in progress

* fixed flat tracing tests

* fixed compiling ethcore-rpc with new flat traces

* removed warnings from ethcore module

* remove unused data structures
2016-07-30 06:39:26 -07:00
Arkadiy Paronyan
8017daf47c Backport commits to beta (#1763)
* Don't try to sync to ancient blocks

* Parallel block body download

* Fixed reading chunked EIP8 handshake (#1712)

* Fixed reading chunked EIP8 handshake

* Added missing break

* Disconnect peers on a fork

* Updated json-ipc-server

* Combine mining queue and enabled into single locked datum (#1749)

* Combine mining queue and enabled into single locked datum

Additional tracing.

* Fix bug uncovered by test.

* Fix typo

* Remove unneeded log initialisation in test.

* fix failing test (#1756)

* Fixed test

* Suicides tracing (#1688)

* tracing suicide

* fixed #1635

* fixed typo

* Stackoverflow #1686 (#1698)

* flat trace serialization

* tracing finds transaction which creates contract

* flatten traces before inserting them to the db

* Trace other types of calls (#1727)

* Trace through DELEGATECALL and CALLCODE

Add them to the JSON output and RLP database store.

* Fix tests.

* Fix all tests.

* Fix one more test.

* filtering transactions toAddress includes contract creation (#1697)

* tracing finds transaction which creates contract

* comma cleanup

Remove when following `}`s, add to final entries.

* Various improvements to tracing & diagnostics. (#1707)

* Various improvements to tracing & diagnostics.

- Manage possibility of `Account` not having code for `PodAccount`
- New RPC: `trace_sendRawTransaction`
- See raw transaction dump when inspecting over RPC

* Fix test

* Remove one of the dupe error messages

* Remove unneeded `&`s

* Reformat and extremely minor optimisation

* Minor optimisation

* Remove unneeded let

* Fix tests.

* Additional fix.

* Minor rename.

* Bowing to the pressure.

* Stackoverflow fix (#1742)

* executive tracer builds flat traces without intermediate struct

* temporarilt commented out tests for traces

* fixed new way of building trace address

* fixed new way of building trace address

* updating state tests with flat tracing in progress

* fixed flat tracing tests

* fixed compiling ethcore-rpc with new flat traces

* removed warnings from ethcore module

* remove unused data structures
2016-07-30 06:37:18 -07:00
Arkadiy Paronyan
429c83f92f Deadlock on incoming connection (#1672) (#1675) 2016-07-20 18:12:07 +02:00
Arkadiy Paronyan
a453bab9e8 Removed DAO soft fork traces (#1640) 2016-07-16 19:50:13 +02:00
Arkadiy Paronyan
2cf4549d01 DAO hard-fork (#1483) (#1636)
* DAO hard-fork (#1483)

* Minor additions to allow resetting of code.

* Add test.

* Provisional DAO hard-fork proposal.

* Change to reflect latest HF spec.

* Include extradata restrictions and overrides.

* Introduce new tests.

* Update tests to new spec format.

* Allow JSON chain spec fields to be optional.

* Remove superfluous definitions. Fix overflow risk.

* Fix build.

* Add missing file.

* Remove old flag.

* Update to latest address set.

* Update tests and test spec to latest.

Change the mining default to release only on own transactions.

* Updated tests submodule
2016-07-16 15:04:02 +02:00
Arkadiy Paronyan
68dfae8f06 Backports for beta (#1628)
* Remove soft-fork stuff.

* Fix tests.

* Fix "pending" parameter on RPC block requests (#1602)

* Initial commit.

* Pending blocks work.

* Address grumbles.

* Fix up for new API.

* Fixed test
2016-07-15 16:44:27 +02:00
Arkadiy Paronyan
b7caa24c2e don't batch best block for branches (#1623) (#1626) 2016-07-15 10:13:12 +02:00
Arkadiy Paronyan
ed5d797662 Merge bugfixes from master to beta (#1605)
* Attempt to fix blochchain DB sync

* Fix bloomchain on blockchain repair

* Make sure reserved peers are in the node table

* fixed #1606 (#1615)
2016-07-14 12:52:07 +02:00
Nikolay Volf
69847e3b8b (BETA) using block options cache instead of general cache for rocksdb (#1613)
* using block options cache instead of general cache for rocksdb

* remove previous cache setup
2016-07-14 10:25:09 +02:00
Arkadiy Paronyan
ef124fa3ef Backport sealing fixes to beta (#1583)
* Update sealing just once when  externally importing many blocks (#1541)

Fixes Issue #1372

* Fixing deadlock in miner (#1569)

* Fixing deadlock in miner
* Adding more comments
2016-07-12 09:52:46 +02:00
Arkadiy Paronyan
aece120e77 v1.2.2 in beta (#1581)
* v1.2.2

* Fixed warning
2016-07-12 09:48:52 +02:00
Gav Wood
cc127eed15 Fix the reseal mechanism. 2016-07-06 12:37:45 +02:00
Gav Wood
acfabe5431 Skipping transactions with invalid nonces when pushing to block. (#1545) (#1547)
* Changing some logging levels

* Skipping invalid nonce errors
2016-07-06 10:41:29 +02:00
arkpar
a600b1ac80 Merge remote-tracking branch 'origin/work-notify' into beta 2016-07-01 13:10:22 +02:00
arkpar
1ce3fc24cf Save the block reference in the queue on notification 2016-07-01 11:37:31 +02:00
Arkadiy Paronyan
7ae0eb8137 Merge pull request #1513 from ethcore/fixmining
Fix the reseal mechanism.
2016-07-01 08:09:06 +02:00
arkpar
df04c95f9a Merge branch 'fixmining' of github.com:ethcore/parity into beta 2016-06-30 23:20:28 +02:00
arkpar
6e7b003e78 Merge branch 'fixmining' of github.com:ethcore/parity into beta 2016-06-30 23:20:12 +02:00
Gav Wood
1d780f456a Fix is_new. 2016-06-30 23:14:54 +02:00
arkpar
0de297adf7 Merge branch 'work-notify' into beta 2016-06-30 22:44:09 +02:00
Gav Wood
29b6ba4a87 Fix the reseal mechanism. 2016-06-30 22:35:59 +02:00
arkpar
5a7fd628db Added comment 2016-06-30 22:34:54 +02:00
Arkadiy Paronyan
cf7830fa8f Merge pull request #1509 from General-Beck/patch-15
Update Dockerfile ubuntu-aarch64
2016-06-30 22:34:24 +02:00
Arkadiy Paronyan
1dc56fc3e1 Merge pull request #1510 from General-Beck/patch-16
Update Ubuntu-arm Dockerfile
2016-06-30 22:34:18 +02:00
Arkadiy Paronyan
91efef8497 Merge pull request #1511 from General-Beck/patch-17
Update Ubuntu-jit Dockerfile
2016-06-30 22:34:15 +02:00
Arkadiy Paronyan
6962e1d211 Merge pull request #1512 from General-Beck/patch-18
Update Ubuntu Dockerfile
2016-06-30 22:34:13 +02:00
Arkadiy Paronyan
dd62e2d43b Merge pull request #1508 from General-Beck/patch-14
Update CentOS Dockerfile
2016-06-30 22:33:55 +02:00
Denis S. Soldatov aka General-Beck
038ef2b3c3 Update Ubuntu Dockerfile
[ci skip]
2016-07-01 03:29:45 +07:00
Denis S. Soldatov aka General-Beck
c8c7fbbf27 Update Ubuntu-jit Dockerfile
[ci skip]
2016-07-01 03:29:00 +07:00
Denis S. Soldatov aka General-Beck
6bbd237711 Update Ubuntu-arm Dockerfile
[ci skip]
2016-07-01 03:28:18 +07:00
Denis S. Soldatov aka General-Beck
6bdbc2cb93 Update Dockerfile ubuntu-aarch64
[ci skip]
2016-07-01 03:27:36 +07:00
Denis S. Soldatov aka General-Beck
f370e17a54 Update CentOS Dockerfile
[ci skip]
2016-07-01 03:26:56 +07:00
Arkadiy Paronyan
30f2e8f60c Merge pull request #1502 from ethcore/bump-status-page
bump status page v0.5.1
2016-06-30 22:16:32 +02:00
Nikolay Volf
4a60407c2a Merge pull request #1507 from General-Beck/patch-13
Update CentOS Dockerfile
2016-07-01 00:16:09 +04:00
Nikolay Volf
5dd3c6196c Merge pull request #1506 from General-Beck/patch-12
Update Dockerfile ubuntu-aarch64
2016-07-01 00:15:56 +04:00
Nikolay Volf
a681566967 Merge pull request #1505 from General-Beck/patch-11
Update Ubuntu-arm Dockerfile
2016-07-01 00:15:41 +04:00
Nikolay Volf
ff0d8ea868 Merge pull request #1504 from General-Beck/patch-10
Update Ubuntu-jit Dockerfile
2016-07-01 00:15:21 +04:00
Nikolay Volf
489ddd1d6f Merge pull request #1503 from General-Beck/patch-9
Update Ubuntu Dockerfile
2016-07-01 00:15:00 +04:00
Denis S. Soldatov aka General-Beck
90a4475f52 Update CentOS Dockerfile
[ci skip]
2016-07-01 03:10:58 +07:00
Denis S. Soldatov aka General-Beck
bee2102424 Update Dockerfile ubuntu-aarch64
[ci skip]
2016-07-01 03:09:48 +07:00
Denis S. Soldatov aka General-Beck
bb70cd889e Update Ubuntu-arm Dockerfile
[ci skip]
2016-07-01 03:08:58 +07:00
Denis S. Soldatov aka General-Beck
8134a89b87 Update Ubuntu-jit Dockerfile
[ci skip]
2016-07-01 03:08:07 +07:00
Denis S. Soldatov aka General-Beck
d3cb79833b Update Ubuntu Dockerfile
[ci skip]
2016-07-01 03:07:22 +07:00
Arkadiy Paronyan
673c5afd4d Update install-parity.sh 2016-06-30 18:56:16 +02:00
arkpar
3921e10af0 Merge branch 'work-notify' of github.com:ethcore/parity into beta 2016-06-30 18:21:12 +02:00
arkpar
4ba8b3c1e0 Merge remote-tracking branch 'origin/master' into beta 2016-06-30 18:20:06 +02:00
goldylucks
6616b5e17d bump status page v0.5.1 2016-06-30 18:14:20 +02:00
goldylucks
a7c332ecea status page bump 2016-06-30 18:07:38 +02:00
arkpar
070c1b170f Save the block reference in the queue on notification 2016-06-30 17:33:21 +02:00
arkpar
c38d15ad4d Merge branch 'master' of github.com:ethcore/parity into beta 2016-06-30 16:11:56 +02:00
Arkadiy Paronyan
24e73f3aec Merge pull request #1497 from ethcore/clone-work
Optionally clone block behind work-package
2016-06-30 15:50:27 +02:00
Gav Wood
6ae467252c Fix no colour on windows. (#1498) 2016-06-30 15:49:00 +02:00
Gav Wood
9c58ebf2d2 Merge branch 'master' into clone-work 2016-06-30 13:16:48 +02:00
Arkadiy Paronyan
ff29c82c9e Merge pull request #1495 from ethcore/work-notify
Workaround for hyper panic
2016-06-30 13:14:24 +02:00
Gav Wood
dff7d9603c Fix for fake new work packages. 2016-06-30 13:12:15 +02:00
Gav Wood
9c07e5c355 Optionally clone block behind work-package. 2016-06-30 12:56:58 +02:00
Gav Wood
5665083e20 UsingQueue can clone rather than just take. 2016-06-30 12:21:04 +02:00
Arkadiy Paronyan
30fad64621 Merge pull request #1488 from ethcore/notification-on-mine
Colourful notification on mine
2016-06-30 11:42:43 +02:00
arkpar
51c6b85f80 Workaround hyper panic 2016-06-30 10:07:33 +02:00
Tomasz Drwięga
af65945b58 Specifying max open files (#1494) 2016-06-30 08:24:01 +02:00
Gav Wood
5a794b21cf Make output less green. 2016-06-30 08:20:34 +02:00
Gav Wood
6ca2e6b29b Remove extraneous messages. 2016-06-30 08:20:34 +02:00
Gav Wood
93a89049ed More colour! 2016-06-30 08:20:34 +02:00
Gav Wood
92edf7f511 Safe coloured logging. 2016-06-30 08:20:34 +02:00
Gav Wood
4a6206c514 Log for when we mine a block with lots of info.
Fixes #1468
2016-06-30 08:20:34 +02:00
Arkadiy Paronyan
60270083e5 Merge pull request #1491 from ethcore/work-notify
Work notification over HTTP
2016-06-30 08:19:45 +02:00
Arkadiy Paronyan
34155730ff Merge pull request #1492 from ethcore/v1.2.1
v1.2.1 in beta
2016-06-30 08:13:17 +02:00
Arkadiy Paronyan
946c1fd76a Merge pull request #1478 from ethcore/seal-import
Sealed block importing and propagation optimization
2016-06-30 08:13:07 +02:00
arkpar
2df737bebf v1.2.1 2016-06-29 22:27:49 +02:00
arkpar
9885bdcf0a Merge remote-tracking branch 'origin/master' into beta 2016-06-29 22:14:42 +02:00
Gav Wood
86ba6f1912 Fix test compilation. 2016-06-29 22:05:00 +02:00
arkpar
ee01ad1324 Shortcut sealed block into the chain 2016-06-29 21:49:22 +02:00
Gav Wood
f24ba94fbd Merge branch 'work-notify' of github.com:ethcore/parity into work-notify 2016-06-29 20:14:32 +02:00
Gav Wood
dc24448900 Include number in eth_getWork. 2016-06-29 20:09:13 +02:00
arkpar
b3f37f3cb4 HTTP work notifier 2016-06-29 20:07:21 +02:00
Gav Wood
e24f9c9936 Add CLI option and route to MinerOptions. 2016-06-29 20:06:03 +02:00
arkpar
19d83a9074 Merge branch 'work-notify' of github.com:ethcore/parity into work-notify 2016-06-29 20:05:11 +02:00
arkpar
5958c87e56 HTTP work notifier 2016-06-29 20:04:52 +02:00
Robert Habermeier
83c967c082 Merge pull request #1487 from ethcore/vm-fact
vm factory to mining client
2016-06-29 18:00:54 +02:00
Adam Goldman
aec4130dca topbar dialog fix (#1479)
* topbar dialog fix

* push goldylucks changes to ethcore umbrella
2016-06-29 17:19:04 +02:00
Gav Wood
98ae9cad6f Minor additions to allow resetting of code. (#1482)
* Minor additions to allow resetting of code.

* Add test.
2016-06-29 16:29:04 +02:00
Gav Wood
5d1ff3d7ba Introduce options for fine-grained management of work queue. (#1484)
* Introduce options for fine-grained management of work queue.

- Minimum reseal period between non-mandatory (transaction) reseals.
- Maximum historical cached block size.

Defaults changed to reflect real-world scenarios (2s, 20 blocks).

* Fix test bug.

* 50 -> 20.
2016-06-29 16:26:19 +02:00
NikVolf
580913fa7d vm factory to mining client 2016-06-29 17:23:29 +03:00
Gav Wood
05927eba1f Include number in eth_getWork. 2016-06-29 15:43:34 +02:00
Gav Wood
7c27f9dfed Add CLI option and route to MinerOptions. 2016-06-29 15:37:11 +02:00
Gav Wood
c096c087df Ensure we don't reject our own transactions for gasprice. (#1485)
* Ensure we don't reject our own transactions for gasprice.

* Add test.
2016-06-29 15:23:41 +02:00
Arkadiy Paronyan
78ebc8b975 Merge pull request #1481 from ethcore/av-signing
Signing parity executable & windows installer in appveyor
2016-06-29 10:39:33 +02:00
Gav Wood
e3214c63c6 Rearrange fork CLI options. (#1476)
* Rearrange fork CLI options.

* Fixed compilation
2016-06-29 09:28:56 +02:00
NikVolf
2138a53067 Merge branch 'master' into av-signing 2016-06-29 02:02:02 +03:00
NikVolf
72771bd833 signing executable also 2016-06-29 01:58:15 +03:00
Nikolay Volf
91aee536ca Merge pull request #1475 from ethcore/appveyor_choking
give appveyor some breath
2016-06-29 02:35:12 +04:00
arkpar
09e1970bbf Merge with master 2016-06-28 20:04:00 +02:00
NikVolf
ebcbb19aef sign command 2016-06-28 21:02:15 +03:00
Tomasz Drwięga
e3ca87c4d1 Updating WS version 2016-06-28 19:40:23 +02:00
Tomasz Drwięga
1fcf5c7cc2 Fixing HTTP file serving on ws-rs 2016-06-28 19:40:22 +02:00
Tomasz Drwięga
dd0e681847 Using stable version of ws-rs 2016-06-28 19:40:22 +02:00
arkpar
c006f446a4 Reduced IO messages; removed panics on IO notifications 2016-06-28 19:39:59 +02:00
Gav Wood
9a16e593e2 Update configuration.rs 2016-06-28 19:39:31 +02:00
Gav Wood
5ef767f7f2 Update cli.rs
[ci:skip]
2016-06-28 19:39:31 +02:00
Nikolay Volf
071da2eec5 fix tests 2016-06-28 19:39:31 +02:00
Nikolay Volf
a3f165cf48 cli config 2016-06-28 19:39:31 +02:00
Nikolay Volf
93facbf854 ethcore client config 2016-06-28 19:39:31 +02:00
Nikolay Volf
42f5d7f897 jdb to new settings config 2016-06-28 19:39:31 +02:00
Nikolay Volf
97e553f1bf extra helpers for prefix 2016-06-28 19:38:48 +02:00
Nikolay Volf
8caa859111 compaction struct and helpers 2016-06-28 19:38:48 +02:00
Gav Wood
a3758161ac Ensure we always get the latest work when mining on submitted. (#1469)
* Ensure we always get the latest work when mining on submitted.

* Build fix.

* Smaller timeslices for the wait.
2016-06-28 18:46:09 +02:00
Marek Kotewicz
38870fb3e4 Merge pull request #1471 from ethcore/tests_for_views
Tests for views
2016-06-28 17:37:27 +02:00
NikVolf
3ae8ccf8c6 signing installer 2016-06-28 18:13:21 +03:00
Nikolay Volf
477fdefb55 json ipc version bump (#1470)
* bump version once

* version bump 2
2016-06-28 16:22:05 +02:00
debris
8dbf182618 give appveyor some breath 2016-06-28 16:10:21 +02:00
debris
2462193df8 Merge branch 'master' of github.com:ethcore/parity into tests_for_views 2016-06-28 14:28:54 +02:00
debris
0b86723e68 tests for HeaderView and BlockView, fixed #144 2016-06-28 14:28:42 +02:00
Marek Kotewicz
af891f65a7 verifier is no longer a template type of client (#1467)
* verifier is no longer a template type of client

* added missing ,
2016-06-28 13:23:15 +02:00
Arkadiy Paronyan
39307b2bea Merge pull request #1460 from ethcore/miner-improvements
Allow configuration of when to reseal blocks.
2016-06-28 13:11:24 +02:00
debris
4ecf23df9a tests for TransactionView 2016-06-28 12:08:30 +02:00
Marek Kotewicz
4f56f8b27c removed unsafe code (#1466) 2016-06-28 11:52:59 +02:00
Tomasz Drwięga
6895a56099 Adding default for value (#1465) 2016-06-28 11:10:39 +02:00
Gav Wood
599a6104b7 Minor renaming. 2016-06-28 10:40:35 +02:00
Gav Wood
31de739122 U256 instead of Option<U256>. Fix up tests. 2016-06-28 10:21:29 +02:00
Gav Wood
af935df553 Merge branch 'master' into miner-improvements 2016-06-28 10:02:33 +02:00
Gav Wood
d0cec2434e Merge branch 'miner-improvements' of github.com:ethcore/parity into miner-improvements 2016-06-28 10:00:51 +02:00
Gav Wood
c221f69ccd Clean up some of the FP stuff. 2016-06-28 10:00:28 +02:00
Arkadiy Paronyan
a3a68a20f4 Merge pull request #1461 from ethcore/db-repair
Attempt DB repair if corrupted
2016-06-28 07:37:49 +02:00
Arkadiy Paronyan
993f707fbe Merge pull request #1454 from ethcore/db-config-ext
Database configuration extended
2016-06-28 07:07:05 +02:00
Gav Wood
ff788e4199 Fix another typo
[ci:skip]
2016-06-27 21:06:40 +02:00
Gav Wood
5919c660e5 Fix typo
[ci:skip]
2016-06-27 21:06:10 +02:00
Gav Wood
495e56034f Merge branch 'master' into miner-improvements 2016-06-27 21:02:55 +02:00
arkpar
ed153995f9 Attempt DB repair if corrupted 2016-06-27 20:41:02 +02:00
arkpar
150d7c1c78 Merge remote-tracking branch 'origin/master' into db-config-ext 2016-06-27 20:33:07 +02:00
arkpar
5d67a32cef Merge remote-tracking branch 'origin/master' into miner-improvements 2016-06-27 20:31:57 +02:00
Gav Wood
10aa32b0f5 Include RPC configurability for max tx gas limit.
Also Move the gas limit into the transaction queue from the miner.
2016-06-27 20:19:01 +02:00
Arkadiy Paronyan
a83def78b3 Merge pull request #1459 from ethcore/stable-ws
Updating WS-RS server
2016-06-27 19:53:24 +02:00
Arkadiy Paronyan
60b70dada1 Reduced IO messages; removed panics on IO notifications (#1457) 2016-06-27 19:30:13 +02:00
Gav Wood
dc79e63db7 Update configuration.rs 2016-06-27 19:22:54 +02:00
Gav Wood
7b5eeb1dd7 Update cli.rs
[ci:skip]
2016-06-27 19:22:28 +02:00
Gav Wood
a102015ecf Fix doc test. 2016-06-27 19:16:26 +02:00
Gav Wood
2a51a30d41 Fix up the pending set stuff. 2016-06-27 19:06:54 +02:00
Nikolay Volf
9f4bfd9e7a fix tests 2016-06-27 18:47:50 +02:00
Gav Wood
1667808ecb More miner options.
- Optional limit for the amount of gas transactions may have;
- option to restruct transactions returned/queried to only those
which have been executed.
2016-06-27 18:27:06 +02:00
Tomasz Drwięga
ac9e6f2649 Handle errors when starting parity (#1451) 2016-06-27 17:24:47 +02:00
Arkadiy Paronyan
33dfb819f0 Fixed losing queued blocks on ancient block error (#1453) 2016-06-27 17:24:36 +02:00
Gav Wood
6c1802e412 Allow configuration of when to reseal blocks. 2016-06-27 17:23:54 +02:00
arkpar
2e99bfafc8 Updated to latest hyper with patched mio 2016-06-27 17:22:38 +02:00
Gav Wood
a2c4d550d0 Retweak BASE and MULTIPLIER in rocksdb config. (#1445) 2016-06-27 17:21:25 +02:00
Gav Wood
bc8ba10184 More conservative settings for rocksdb. (#1440) 2016-06-27 17:09:18 +02:00
Tomasz Drwięga
222404f801 Updating WS version 2016-06-27 16:34:46 +02:00
Tomasz Drwięga
044bf5511a Fixing HTTP file serving on ws-rs 2016-06-27 16:34:39 +02:00
Tomasz Drwięga
1fdbfa14ad Handle errors when starting parity (#1451) 2016-06-27 16:00:16 +02:00
Arkadiy Paronyan
6859152c21 Fixed losing queued blocks on ancient block error (#1453) 2016-06-27 15:59:45 +02:00
Nikolay Volf
f9f25fd147 cli config 2016-06-27 14:25:50 +02:00
Nikolay Volf
2e5d5f12dd ethcore client config 2016-06-27 13:58:12 +02:00
Nikolay Volf
627b67db0a jdb to new settings config 2016-06-27 13:23:50 +02:00
Nikolay Volf
07098fd16f extra helpers for prefix 2016-06-27 13:14:40 +02:00
Nikolay Volf
e4763e90bc compaction struct and helpers 2016-06-27 13:03:34 +02:00
Marek Kotewicz
6b51dffca0 Merge pull request #1450 from ethcore/rpc-server-fix
Updated to latest hyper with patched mio
2016-06-27 11:36:37 +02:00
arkpar
c21550a663 Updated to latest hyper with patched mio 2016-06-27 10:39:37 +02:00
Gav Wood
4f1f33d1b8 Retweak BASE and MULTIPLIER in rocksdb config. (#1445) 2016-06-27 09:20:38 +02:00
Marek Kotewicz
b3398cec33 Merge pull request #1410 from ethcore/miner-no-default
Removing Miner::default.
2016-06-27 09:18:42 +02:00
Tomasz Drwięga
593d947fcd Using stable version of ws-rs 2016-06-26 23:48:59 +02:00
Tomasz Drwięga
2bd0c5ebcb Unwrap or default 2016-06-26 22:48:09 +02:00
Tomasz Drwięga
6bbaced3cd Merge branch 'master' into miner-no-default
Conflicts:
	ethcore/src/miner/miner.rs
	parity/main.rs
2016-06-26 22:44:34 +02:00
Gav Wood
cdc34957db Don't mine without --author (#1436)
Requires --author to be set before mining is allowed to happen.
2016-06-26 22:28:55 +02:00
Gav Wood
8a644e7185 Revert the rescuedao extradata. 2016-06-26 22:28:27 +02:00
Gav Wood
516b015325 Don't mine without --author (#1436)
Requires --author to be set before mining is allowed to happen.
2016-06-26 22:02:17 +02:00
Arkadiy Paronyan
2ef929dcbd Merge pull request #1437 from ethcore/revertrescuedaoed
Revert the rescuedao extradata.
2016-06-26 14:27:56 +02:00
Gav Wood
2400001675 More conservative settings for rocksdb. (#1440) 2016-06-25 23:13:34 +02:00
Gav Wood
2574d000a3 Revert the rescuedao extradata. 2016-06-25 14:35:43 +02:00
Arkadiy Paronyan
a72d8ee0e7 v1.3.0 (#1421) 2016-06-25 10:32:05 +02:00
Arkadiy Paronyan
482d910b15 Merge pull request #1429 from General-Beck/patch-7
Update Ubuntu-arm Dockerfile
2016-06-24 22:53:33 +02:00
Arkadiy Paronyan
b02d7a4311 Merge pull request #1430 from General-Beck/patch-8
Create Dockerfile ubuntu-aarch64
2016-06-24 22:53:11 +02:00
Denis S. Soldatov aka General-Beck
ab0d280232 Create Dockerfile ubuntu-aarch64
Create Dockerfile ubuntu-aarch64
[ci skip]
2016-06-25 03:51:05 +07:00
Denis S. Soldatov aka General-Beck
4fd0a95112 Update Ubuntu-arm Dockerfile
Update Ubuntu-arm Dockerfile
[ci skip]
2016-06-25 02:58:06 +07:00
Arkadiy Paronyan
59d1a82814 Merge pull request #1424 from General-Beck/patch-4
Update CentOS Dockerfile
2016-06-24 21:55:45 +02:00
Arkadiy Paronyan
83af81f443 Merge pull request #1426 from General-Beck/patch-5
Update Ubuntu Dockerfile
2016-06-24 21:52:58 +02:00
Arkadiy Paronyan
6c40cdf5c6 Merge pull request #1427 from General-Beck/patch-6
Update Ubuntu-jit Dockerfile
2016-06-24 21:52:35 +02:00
Denis S. Soldatov aka General-Beck
a109a4a72b Update Ubuntu-jit Dockerfile
Update Ubuntu-jit Dockerfile
[ci skip]
2016-06-25 02:03:36 +07:00
Denis S. Soldatov aka General-Beck
102626f2c2 Update Ubuntu Dockerfile
Update Ubuntu Dockerfile
[ci skip]
2016-06-25 01:57:29 +07:00
Denis S. Soldatov aka General-Beck
8cc349bcb0 Update Dockerfile
Update CentOS Dockerfile
[ci skip]
2016-06-25 00:59:03 +07:00
Arkadiy Paronyan
3c63244c00 Merge pull request #1418 from ethcore/newblocknumber
Update SF blocknumber to 1800000.
2016-06-24 17:50:03 +02:00
Arkadiy Paronyan
a9b757a75c Update install-parity.sh 2016-06-24 17:27:43 +02:00
Arkadiy Paronyan
92bc21ba9c Update README.md 2016-06-24 17:04:40 +02:00
Arkadiy Paronyan
879bee994d Merge pull request #1420 from ethcore/pdb-exe-artifact
(BETA) add artifacts
2016-06-24 16:53:13 +02:00
NikVolf
a6f7957042 add artifacts 2016-06-24 17:48:42 +03:00
arkpar
2785d61e75 Merge branch 'newblocknumber' of github.com:ethcore/parity into beta 2016-06-24 16:34:26 +02:00
arkpar
8b49b315d9 Merge branch 'master' of github.com:ethcore/parity into beta 2016-06-24 16:34:17 +02:00
Arkadiy Paronyan
313d9048bf Merge pull request #1417 from ethcore/ui
Signer enabled by default for UI
2016-06-24 16:31:14 +02:00
Arkadiy Paronyan
29e2ba91a7 Merge pull request #1415 from ethcore/removebadpruningoptions
Remove experimental pruning options.
2016-06-24 16:16:48 +02:00
Gav Wood
bf11fb6633 Fix up selection. 2016-06-24 16:12:15 +02:00
arkpar
3e7edb2665 More cases 2016-06-24 14:29:15 +02:00
Gav Wood
60d259c9d5 Update SF blocknumber to 1800000. 2016-06-24 14:20:50 +02:00
arkpar
568dc90769 Signer enabled by default for UI 2016-06-24 14:20:39 +02:00
Arkadiy Paronyan
b9649c0e78 Merge pull request #1414 from ethcore/uifix
Fixing interface and port for parity ui
2016-06-24 14:08:06 +02:00
Arkadiy Paronyan
4e0d6f735a Merge pull request #1405 from ethcore/sfedgecase
Configurable gas limit cap.
2016-06-24 13:36:40 +02:00
Gav Wood
44d6e1f443 Remove experimental pruning options. 2016-06-24 13:32:43 +02:00
Arkadiy Paronyan
031a91ebc6 Merge pull request #1413 from ethcore/dapps-bump
Bumping TopBar, Minimal SignerUI and wallet
2016-06-24 13:00:29 +02:00
Tomasz Drwięga
4ece68349c Fixing sync doctests 2016-06-24 12:41:48 +02:00
Tomasz Drwięga
653a368783 Changing macos impl 2016-06-24 12:30:54 +02:00
Tomasz Drwięga
566bb030ec Fixing detecting if dapps are off 2016-06-24 12:21:21 +02:00
Tomasz Drwięga
23732fa516 Fixing interface and port for parity ui 2016-06-24 12:10:36 +02:00
Gav Wood
84ce5af2b0 max/min incorrect 2016-06-24 11:40:25 +02:00
Tomasz Drwięga
e3e10335f9 Bumping TopBar, Minimal SignerUI and wallet 2016-06-24 11:26:04 +02:00
Nikolay Volf
54fc5a533b Merge pull request #1411 from ethcore/sync
Sync: Update highest block for progress reporting
2016-06-24 12:21:01 +03:00
Tomasz Drwięga
dc7c53d59a Fixing json tests 2016-06-24 10:57:44 +02:00
Tomasz Drwięga
34c89e5841 fixing json_tests 2016-06-24 10:49:13 +02:00
arkpar
e77cce66a1 Update highest block progress 2016-06-23 22:40:44 +02:00
Tomasz Drwięga
6edb981bfa Merge branch 'master' into miner-no-default
Conflicts:
	sync/src/lib.rs
2016-06-23 21:18:43 +02:00
Gav Wood
bca9e1f31a Merge branch 'master' into sfedgecase 2016-06-23 14:43:42 +02:00
Gav Wood
41e0769e63 Fix tests, 2016-06-23 14:43:20 +02:00
Gav Wood
8fcec20398 Gas limit ceiling option. 2016-06-23 14:29:16 +02:00
Tomasz Drwięga
a2f24a0083 Removing Default from Miner 2016-06-20 10:28:38 +02:00
153 changed files with 4349 additions and 2320 deletions

153
Cargo.lock generated
View File

@@ -1,6 +1,6 @@
[root]
name = "parity"
version = "1.2.0"
version = "1.2.3"
dependencies = [
"ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -16,11 +16,11 @@ dependencies = [
"ethcore-ipc-nano 1.2.0",
"ethcore-rpc 1.2.0",
"ethcore-signer 1.2.0",
"ethcore-util 1.2.0",
"ethcore-util 1.2.3",
"ethsync 1.2.0",
"fdlimit 0.1.0",
"hyper 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"json-ipc-server 0.2.3 (git+https://github.com/ethcore/json-ipc-server.git)",
"json-ipc-server 0.2.4 (git+https://github.com/ethcore/json-ipc-server.git)",
"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)",
@@ -164,7 +164,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.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -257,10 +257,11 @@ dependencies = [
"ethcore-devtools 1.2.0",
"ethcore-ipc 1.2.0",
"ethcore-ipc-codegen 1.2.0",
"ethcore-util 1.2.0",
"ethcore-util 1.2.3",
"ethjson 0.1.0",
"ethstore 0.1.0",
"heapsize 0.3.5 (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)",
"num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -277,22 +278,22 @@ version = "1.2.0"
dependencies = [
"clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-rpc 1.2.0",
"ethcore-util 1.2.0",
"hyper 0.9.3 (git+https://github.com/ethcore/hyper)",
"ethcore-util 1.2.3",
"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 5.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)",
"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.3.0 (git+https://github.com/ethcore/parity-dapps-rs.git)",
"parity-dapps-builtins 0.5.1 (git+https://github.com/ethcore/parity-dapps-builtins-rs.git)",
"parity-dapps-status 0.5.0 (git+https://github.com/ethcore/parity-dapps-status-rs.git)",
"parity-dapps-wallet 0.6.1 (git+https://github.com/ethcore/parity-dapps-wallet-rs.git)",
"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)",
"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)",
"url 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -307,7 +308,7 @@ name = "ethcore-ipc"
version = "1.2.0"
dependencies = [
"ethcore-devtools 1.2.0",
"ethcore-util 1.2.0",
"ethcore-util 1.2.3",
"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)",
]
@@ -341,10 +342,10 @@ dependencies = [
"ethash 1.2.0",
"ethcore 1.2.0",
"ethcore-devtools 1.2.0",
"ethcore-util 1.2.0",
"ethcore-util 1.2.3",
"ethjson 0.1.0",
"ethsync 1.2.0",
"json-ipc-server 0.2.3 (git+https://github.com/ethcore/json-ipc-server.git)",
"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 5.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -363,19 +364,20 @@ dependencies = [
"clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-rpc 1.2.0",
"ethcore-util 1.2.0",
"ethcore-util 1.2.3",
"jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-minimal-sysui 0.1.0 (git+https://github.com/ethcore/parity-dapps-minimal-sysui-rs.git)",
"parity-dapps-signer 0.6.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.1 (git+https://github.com/ethcore/ws-rs.git)",
"ws 0.5.0 (git+https://github.com/ethcore/ws-rs.git?branch=stable)",
]
[[package]]
name = "ethcore-util"
version = "1.2.0"
version = "1.2.3"
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)",
"bigint 0.1.0",
"chrono 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -412,7 +414,7 @@ dependencies = [
name = "ethjson"
version = "0.1.0"
dependencies = [
"ethcore-util 1.2.0",
"ethcore-util 1.2.3",
"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)",
@@ -454,7 +456,7 @@ dependencies = [
"clippy 0.0.77 (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.2.0",
"ethcore-util 1.2.0",
"ethcore-util 1.2.3",
"heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -546,23 +548,22 @@ dependencies = [
[[package]]
name = "hyper"
version = "0.9.3"
source = "git+https://github.com/ethcore/hyper#dbb4cf160ebf242f7f0459d547c40e9e6877ccf4"
version = "0.9.4"
source = "git+https://github.com/ethcore/hyper#9e346c1d4bc30cd4142dea9d8a0b117d30858ca4"
dependencies = [
"cookie 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rotor 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rotor 0.6.3 (git+https://github.com/ethcore/rotor)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"spmc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"spmc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"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.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -595,8 +596,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "json-ipc-server"
version = "0.2.3"
source = "git+https://github.com/ethcore/json-ipc-server.git#bfe16b66b2e9412d153b1ea53bc078d74037da7f"
version = "0.2.4"
source = "git+https://github.com/ethcore/json-ipc-server.git#7a02a0f8b249fda100b9bab5f90b2081d410d8cf"
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)",
@@ -630,9 +631,9 @@ dependencies = [
[[package]]
name = "jsonrpc-http-server"
version = "5.1.0"
source = "git+https://github.com/ethcore/jsonrpc-http-server.git#0c99d308bc15e8fae50642eff77a3e1fd7610652"
source = "git+https://github.com/ethcore/jsonrpc-http-server.git#e59c2fbaca499620874023755cb91f05b858ffe7"
dependencies = [
"hyper 0.9.3 (git+https://github.com/ethcore/hyper)",
"hyper 0.9.4 (git+https://github.com/ethcore/hyper)",
"jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -712,26 +713,10 @@ dependencies = [
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mio"
version = "0.5.0"
source = "git+https://github.com/carllerche/mio.git#f4aa49a9d2c4507fb33a4533d5238e0365f67c99"
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)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.5.0-pre (git+https://github.com/carllerche/nix-rust?rev=c4257f8a76)",
"slab 0.1.3 (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)",
]
[[package]]
name = "mio"
version = "0.5.1"
source = "git+https://github.com/ethcore/mio?branch=v0.5.x#1fc881771fb8c2517317b4f805d7b88235be422b"
source = "git+https://github.com/ethcore/mio?branch=v0.5.x#3842d3b250ffd7bd9b16f9586b875ddcbac2b0dd"
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)",
@@ -801,15 +786,6 @@ dependencies = [
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nix"
version = "0.5.0-pre"
source = "git+https://github.com/carllerche/nix-rust?rev=c4257f8a76#c4257f8a76b69b0d2e9a001d83e4bef67c03b23f"
dependencies = [
"bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nix"
version = "0.5.0"
@@ -921,8 +897,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "parity-dapps"
version = "0.3.0"
source = "git+https://github.com/ethcore/parity-dapps-rs.git#8cc812c26c903cf5764ce0f4cc3f2a7c3ddb0dc2"
version = "0.6.0"
source = "git+https://github.com/ethcore/parity-ui.git#7120546d08d4d9eb648e255c04935002223d362f"
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)",
@@ -934,34 +910,37 @@ dependencies = [
]
[[package]]
name = "parity-dapps-builtins"
version = "0.5.1"
source = "git+https://github.com/ethcore/parity-dapps-builtins-rs.git#650b0d94d076635904b86c1fd45c5f4a2061463f"
name = "parity-dapps-home"
version = "0.6.0"
source = "git+https://github.com/ethcore/parity-ui.git#7120546d08d4d9eb648e255c04935002223d362f"
dependencies = [
"parity-dapps 0.3.0 (git+https://github.com/ethcore/parity-dapps-rs.git)",
"parity-dapps 0.6.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#7120546d08d4d9eb648e255c04935002223d362f"
dependencies = [
"parity-dapps 0.6.0 (git+https://github.com/ethcore/parity-ui.git)",
]
[[package]]
name = "parity-dapps-status"
version = "0.5.0"
source = "git+https://github.com/ethcore/parity-dapps-status-rs.git#0cdd3512004e403aff7da3b8c16ba0bf5d6c911c"
version = "0.6.0"
source = "git+https://github.com/ethcore/parity-ui.git#7120546d08d4d9eb648e255c04935002223d362f"
dependencies = [
"parity-dapps 0.3.0 (git+https://github.com/ethcore/parity-dapps-rs.git)",
"parity-dapps 0.6.0 (git+https://github.com/ethcore/parity-ui.git)",
]
[[package]]
name = "parity-dapps-wallet"
version = "0.6.1"
source = "git+https://github.com/ethcore/parity-dapps-wallet-rs.git#8923d4c73359c75ce04f0639bbcde46adb846b81"
version = "0.6.0"
source = "git+https://github.com/ethcore/parity-ui.git#7120546d08d4d9eb648e255c04935002223d362f"
dependencies = [
"parity-dapps 0.3.0 (git+https://github.com/ethcore/parity-dapps-rs.git)",
"parity-dapps 0.6.0 (git+https://github.com/ethcore/parity-ui.git)",
]
[[package]]
name = "parity-minimal-sysui"
version = "0.1.0"
source = "git+https://github.com/ethcore/parity-dapps-minimal-sysui-rs.git#3c6ad40680126a760eb867b07b506ea996819ce3"
[[package]]
name = "phf"
version = "0.7.14"
@@ -1057,7 +1036,7 @@ dependencies = [
[[package]]
name = "quick-error"
version = "0.2.2"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -1103,7 +1082,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#6f3c68f5f075433d206be4af6a620651cd9f8541"
source = "git+https://github.com/ethcore/rust-rocksdb#6472a9dce16c267a3acec2ee6fd01d1bf8de4913"
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)",
@@ -1112,7 +1091,7 @@ dependencies = [
[[package]]
name = "rocksdb-sys"
version = "0.3.0"
source = "git+https://github.com/ethcore/rust-rocksdb#6f3c68f5f075433d206be4af6a620651cd9f8541"
source = "git+https://github.com/ethcore/rust-rocksdb#6472a9dce16c267a3acec2ee6fd01d1bf8de4913"
dependencies = [
"gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1121,12 +1100,11 @@ dependencies = [
[[package]]
name = "rotor"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
source = "git+https://github.com/ethcore/rotor#e63d45137b2eb66d1e085a7c6321a5db8b187576"
dependencies = [
"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)",
"quick-error 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)",
"quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1249,7 +1227,7 @@ dependencies = [
[[package]]
name = "spmc"
version = "0.2.0"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -1408,7 +1386,7 @@ dependencies = [
[[package]]
name = "url"
version = "1.0.0"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1472,16 +1450,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ws"
version = "0.5.1"
source = "git+https://github.com/ethcore/ws-rs.git#d5745df8ea1ab82cd2b844f15ca1ac759e7aa9f5"
version = "0.5.0"
source = "git+https://github.com/ethcore/ws-rs.git?branch=stable#a876fc115c3ef50a17c8822c9bd2f6e94473e005"
dependencies = [
"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.0 (git+https://github.com/carllerche/mio.git)",
"mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)",
"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)",
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]

View File

@@ -1,7 +1,7 @@
[package]
description = "Ethcore client."
name = "parity"
version = "1.2.0"
version = "1.2.3"
license = "GPL-3.0"
authors = ["Ethcore <admin@ethcore.io>"]
build = "build.rs"
@@ -47,9 +47,11 @@ version = "0.8"
default-features = false
[features]
default = ["rpc", "dapps", "ethcore-signer"]
rpc = ["ethcore-rpc"]
default = ["rpc", "ethcore-signer", "ui", "use-precompiled-js"]
ui = ["dapps", "ethcore-signer/ui"]
use-precompiled-js = ["ethcore-dapps/use-precompiled-js", "ethcore-signer/use-precompiled-js"]
dapps = ["ethcore-dapps"]
rpc = ["ethcore-rpc"]
dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev",
"ethcore-dapps/dev", "ethcore-signer/dev"]
travis-beta = ["ethcore/json-tests"]

View File

@@ -31,7 +31,7 @@ In a near-future release, it will be easy to install Dapps and use them through
If you run into an issue while using parity, feel free to file one in this repository
or hop on our [gitter chat room]([gitter-url]) to ask a question. We are glad to help!
Parity's current release is 1.1. You can download it at https://ethcore.io/parity.html or follow the instructions
Parity's current release is 1.2. You can download it at https://ethcore.io/parity.html or follow the instructions
below to build from source.
----

View File

@@ -1,13 +1,27 @@
environment:
matrix:
- TARGET: x86_64-pc-windows-msvc
cert:
secure: ESPpYVVAMG1fbJx6kq4ct/g9SQTXac4Hs6xXr6Oh4Zrk2dwYglNjxmzErdPnvu7gs/gekzrJ6KEQHYRc+5+4dKg6rRADQ681NLVx9vOggBs=
certpass:
secure: 0BgXJqxq9Ei34/hZ7121FQ==
keyfile: C:\users\appveyor\Certificates.p12
branches:
only:
- master
- /^beta-.*$/
- /^stable-.*$/
- /^beta$/
- /^stable$/
install:
- git submodule update --init --recursive
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.9.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.9.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
- 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
@@ -18,11 +32,18 @@ test_script:
after_test:
- cargo build --verbose --release
- ps: if($env:cert) { Start-FileDownload $env:cert -FileName $env:keyfile }
- ps: if($env:cert) { signtool sign /f $env:keyfile /p $env:certpass target\release\parity.exe }
- makensis.exe nsis\installer.nsi
- ps: if($env:cert) { signtool sign /f $env:keyfile /p $env:certpass nsis\installer.exe }
artifacts:
- path: nsis\installer.exe
name: Windows Installer (x86_64)
- path: target\release\parity.exe
name: Windows Executable (x86_64)
- path: target\release\parity.pdb
name: Windows Executable Debug Symbols (x86_64)
cache:
- target

View File

@@ -20,13 +20,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-dapps-rs.git", version = "0.3" }
parity-dapps = { git = "https://github.com/ethcore/parity-ui.git", version = "0.6" }
# List of apps
parity-dapps-status = { git = "https://github.com/ethcore/parity-dapps-status-rs.git", version = "0.5.0" }
parity-dapps-builtins = { git = "https://github.com/ethcore/parity-dapps-builtins-rs.git", version = "0.5.0" }
parity-dapps-wallet = { git = "https://github.com/ethcore/parity-dapps-wallet-rs.git", version = "0.6.0", optional = true }
parity-dapps-dao = { git = "https://github.com/ethcore/parity-dapps-dao-rs.git", version = "0.4.0", optional = true }
parity-dapps-makerotc = { git = "https://github.com/ethcore/parity-dapps-makerotc-rs.git", version = "0.3.0", optional = true }
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 }
mime_guess = { version = "1.6.1" }
clippy = { version = "0.0.77", optional = true}
@@ -39,3 +37,9 @@ default = ["serde_codegen", "extra-dapps"]
extra-dapps = ["parity-dapps-wallet"]
nightly = ["serde_macros"]
dev = ["clippy", "ethcore-rpc/dev", "ethcore-util/dev"]
use-precompiled-js = [
"parity-dapps-status/use-precompiled-js",
"parity-dapps-home/use-precompiled-js",
"parity-dapps-wallet/use-precompiled-js"
]

View File

@@ -22,7 +22,7 @@ use parity_dapps::WebApp;
mod fs;
extern crate parity_dapps_status;
extern crate parity_dapps_builtins;
extern crate parity_dapps_home;
pub const DAPPS_DOMAIN : &'static str = ".parity";
pub const RPC_PATH : &'static str = "rpc";
@@ -34,7 +34,7 @@ pub fn main_page() -> &'static str {
}
pub fn utils() -> Box<Endpoint> {
Box::new(PageEndpoint::with_prefix(parity_dapps_builtins::App::default(), UTILS_PATH.to_owned()))
Box::new(PageEndpoint::with_prefix(parity_dapps_home::App::default(), UTILS_PATH.to_owned()))
}
pub fn all_endpoints(dapps_path: String) -> Endpoints {
@@ -44,7 +44,7 @@ pub fn all_endpoints(dapps_path: String) -> Endpoints {
// because we use Cross-Origin LocalStorage.
// TODO [ToDr] Account naming should be moved to parity.
pages.insert("home".into(), Box::new(
PageEndpoint::new_safe_to_embed(parity_dapps_builtins::App::default())
PageEndpoint::new_safe_to_embed(parity_dapps_home::App::default())
));
pages.insert("proxy".into(), ProxyPac::boxed());
insert::<parity_dapps_status::App>(&mut pages, "parity");
@@ -52,8 +52,6 @@ pub fn all_endpoints(dapps_path: String) -> Endpoints {
// Optional dapps
wallet_page(&mut pages);
daodapp_page(&mut pages);
makerotc_page(&mut pages);
pages
}
@@ -66,22 +64,6 @@ fn wallet_page(pages: &mut Endpoints) {
#[cfg(not(feature = "parity-dapps-wallet"))]
fn wallet_page(_pages: &mut Endpoints) {}
#[cfg(feature = "parity-dapps-dao")]
fn daodapp_page(pages: &mut Endpoints) {
extern crate parity_dapps_dao;
insert::<parity_dapps_dao::App>(pages, "dao");
}
#[cfg(not(feature = "parity-dapps-dao"))]
fn daodapp_page(_pages: &mut Endpoints) {}
#[cfg(feature = "parity-dapps-makerotc")]
fn makerotc_page(pages: &mut Endpoints) {
extern crate parity_dapps_makerotc;
insert::<parity_dapps_makerotc::App>(pages, "makerotc");
}
#[cfg(not(feature = "parity-dapps-makerotc"))]
fn makerotc_page(_pages: &mut Endpoints) {}
fn insert<T : WebApp + Default + 'static>(pages: &mut Endpoints, id: &str) {
pages.insert(id.to_owned(), Box::new(PageEndpoint::new(T::default())));
}

View File

@@ -42,11 +42,11 @@ pub struct EndpointInfo {
pub trait Endpoint : Send + Sync {
fn info(&self) -> Option<&EndpointInfo> { None }
fn to_handler(&self, path: EndpointPath) -> Box<server::Handler<HttpStream>>;
fn to_handler(&self, path: EndpointPath) -> Box<server::Handler<HttpStream> + Send>;
}
pub type Endpoints = BTreeMap<String, Box<Endpoint>>;
pub type Handler = server::Handler<HttpStream>;
pub type Handler = server::Handler<HttpStream> + Send;
pub struct ContentHandler {
content: String,
@@ -65,7 +65,7 @@ impl ContentHandler {
}
impl server::Handler<HttpStream> for ContentHandler {
fn on_request(&mut self, _request: server::Request) -> Next {
fn on_request(&mut self, _request: server::Request<HttpStream>) -> Next {
Next::write()
}

View File

@@ -132,9 +132,16 @@ impl Server {
special.clone(),
authorization.clone(),
))
.map(|l| Server {
server: Some(l),
panic_handler: panic_handler,
.map(|(l, srv)| {
::std::thread::spawn(move || {
srv.run();
});
Server {
server: Some(l),
panic_handler: panic_handler,
}
})
.map_err(ServerError::from)
}

View File

@@ -86,7 +86,7 @@ impl<T: Dapp> PageHandler<T> {
}
impl<T: Dapp> server::Handler<HttpStream> for PageHandler<T> {
fn on_request(&mut self, req: server::Request) -> Next {
fn on_request(&mut self, req: server::Request<HttpStream>) -> Next {
self.file = match *req.uri() {
RequestUri::AbsolutePath(ref path) => {
self.app.file(&self.extract_path(path))

View File

@@ -27,13 +27,13 @@ pub enum Authorized {
/// Authorization was successful.
Yes,
/// Unsuccessful authorization. Handler for further work is returned.
No(Box<server::Handler<HttpStream>>),
No(Box<server::Handler<HttpStream> + Send>),
}
/// Authorization interface
pub trait Authorization : Send + Sync {
/// Checks if authorization is valid.
fn is_authorized(&self, req: &server::Request)-> Authorized;
fn is_authorized(&self, req: &server::Request<HttpStream>)-> Authorized;
}
/// HTTP Basic Authorization handler
@@ -45,13 +45,13 @@ pub struct HttpBasicAuth {
pub struct NoAuth;
impl Authorization for NoAuth {
fn is_authorized(&self, _req: &server::Request)-> Authorized {
fn is_authorized(&self, _req: &server::Request<HttpStream>)-> Authorized {
Authorized::Yes
}
}
impl Authorization for HttpBasicAuth {
fn is_authorized(&self, req: &server::Request) -> Authorized {
fn is_authorized(&self, req: &server::Request<HttpStream>) -> Authorized {
let auth = self.check_auth(&req);
match auth {
@@ -89,7 +89,7 @@ impl HttpBasicAuth {
self.users.get(&username.to_owned()).map_or(false, |pass| pass == password)
}
fn check_auth(&self, req: &server::Request) -> Access {
fn check_auth(&self, req: &server::Request<HttpStream>) -> Access {
match req.headers().get::<header::Authorization<header::Basic>>() {
Some(&header::Authorization(
header::Basic { ref username, password: Some(ref password) }
@@ -105,7 +105,7 @@ pub struct UnauthorizedHandler {
}
impl server::Handler<HttpStream> for UnauthorizedHandler {
fn on_request(&mut self, _request: server::Request) -> Next {
fn on_request(&mut self, _request: server::Request<HttpStream>) -> Next {
Next::write()
}
@@ -141,7 +141,7 @@ impl server::Handler<HttpStream> for UnauthorizedHandler {
pub struct AuthRequiredHandler;
impl server::Handler<HttpStream> for AuthRequiredHandler {
fn on_request(&mut self, _request: server::Request) -> Next {
fn on_request(&mut self, _request: server::Request<HttpStream>) -> Next {
Next::write()
}

View File

@@ -49,12 +49,12 @@ pub struct Router<A: Authorization + 'static> {
endpoints: Arc<Endpoints>,
special: Arc<HashMap<SpecialEndpoint, Box<Endpoint>>>,
authorization: Arc<A>,
handler: Box<server::Handler<HttpStream>>,
handler: Box<server::Handler<HttpStream> + Send>,
}
impl<A: Authorization + 'static> server::Handler<HttpStream> for Router<A> {
fn on_request(&mut self, req: server::Request) -> Next {
fn on_request(&mut self, req: server::Request<HttpStream>) -> Next {
// Check authorization
let auth = self.authorization.is_authorized(&req);
@@ -124,7 +124,7 @@ impl<A: Authorization> Router<A> {
}
}
fn extract_url(req: &server::Request) -> Option<Url> {
fn extract_url(req: &server::Request<HttpStream>) -> Option<Url> {
match *req.uri() {
uri::RequestUri::AbsoluteUri(ref url) => {
match Url::from_generic_url(url.clone()) {

View File

@@ -33,7 +33,7 @@ impl Redirection {
}
impl server::Handler<HttpStream> for Redirection {
fn on_request(&mut self, _request: server::Request) -> Next {
fn on_request(&mut self, _request: server::Request<HttpStream>) -> Next {
Next::write()
}

View File

@@ -2,24 +2,28 @@ FROM centos:latest
WORKDIR /build
# install tools and dependencies
RUN yum -y update&& \
yum install -y git make gcc-c++ gcc file
yum install -y git make gcc-c++ gcc file binutils
# install rustup
RUN curl -sSf https://static.rust-lang.org/rustup.sh -o rustup.sh &&\
ls&&\
sh rustup.sh -s -- --disable-sudo
# show backtraces
ENV RUST_BACKTRACE 1
# set compiler
ENV CXX g++
ENV CC gcc
# show tools
RUN rustc -vV && \
cargo -V && \
gcc -v &&\
g++ -v
# git clone parity
# build parity
RUN git clone https://github.com/ethcore/parity && \
cd parity&&\
git checkout beta && \
git pull && \
ls -a&&\
cargo build --release --verbose && \
ls /build/parity/target/release/parity && \
file /build/parity/target/release/parity && \
strip /build/parity/target/release/parity
RUN file /build/parity/target/release/parity

View File

@@ -0,0 +1,49 @@
FROM ubuntu:14.04
WORKDIR /build
# install tools and dependencies
RUN apt-get -y update && \
apt-get install -y --force-yes --no-install-recommends \
curl git make g++ gcc-aarch64-linux-gnu g++-aarch64-linux-gnu \
libc6-arm64-cross libc6-dev-arm64-cross wget file ca-certificates \
binutils-aarch64-linux-gnu \
&& \
apt-get clean
# install rustup
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
# rustup directory
ENV PATH /root/.cargo/bin:$PATH
ENV RUST_TARGETS="aarch64-unknown-linux-gnu"
# multirust add arm--linux-gnuabhf toolchain
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
# build parity
RUN git clone https://github.com/ethcore/parity && \
cd parity && \
git checkout beta && \
git pull && \
mkdir -p .cargo && \
echo '[target.aarch64-unknown-linux-gnu]\n\
linker = "aarch64-linux-gnu-gcc"\n'\
>>.cargo/config && \
cat .cargo/config && \
cargo build --target aarch64-unknown-linux-gnu --release --verbose && \
ls /build/parity/target/aarch64-unknown-linux-gnu/release/parity && \
/usr/bin/aarch64-linux-gnu-strip /build/parity/target/aarch64-unknown-linux-gnu/release/parity
RUN file /build/parity/target/aarch64-unknown-linux-gnu/release/parity

View File

@@ -2,11 +2,11 @@ FROM ubuntu:14.04
WORKDIR /build
# install tools and dependencies
RUN apt-get -y update && \
apt-get install -y --force-yes --no-install-recommends \
curl git make g++ gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf \
libc6-dev-armhf-cross wget file ca-certificates \
binutils-arm-linux-gnueabihf \
&& \
apt-get install -y --force-yes --no-install-recommends \
curl git make g++ gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf \
libc6-dev-armhf-cross wget file ca-certificates \
binutils-arm-linux-gnueabihf \
&& \
apt-get clean
# install rustup
@@ -18,33 +18,32 @@ ENV PATH /root/.cargo/bin:$PATH
ENV RUST_TARGETS="arm-unknown-linux-gnueabihf"
# multirust add arm--linux-gnuabhf toolchain
RUN rustup target add stable arm-unknown-linux-gnueabihf
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
# build parity
RUN git clone https://github.com/ethcore/parity && \
cd parity && \
git checkout master && \
wget https://github.com/nix-rust/nix/archive/v0.5.0.tar.gz && \
tar -xf v0.5.0.tar.gz && \
rm -rf v0.5.0.tar.gz && \
wget https://github.com/thkaw/mio/archive/v0.5.x.tar.gz && \
tar -xf v0.5.x.tar.gz && \
rm -rf v0.5.x.tar.gz && \
mkdir -p .cargo && \
echo 'paths = ["nix-0.5.0","mio-0.5.x"]\n\
[target.arm-unknown-linux-gnueabihf]\n\
linker = "arm-linux-gnueabihf-gcc"\n'\
>>.cargo/config && \
cat .cargo/config && \
rustc -vV && \
cargo -V && \
cargo build --target arm-unknown-linux-gnueabihf --release --verbose && \
ls /build/parity/target/arm-unknown-linux-gnueabihf/release/parity && \
file /build/parity/target/arm-unknown-linux-gnueabihf/release/parity && \
/usr/bin/arm-linux-gnueabihf-strip /build/parity/target/arm-unknown-linux-gnueabihf/release/parity
RUN file /build/parity/target/arm-unknown-linux-gnueabihf/release/parity
cd parity && \
git checkout beta && \
git pull && \
mkdir -p .cargo && \
echo '[target.armv7-unknown-linux-gnueabihf]\n\
linker = "arm-linux-gnueabihf-gcc"\n'\
>>.cargo/config && \
cat .cargo/config && \
cargo build --target armv7-unknown-linux-gnueabihf --release --verbose && \
ls /build/parity/target/armv7-unknown-linux-gnueabihf/release/parity && \
/usr/bin/arm-linux-gnueabihf-strip /build/parity/target/armv7-unknown-linux-gnueabihf/release/parity
RUN file /build/parity/target/armv7-unknown-linux-gnueabihf/release/parity

View File

@@ -1,31 +1,33 @@
FROM ubuntu:14.04
WORKDIR /build
# install tools and dependencies
RUN apt-get update && \
apt-get install -y \
# make
build-essential \
# add-apt-repository
software-properties-common \
curl \
wget \
git \
g++ \
# evmjit dependencies
zlib1g-dev \
libedit-dev
apt-get install -y \
# make
build-essential \
# add-apt-repository
software-properties-common \
curl \
wget \
git \
g++ \
binutils \
file \
# evmjit dependencies
zlib1g-dev \
libedit-dev
# cmake, llvm and rocksdb ppas. then update ppas
# cmake and llvm ppas. then update ppas
RUN add-apt-repository -y "ppa:george-edison55/cmake-3.x" && \
add-apt-repository "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main" && \
apt-get update && \
apt-get install -y --force-yes cmake llvm-3.7-dev
add-apt-repository "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main" && \
apt-get update && \
apt-get install -y --force-yes cmake llvm-3.7-dev
# install evmjit
RUN git clone https://github.com/debris/evmjit && \
cd evmjit && \
mkdir build && cd build && \
cmake .. && make && make install && cd
cd evmjit && \
mkdir build && cd build && \
cmake .. && make && make install && cd
# install rustup
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
@@ -36,7 +38,18 @@ ENV PATH /root/.cargo/bin:$PATH
# show backtraces
ENV RUST_BACKTRACE 1
# show tools
RUN rustc -vV && \
cargo -V && \
gcc -v &&\
g++ -v
# build parity
RUN git clone https://github.com/ethcore/parity && \
cd parity && \
cargo build --release --features ethcore/jit
cd parity && \
git checkout beta && \
git pull && \
cargo build --release --features ethcore/jit --verbose && \
ls /build/parity/target/release/parity && \
strip /build/parity/target/release/parity
RUN file /build/parity/target/release/parity

View File

@@ -1,12 +1,13 @@
FROM ubuntu:14.04
WORKDIR /build
# install tools and dependencies
RUN apt-get update && \
apt-get install -y \
g++ \
curl \
git \
make
apt-get install -y \
g++ \
curl \
git \
file \
binutils
# install rustup
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
@@ -17,7 +18,18 @@ ENV PATH /root/.cargo/bin:$PATH
# show backtraces
ENV RUST_BACKTRACE 1
# show tools
RUN rustc -vV && \
cargo -V && \
gcc -v &&\
g++ -v
# build parity
RUN git clone https://github.com/ethcore/parity && \
cd parity && \
cargo build --release
cd parity && \
git checkout beta && \
git pull && \
cargo build --release --verbose && \
ls /build/parity/target/release/parity && \
strip /build/parity/target/release/parity
RUN file /build/parity/target/release/parity

View File

@@ -32,6 +32,10 @@ bloomchain = "0.1"
rayon = "0.3.1"
ethstore = { path = "../ethstore" }
[dependencies.hyper]
git = "https://github.com/ethcore/hyper"
default-features = false
[features]
jit = ["evmjit"]
evm-debug = []

View File

@@ -0,0 +1,162 @@
{
"name": "DAO hard-fork consensus test",
"engine": {
"Ethash": {
"params": {
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0x5",
"daoHardforkTransition": "0x8",
"daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754",
"daoHardforkAccounts": [
"0xd4fe7bc31cedb7bfb8a345f31e668033056b2728",
"0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425",
"0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f",
"0xecd135fa4f61a655311e86238c92adcd779555d2",
"0x1975bd06d486162d5dc297798dfc41edd5d160a7",
"0xa3acf3a1e16b1d7c315e23510fdd7847b48234f6",
"0x319f70bab6845585f412ec7724b744fec6095c85",
"0x06706dd3f2c9abf0a21ddcc6941d9b86f0596936",
"0x5c8536898fbb74fc7445814902fd08422eac56d0",
"0x6966ab0d485353095148a2155858910e0965b6f9",
"0x779543a0491a837ca36ce8c635d6154e3c4911a6",
"0x2a5ed960395e2a49b1c758cef4aa15213cfd874c",
"0x5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5",
"0x9c50426be05db97f5d64fc54bf89eff947f0a321",
"0x200450f06520bdd6c527622a273333384d870efb",
"0xbe8539bfe837b67d1282b2b1d61c3f723966f049",
"0x6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb",
"0xf1385fb24aad0cd7432824085e42aff90886fef5",
"0xd1ac8b1ef1b69ff51d1d401a476e7e612414f091",
"0x8163e7fb499e90f8544ea62bbf80d21cd26d9efd",
"0x51e0ddd9998364a2eb38588679f0d2c42653e4a6",
"0x627a0a960c079c21c34f7612d5d230e01b4ad4c7",
"0xf0b1aa0eb660754448a7937c022e30aa692fe0c5",
"0x24c4d950dfd4dd1902bbed3508144a54542bba94",
"0x9f27daea7aca0aa0446220b98d028715e3bc803d",
"0xa5dc5acd6a7968a4554d89d65e59b7fd3bff0f90",
"0xd9aef3a1e38a39c16b31d1ace71bca8ef58d315b",
"0x63ed5a272de2f6d968408b4acb9024f4cc208ebf",
"0x6f6704e5a10332af6672e50b3d9754dc460dfa4d",
"0x77ca7b50b6cd7e2f3fa008e24ab793fd56cb15f6",
"0x492ea3bb0f3315521c31f273e565b868fc090f17",
"0x0ff30d6de14a8224aa97b78aea5388d1c51c1f00",
"0x9ea779f907f0b315b364b0cfc39a0fde5b02a416",
"0xceaeb481747ca6c540a000c1f3641f8cef161fa7",
"0xcc34673c6c40e791051898567a1222daf90be287",
"0x579a80d909f346fbfb1189493f521d7f48d52238",
"0xe308bd1ac5fda103967359b2712dd89deffb7973",
"0x4cb31628079fb14e4bc3cd5e30c2f7489b00960c",
"0xac1ecab32727358dba8962a0f3b261731aad9723",
"0x4fd6ace747f06ece9c49699c7cabc62d02211f75",
"0x440c59b325d2997a134c2c7c60a8c61611212bad",
"0x4486a3d68fac6967006d7a517b889fd3f98c102b",
"0x9c15b54878ba618f494b38f0ae7443db6af648ba",
"0x27b137a85656544b1ccb5a0f2e561a5703c6a68f",
"0x21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241",
"0x23b75c2f6791eef49c69684db4c6c1f93bf49a50",
"0x1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b",
"0xb9637156d330c0d605a791f1c31ba5890582fe1c",
"0x6131c42fa982e56929107413a9d526fd99405560",
"0x1591fc0f688c81fbeb17f5426a162a7024d430c2",
"0x542a9515200d14b68e934e9830d91645a980dd7a",
"0xc4bbd073882dd2add2424cf47d35213405b01324",
"0x782495b7b3355efb2833d56ecb34dc22ad7dfcc4",
"0x58b95c9a9d5d26825e70a82b6adb139d3fd829eb",
"0x3ba4d81db016dc2890c81f3acec2454bff5aada5",
"0xb52042c8ca3f8aa246fa79c3feaa3d959347c0ab",
"0xe4ae1efdfc53b73893af49113d8694a057b9c0d1",
"0x3c02a7bc0391e86d91b7d144e61c2c01a25a79c5",
"0x0737a6b837f97f46ebade41b9bc3e1c509c85c53",
"0x97f43a37f595ab5dd318fb46e7a155eae057317a",
"0x52c5317c848ba20c7504cb2c8052abd1fde29d03",
"0x4863226780fe7c0356454236d3b1c8792785748d",
"0x5d2b2e6fcbe3b11d26b525e085ff818dae332479",
"0x5f9f3392e9f62f63b8eac0beb55541fc8627f42c",
"0x057b56736d32b86616a10f619859c6cd6f59092a",
"0x9aa008f65de0b923a2a4f02012ad034a5e2e2192",
"0x304a554a310c7e546dfe434669c62820b7d83490",
"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79",
"0x4deb0033bb26bc534b197e61d19e0733e5679784",
"0x07f5c1e1bc2c93e0402f23341973a0e043f7bf8a",
"0x35a051a0010aba705c9008d7a7eff6fb88f6ea7b",
"0x4fa802324e929786dbda3b8820dc7834e9134a2a",
"0x9da397b9e80755301a3b32173283a91c0ef6c87e",
"0x8d9edb3054ce5c5774a420ac37ebae0ac02343c6",
"0x0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9",
"0x5dc28b15dffed94048d73806ce4b7a4612a1d48f",
"0xbcf899e6c7d9d5a215ab1e3444c86806fa854c76",
"0x12e626b0eebfe86a56d633b9864e389b45dcb260",
"0xa2f1ccba9395d7fcb155bba8bc92db9bafaeade7",
"0xec8e57756626fdc07c63ad2eafbd28d08e7b0ca5",
"0xd164b088bd9108b60d0ca3751da4bceb207b0782",
"0x6231b6d0d5e77fe001c2a460bd9584fee60d409b",
"0x1cba23d343a983e9b5cfd19496b9a9701ada385f",
"0xa82f360a8d3455c5c41366975bde739c37bfeb8a",
"0x9fcd2deaff372a39cc679d5c5e4de7bafb0b1339",
"0x005f5cee7a43331d5a3d3eec71305925a62f34b6",
"0x0e0da70933f4c7849fc0d203f5d1d43b9ae4532d",
"0xd131637d5275fd1a68a3200f4ad25c71a2a9522e",
"0xbc07118b9ac290e4622f5e77a0853539789effbe",
"0x47e7aa56d6bdf3f36be34619660de61275420af8",
"0xacd87e28b0c9d1254e868b81cba4cc20d9a32225",
"0xadf80daec7ba8dcf15392f1ac611fff65d94f880",
"0x5524c55fb03cf21f549444ccbecb664d0acad706",
"0x40b803a9abce16f50f36a77ba41180eb90023925",
"0xfe24cdd8648121a43a7c86d289be4dd2951ed49f",
"0x17802f43a0137c506ba92291391a8a8f207f487d",
"0x253488078a4edf4d6f42f113d1e62836a942cf1a",
"0x86af3e9626fce1957c82e88cbf04ddf3a2ed7915",
"0xb136707642a4ea12fb4bae820f03d2562ebff487",
"0xdbe9b615a3ae8709af8b93336ce9b477e4ac0940",
"0xf14c14075d6c4ed84b86798af0956deef67365b5",
"0xca544e5c4687d109611d0f8f928b53a25af72448",
"0xaeeb8ff27288bdabc0fa5ebb731b6f409507516c",
"0xcbb9d3703e651b0d496cdefb8b92c25aeb2171f7",
"0x6d87578288b6cb5549d5076a207456a1f6a63dc0",
"0xb2c6f0dfbb716ac562e2d85d6cb2f8d5ee87603e",
"0xaccc230e8a6e5be9160b8cdf2864dd2a001c28b6",
"0x2b3455ec7fedf16e646268bf88846bd7a2319bb2",
"0x4613f3bca5c44ea06337a9e439fbc6d42e501d0a",
"0xd343b217de44030afaa275f54d31a9317c7f441e",
"0x84ef4b2357079cd7a7c69fd7a37cd0609a679106",
"0xda2fef9e4a3230988ff17df2165440f37e8b1708",
"0xf4c64518ea10f995918a454158c6b61407ea345c",
"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97",
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
]
}
}
},
"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": { "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 } } } }
}
}

View File

@@ -9,8 +9,7 @@
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0x118c30",
"daoRescueSoftFork": true
"frontierCompatibilityModeLimit": "0x118c30"
}
}
},
@@ -18,7 +17,9 @@
"accountStartNonce": "0x00",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x1"
"networkID" : "0x1",
"forkBlock": "0x1d4c00",
"forkCanonHash": "0x94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f"
},
"genesis": {
"seal": {

View File

@@ -10,7 +10,126 @@
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0x118c30",
"daoRescueSoftFork": false
"daoHardforkTransition": "0x1d4c00",
"daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754",
"daoHardforkAccounts": [
"0xd4fe7bc31cedb7bfb8a345f31e668033056b2728",
"0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425",
"0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f",
"0xecd135fa4f61a655311e86238c92adcd779555d2",
"0x1975bd06d486162d5dc297798dfc41edd5d160a7",
"0xa3acf3a1e16b1d7c315e23510fdd7847b48234f6",
"0x319f70bab6845585f412ec7724b744fec6095c85",
"0x06706dd3f2c9abf0a21ddcc6941d9b86f0596936",
"0x5c8536898fbb74fc7445814902fd08422eac56d0",
"0x6966ab0d485353095148a2155858910e0965b6f9",
"0x779543a0491a837ca36ce8c635d6154e3c4911a6",
"0x2a5ed960395e2a49b1c758cef4aa15213cfd874c",
"0x5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5",
"0x9c50426be05db97f5d64fc54bf89eff947f0a321",
"0x200450f06520bdd6c527622a273333384d870efb",
"0xbe8539bfe837b67d1282b2b1d61c3f723966f049",
"0x6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb",
"0xf1385fb24aad0cd7432824085e42aff90886fef5",
"0xd1ac8b1ef1b69ff51d1d401a476e7e612414f091",
"0x8163e7fb499e90f8544ea62bbf80d21cd26d9efd",
"0x51e0ddd9998364a2eb38588679f0d2c42653e4a6",
"0x627a0a960c079c21c34f7612d5d230e01b4ad4c7",
"0xf0b1aa0eb660754448a7937c022e30aa692fe0c5",
"0x24c4d950dfd4dd1902bbed3508144a54542bba94",
"0x9f27daea7aca0aa0446220b98d028715e3bc803d",
"0xa5dc5acd6a7968a4554d89d65e59b7fd3bff0f90",
"0xd9aef3a1e38a39c16b31d1ace71bca8ef58d315b",
"0x63ed5a272de2f6d968408b4acb9024f4cc208ebf",
"0x6f6704e5a10332af6672e50b3d9754dc460dfa4d",
"0x77ca7b50b6cd7e2f3fa008e24ab793fd56cb15f6",
"0x492ea3bb0f3315521c31f273e565b868fc090f17",
"0x0ff30d6de14a8224aa97b78aea5388d1c51c1f00",
"0x9ea779f907f0b315b364b0cfc39a0fde5b02a416",
"0xceaeb481747ca6c540a000c1f3641f8cef161fa7",
"0xcc34673c6c40e791051898567a1222daf90be287",
"0x579a80d909f346fbfb1189493f521d7f48d52238",
"0xe308bd1ac5fda103967359b2712dd89deffb7973",
"0x4cb31628079fb14e4bc3cd5e30c2f7489b00960c",
"0xac1ecab32727358dba8962a0f3b261731aad9723",
"0x4fd6ace747f06ece9c49699c7cabc62d02211f75",
"0x440c59b325d2997a134c2c7c60a8c61611212bad",
"0x4486a3d68fac6967006d7a517b889fd3f98c102b",
"0x9c15b54878ba618f494b38f0ae7443db6af648ba",
"0x27b137a85656544b1ccb5a0f2e561a5703c6a68f",
"0x21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241",
"0x23b75c2f6791eef49c69684db4c6c1f93bf49a50",
"0x1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b",
"0xb9637156d330c0d605a791f1c31ba5890582fe1c",
"0x6131c42fa982e56929107413a9d526fd99405560",
"0x1591fc0f688c81fbeb17f5426a162a7024d430c2",
"0x542a9515200d14b68e934e9830d91645a980dd7a",
"0xc4bbd073882dd2add2424cf47d35213405b01324",
"0x782495b7b3355efb2833d56ecb34dc22ad7dfcc4",
"0x58b95c9a9d5d26825e70a82b6adb139d3fd829eb",
"0x3ba4d81db016dc2890c81f3acec2454bff5aada5",
"0xb52042c8ca3f8aa246fa79c3feaa3d959347c0ab",
"0xe4ae1efdfc53b73893af49113d8694a057b9c0d1",
"0x3c02a7bc0391e86d91b7d144e61c2c01a25a79c5",
"0x0737a6b837f97f46ebade41b9bc3e1c509c85c53",
"0x97f43a37f595ab5dd318fb46e7a155eae057317a",
"0x52c5317c848ba20c7504cb2c8052abd1fde29d03",
"0x4863226780fe7c0356454236d3b1c8792785748d",
"0x5d2b2e6fcbe3b11d26b525e085ff818dae332479",
"0x5f9f3392e9f62f63b8eac0beb55541fc8627f42c",
"0x057b56736d32b86616a10f619859c6cd6f59092a",
"0x9aa008f65de0b923a2a4f02012ad034a5e2e2192",
"0x304a554a310c7e546dfe434669c62820b7d83490",
"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79",
"0x4deb0033bb26bc534b197e61d19e0733e5679784",
"0x07f5c1e1bc2c93e0402f23341973a0e043f7bf8a",
"0x35a051a0010aba705c9008d7a7eff6fb88f6ea7b",
"0x4fa802324e929786dbda3b8820dc7834e9134a2a",
"0x9da397b9e80755301a3b32173283a91c0ef6c87e",
"0x8d9edb3054ce5c5774a420ac37ebae0ac02343c6",
"0x0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9",
"0x5dc28b15dffed94048d73806ce4b7a4612a1d48f",
"0xbcf899e6c7d9d5a215ab1e3444c86806fa854c76",
"0x12e626b0eebfe86a56d633b9864e389b45dcb260",
"0xa2f1ccba9395d7fcb155bba8bc92db9bafaeade7",
"0xec8e57756626fdc07c63ad2eafbd28d08e7b0ca5",
"0xd164b088bd9108b60d0ca3751da4bceb207b0782",
"0x6231b6d0d5e77fe001c2a460bd9584fee60d409b",
"0x1cba23d343a983e9b5cfd19496b9a9701ada385f",
"0xa82f360a8d3455c5c41366975bde739c37bfeb8a",
"0x9fcd2deaff372a39cc679d5c5e4de7bafb0b1339",
"0x005f5cee7a43331d5a3d3eec71305925a62f34b6",
"0x0e0da70933f4c7849fc0d203f5d1d43b9ae4532d",
"0xd131637d5275fd1a68a3200f4ad25c71a2a9522e",
"0xbc07118b9ac290e4622f5e77a0853539789effbe",
"0x47e7aa56d6bdf3f36be34619660de61275420af8",
"0xacd87e28b0c9d1254e868b81cba4cc20d9a32225",
"0xadf80daec7ba8dcf15392f1ac611fff65d94f880",
"0x5524c55fb03cf21f549444ccbecb664d0acad706",
"0x40b803a9abce16f50f36a77ba41180eb90023925",
"0xfe24cdd8648121a43a7c86d289be4dd2951ed49f",
"0x17802f43a0137c506ba92291391a8a8f207f487d",
"0x253488078a4edf4d6f42f113d1e62836a942cf1a",
"0x86af3e9626fce1957c82e88cbf04ddf3a2ed7915",
"0xb136707642a4ea12fb4bae820f03d2562ebff487",
"0xdbe9b615a3ae8709af8b93336ce9b477e4ac0940",
"0xf14c14075d6c4ed84b86798af0956deef67365b5",
"0xca544e5c4687d109611d0f8f928b53a25af72448",
"0xaeeb8ff27288bdabc0fa5ebb731b6f409507516c",
"0xcbb9d3703e651b0d496cdefb8b92c25aeb2171f7",
"0x6d87578288b6cb5549d5076a207456a1f6a63dc0",
"0xb2c6f0dfbb716ac562e2d85d6cb2f8d5ee87603e",
"0xaccc230e8a6e5be9160b8cdf2864dd2a001c28b6",
"0x2b3455ec7fedf16e646268bf88846bd7a2319bb2",
"0x4613f3bca5c44ea06337a9e439fbc6d42e501d0a",
"0xd343b217de44030afaa275f54d31a9317c7f441e",
"0x84ef4b2357079cd7a7c69fd7a37cd0609a679106",
"0xda2fef9e4a3230988ff17df2165440f37e8b1708",
"0xf4c64518ea10f995918a454158c6b61407ea345c",
"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97",
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
]
}
}
},
@@ -18,7 +137,9 @@
"accountStartNonce": "0x00",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x1"
"networkID" : "0x1",
"forkBlock": "0x1d4c00",
"forkCanonHash": "0x4985f5ca3d2afbec36529aa96f74de3cc10a2a4a6c44f2157a57d2c6059a11bb"
},
"genesis": {
"seal": {

View File

@@ -10,7 +10,126 @@
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0x118c30",
"daoRescueSoftFork": false
"daoHardforkTransition": "0x1d4c00",
"daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754",
"daoHardforkAccounts": [
"0xd4fe7bc31cedb7bfb8a345f31e668033056b2728",
"0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425",
"0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f",
"0xecd135fa4f61a655311e86238c92adcd779555d2",
"0x1975bd06d486162d5dc297798dfc41edd5d160a7",
"0xa3acf3a1e16b1d7c315e23510fdd7847b48234f6",
"0x319f70bab6845585f412ec7724b744fec6095c85",
"0x06706dd3f2c9abf0a21ddcc6941d9b86f0596936",
"0x5c8536898fbb74fc7445814902fd08422eac56d0",
"0x6966ab0d485353095148a2155858910e0965b6f9",
"0x779543a0491a837ca36ce8c635d6154e3c4911a6",
"0x2a5ed960395e2a49b1c758cef4aa15213cfd874c",
"0x5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5",
"0x9c50426be05db97f5d64fc54bf89eff947f0a321",
"0x200450f06520bdd6c527622a273333384d870efb",
"0xbe8539bfe837b67d1282b2b1d61c3f723966f049",
"0x6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb",
"0xf1385fb24aad0cd7432824085e42aff90886fef5",
"0xd1ac8b1ef1b69ff51d1d401a476e7e612414f091",
"0x8163e7fb499e90f8544ea62bbf80d21cd26d9efd",
"0x51e0ddd9998364a2eb38588679f0d2c42653e4a6",
"0x627a0a960c079c21c34f7612d5d230e01b4ad4c7",
"0xf0b1aa0eb660754448a7937c022e30aa692fe0c5",
"0x24c4d950dfd4dd1902bbed3508144a54542bba94",
"0x9f27daea7aca0aa0446220b98d028715e3bc803d",
"0xa5dc5acd6a7968a4554d89d65e59b7fd3bff0f90",
"0xd9aef3a1e38a39c16b31d1ace71bca8ef58d315b",
"0x63ed5a272de2f6d968408b4acb9024f4cc208ebf",
"0x6f6704e5a10332af6672e50b3d9754dc460dfa4d",
"0x77ca7b50b6cd7e2f3fa008e24ab793fd56cb15f6",
"0x492ea3bb0f3315521c31f273e565b868fc090f17",
"0x0ff30d6de14a8224aa97b78aea5388d1c51c1f00",
"0x9ea779f907f0b315b364b0cfc39a0fde5b02a416",
"0xceaeb481747ca6c540a000c1f3641f8cef161fa7",
"0xcc34673c6c40e791051898567a1222daf90be287",
"0x579a80d909f346fbfb1189493f521d7f48d52238",
"0xe308bd1ac5fda103967359b2712dd89deffb7973",
"0x4cb31628079fb14e4bc3cd5e30c2f7489b00960c",
"0xac1ecab32727358dba8962a0f3b261731aad9723",
"0x4fd6ace747f06ece9c49699c7cabc62d02211f75",
"0x440c59b325d2997a134c2c7c60a8c61611212bad",
"0x4486a3d68fac6967006d7a517b889fd3f98c102b",
"0x9c15b54878ba618f494b38f0ae7443db6af648ba",
"0x27b137a85656544b1ccb5a0f2e561a5703c6a68f",
"0x21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241",
"0x23b75c2f6791eef49c69684db4c6c1f93bf49a50",
"0x1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b",
"0xb9637156d330c0d605a791f1c31ba5890582fe1c",
"0x6131c42fa982e56929107413a9d526fd99405560",
"0x1591fc0f688c81fbeb17f5426a162a7024d430c2",
"0x542a9515200d14b68e934e9830d91645a980dd7a",
"0xc4bbd073882dd2add2424cf47d35213405b01324",
"0x782495b7b3355efb2833d56ecb34dc22ad7dfcc4",
"0x58b95c9a9d5d26825e70a82b6adb139d3fd829eb",
"0x3ba4d81db016dc2890c81f3acec2454bff5aada5",
"0xb52042c8ca3f8aa246fa79c3feaa3d959347c0ab",
"0xe4ae1efdfc53b73893af49113d8694a057b9c0d1",
"0x3c02a7bc0391e86d91b7d144e61c2c01a25a79c5",
"0x0737a6b837f97f46ebade41b9bc3e1c509c85c53",
"0x97f43a37f595ab5dd318fb46e7a155eae057317a",
"0x52c5317c848ba20c7504cb2c8052abd1fde29d03",
"0x4863226780fe7c0356454236d3b1c8792785748d",
"0x5d2b2e6fcbe3b11d26b525e085ff818dae332479",
"0x5f9f3392e9f62f63b8eac0beb55541fc8627f42c",
"0x057b56736d32b86616a10f619859c6cd6f59092a",
"0x9aa008f65de0b923a2a4f02012ad034a5e2e2192",
"0x304a554a310c7e546dfe434669c62820b7d83490",
"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79",
"0x4deb0033bb26bc534b197e61d19e0733e5679784",
"0x07f5c1e1bc2c93e0402f23341973a0e043f7bf8a",
"0x35a051a0010aba705c9008d7a7eff6fb88f6ea7b",
"0x4fa802324e929786dbda3b8820dc7834e9134a2a",
"0x9da397b9e80755301a3b32173283a91c0ef6c87e",
"0x8d9edb3054ce5c5774a420ac37ebae0ac02343c6",
"0x0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9",
"0x5dc28b15dffed94048d73806ce4b7a4612a1d48f",
"0xbcf899e6c7d9d5a215ab1e3444c86806fa854c76",
"0x12e626b0eebfe86a56d633b9864e389b45dcb260",
"0xa2f1ccba9395d7fcb155bba8bc92db9bafaeade7",
"0xec8e57756626fdc07c63ad2eafbd28d08e7b0ca5",
"0xd164b088bd9108b60d0ca3751da4bceb207b0782",
"0x6231b6d0d5e77fe001c2a460bd9584fee60d409b",
"0x1cba23d343a983e9b5cfd19496b9a9701ada385f",
"0xa82f360a8d3455c5c41366975bde739c37bfeb8a",
"0x9fcd2deaff372a39cc679d5c5e4de7bafb0b1339",
"0x005f5cee7a43331d5a3d3eec71305925a62f34b6",
"0x0e0da70933f4c7849fc0d203f5d1d43b9ae4532d",
"0xd131637d5275fd1a68a3200f4ad25c71a2a9522e",
"0xbc07118b9ac290e4622f5e77a0853539789effbe",
"0x47e7aa56d6bdf3f36be34619660de61275420af8",
"0xacd87e28b0c9d1254e868b81cba4cc20d9a32225",
"0xadf80daec7ba8dcf15392f1ac611fff65d94f880",
"0x5524c55fb03cf21f549444ccbecb664d0acad706",
"0x40b803a9abce16f50f36a77ba41180eb90023925",
"0xfe24cdd8648121a43a7c86d289be4dd2951ed49f",
"0x17802f43a0137c506ba92291391a8a8f207f487d",
"0x253488078a4edf4d6f42f113d1e62836a942cf1a",
"0x86af3e9626fce1957c82e88cbf04ddf3a2ed7915",
"0xb136707642a4ea12fb4bae820f03d2562ebff487",
"0xdbe9b615a3ae8709af8b93336ce9b477e4ac0940",
"0xf14c14075d6c4ed84b86798af0956deef67365b5",
"0xca544e5c4687d109611d0f8f928b53a25af72448",
"0xaeeb8ff27288bdabc0fa5ebb731b6f409507516c",
"0xcbb9d3703e651b0d496cdefb8b92c25aeb2171f7",
"0x6d87578288b6cb5549d5076a207456a1f6a63dc0",
"0xb2c6f0dfbb716ac562e2d85d6cb2f8d5ee87603e",
"0xaccc230e8a6e5be9160b8cdf2864dd2a001c28b6",
"0x2b3455ec7fedf16e646268bf88846bd7a2319bb2",
"0x4613f3bca5c44ea06337a9e439fbc6d42e501d0a",
"0xd343b217de44030afaa275f54d31a9317c7f441e",
"0x84ef4b2357079cd7a7c69fd7a37cd0609a679106",
"0xda2fef9e4a3230988ff17df2165440f37e8b1708",
"0xf4c64518ea10f995918a454158c6b61407ea345c",
"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97",
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
]
}
}
},

View File

@@ -1,43 +0,0 @@
{
"name": "Frontier (Test)",
"engine": {
"Ethash": {
"params": {
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0x118c30",
"daoRescueSoftFork": true
}
}
},
"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": { "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 } } } }
}
}

View File

@@ -9,8 +9,7 @@
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0xffffffffffffffff",
"daoRescueSoftFork": false
"frontierCompatibilityModeLimit": "0xffffffffffffffff"
}
}
},

View File

@@ -9,8 +9,7 @@
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": 0,
"daoRescueSoftFork": false
"frontierCompatibilityModeLimit": "0x0"
}
}
},

View File

@@ -1,43 +0,0 @@
{
"name": "Homestead (Test)",
"engine": {
"Ethash": {
"params": {
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": 0,
"daoRescueSoftFork": true
}
}
},
"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

@@ -9,8 +9,7 @@
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar": "",
"frontierCompatibilityModeLimit": "0x789b0",
"daoRescueSoftFork": false
"frontierCompatibilityModeLimit": "0x789b0"
}
}
},

View File

@@ -8,9 +8,7 @@
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x08",
"blockReward": "0x14D1120D7B160000",
"registrar": "5e70c0bbcd5636e0f9f9316e9f8633feb64d4050",
"frontierCompatibilityModeLimit": "0xffffffffffffffff",
"daoRescueSoftFork": false
"registrar": "5e70c0bbcd5636e0f9f9316e9f8633feb64d4050"
}
}
},

View File

@@ -58,8 +58,8 @@ impl Account {
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: Some(pod.code.sha3()),
code_cache: pod.code
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()),
}
}
@@ -108,6 +108,12 @@ impl Account {
self.code_cache = code;
}
/// 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));
@@ -336,6 +342,21 @@ mod tests {
assert_eq!(a.code_hash().hex(), "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb");
}
#[test]
fn reset_code() {
let mut a = Account::new_contract(69.into(), 0.into());
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);
a.commit_code(&mut db);
assert_eq!(a.code_hash().hex(), "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb");
a.reset_code(vec![0x55]);
assert_eq!(a.code_hash(), SHA3_EMPTY);
a.commit_code(&mut db);
assert_eq!(a.code_hash().hex(), "37bf2238b11b68cdc8382cece82651b59d3c3988873b6e0f33d79694aa45f1be");
}
#[test]
fn rlpio() {
let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new());
@@ -348,7 +369,6 @@ mod tests {
#[test]
fn new_account() {
let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new());
assert_eq!(a.rlp().to_hex(), "f8448045a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
assert_eq!(a.balance(), &U256::from(69u8));
@@ -359,7 +379,6 @@ mod tests {
#[test]
fn create_account() {
let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new());
assert_eq!(a.rlp().to_hex(), "f8448045a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
}

View File

@@ -17,6 +17,7 @@
//! Evm input params.
use common::*;
use ethjson;
use types::executed::CallType;
/// Transaction value
#[derive(Clone, Debug)]
@@ -58,7 +59,10 @@ pub struct ActionParams {
/// Code being executed.
pub code: Option<Bytes>,
/// Input data.
pub data: Option<Bytes>
pub data: Option<Bytes>,
/// Type of call
pub call_type: CallType,
}
impl Default for ActionParams {
@@ -73,16 +77,18 @@ impl Default for ActionParams {
gas_price: U256::zero(),
value: ActionValue::Transfer(U256::zero()),
code: None,
data: None
data: None,
call_type: CallType::None,
}
}
}
impl From<ethjson::vm::Transaction> for ActionParams {
fn from(t: ethjson::vm::Transaction) -> Self {
let address: Address = t.address.into();
ActionParams {
code_address: Address::new(),
address: t.address.into(),
address: address,
sender: t.sender.into(),
origin: t.origin.into(),
code: Some(t.code.into()),
@@ -90,6 +96,7 @@ impl From<ethjson::vm::Transaction> for ActionParams {
gas: t.gas.into(),
gas_price: t.gas_price.into(),
value: ActionValue::Transfer(t.value.into()),
call_type: match address.is_zero() { true => CallType::None, false => CallType::Call }, // TODO @debris is this correct?
}
}
}

View File

@@ -80,7 +80,7 @@ impl Engine for BasicAuthority {
Schedule::new_homestead()
}
fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256) {
fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) {
header.difficulty = parent.difficulty;
header.gas_limit = {
let gas_limit = parent.gas_limit;
@@ -203,7 +203,6 @@ mod tests {
timestamp: 0,
difficulty: 0.into(),
last_hashes: vec![],
dao_rescue_block_gas_limit: None,
gas_used: 0.into(),
gas_limit: 0.into(),
});
@@ -254,7 +253,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, addr, 3141562.into(), vec![]).unwrap();
let b = OpenBlock::new(engine.deref(), &vm_factory, 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());

View File

@@ -22,7 +22,7 @@ use common::*;
use engine::*;
use state::*;
use verification::PreverifiedBlock;
use trace::Trace;
use trace::FlatTrace;
use evm::Factory as EvmFactory;
/// A block, encoded as it is on the block chain.
@@ -41,8 +41,18 @@ impl Block {
pub fn is_good(b: &[u8]) -> bool {
UntrustedRlp::new(b).as_val::<Block>().is_ok()
}
/// Get the RLP-encoding of the block without the seal.
pub fn rlp_bytes(&self, seal: Seal) -> Bytes {
let mut block_rlp = RlpStream::new_list(3);
self.header.stream_rlp(&mut block_rlp, seal);
block_rlp.append(&self.transactions);
block_rlp.append(&self.uncles);
block_rlp.out()
}
}
impl Decodable for Block {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
if decoder.as_raw().len() != try!(decoder.as_rlp().payload_info()).total() {
@@ -68,7 +78,7 @@ pub struct ExecutedBlock {
receipts: Vec<Receipt>,
transactions_set: HashSet<H256>,
state: State,
traces: Option<Vec<Trace>>,
traces: Option<Vec<Vec<FlatTrace>>>,
}
/// A set of references to `ExecutedBlock` fields that are publicly accessible.
@@ -84,7 +94,7 @@ pub struct BlockRefMut<'a> {
/// State.
pub state: &'a mut State,
/// Traces.
pub traces: &'a Option<Vec<Trace>>,
pub traces: &'a Option<Vec<Vec<FlatTrace>>>,
}
/// A set of immutable references to `ExecutedBlock` fields that are publicly accessible.
@@ -100,7 +110,7 @@ pub struct BlockRef<'a> {
/// State.
pub state: &'a State,
/// Traces.
pub traces: &'a Option<Vec<Trace>>,
pub traces: &'a Option<Vec<Vec<FlatTrace>>>,
}
impl ExecutedBlock {
@@ -142,9 +152,12 @@ impl ExecutedBlock {
/// Trait for a object that is a `ExecutedBlock`.
pub trait IsBlock {
/// Get the block associated with this object.
/// Get the `ExecutedBlock` associated with this object.
fn block(&self) -> &ExecutedBlock;
/// Get the base `Block` object associated with this.
fn base(&self) -> &Block { &self.block().base }
/// Get the header associated with this object's block.
fn header(&self) -> &Header { &self.block().base.header }
@@ -158,12 +171,18 @@ pub trait IsBlock {
fn receipts(&self) -> &Vec<Receipt> { &self.block().receipts }
/// Get all information concerning transaction tracing in this block.
fn traces(&self) -> &Option<Vec<Trace>> { &self.block().traces }
fn traces(&self) -> &Option<Vec<Vec<FlatTrace>>> { &self.block().traces }
/// Get all uncles in this block.
fn uncles(&self) -> &Vec<Header> { &self.block().base.uncles }
}
/// 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>;
}
impl IsBlock for ExecutedBlock {
fn block(&self) -> &ExecutedBlock { self }
}
@@ -177,7 +196,6 @@ pub struct OpenBlock<'x> {
engine: &'x Engine,
vm_factory: &'x EvmFactory,
last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>,
}
/// Just like `OpenBlock`, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields,
@@ -189,7 +207,6 @@ pub struct ClosedBlock {
block: ExecutedBlock,
uncle_bytes: Bytes,
last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>,
unclosed_state: State,
}
@@ -220,9 +237,8 @@ impl<'x> OpenBlock<'x> {
db: Box<JournalDB>,
parent: &Header,
last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>,
author: Address,
gas_floor_target: U256,
gas_range_target: (U256, U256),
extra_data: Bytes,
) -> Result<Self, Error> {
let state = try!(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce()));
@@ -231,7 +247,6 @@ impl<'x> OpenBlock<'x> {
engine: engine,
vm_factory: vm_factory,
last_hashes: last_hashes,
dao_rescue_block_gas_limit: dao_rescue_block_gas_limit,
};
r.block.base.header.parent_hash = parent.hash();
@@ -241,7 +256,7 @@ impl<'x> OpenBlock<'x> {
r.block.base.header.extra_data = extra_data;
r.block.base.header.note_dirty();
engine.populate_from_parent(&mut r.block.base.header, parent, gas_floor_target);
engine.populate_from_parent(&mut r.block.base.header, parent, gas_range_target.0, gas_range_target.1);
engine.on_new_block(&mut r.block);
Ok(r)
}
@@ -288,7 +303,6 @@ impl<'x> OpenBlock<'x> {
/// Get the environment info concerning this block.
pub fn env_info(&self) -> EnvInfo {
// TODO: memoise.
const SOFT_FORK_BLOCK: u64 = 1775000;
EnvInfo {
number: self.block.base.header.number,
author: self.block.base.header.author.clone(),
@@ -297,7 +311,6 @@ impl<'x> OpenBlock<'x> {
last_hashes: self.last_hashes.clone(), // TODO: should be a reference.
gas_used: self.block.receipts.last().map_or(U256::zero(), |r| r.gas_used),
gas_limit: self.block.base.header.gas_limit.clone(),
dao_rescue_block_gas_limit: if self.block.base.header.number == SOFT_FORK_BLOCK { Some(self.block.base.header.gas_limit) } else { self.dao_rescue_block_gas_limit },
}
}
@@ -316,7 +329,7 @@ impl<'x> OpenBlock<'x> {
self.block.transactions_set.insert(h.unwrap_or_else(||t.hash()));
self.block.base.transactions.push(t);
let t = outcome.trace;
self.block.traces.as_mut().map(|traces| traces.push(t.expect("self.block.traces.is_some(): so we must be tracing: qed")));
self.block.traces.as_mut().map(|traces| traces.push(t));
self.block.receipts.push(outcome.receipt);
Ok(&self.block.receipts.last().unwrap())
}
@@ -344,7 +357,6 @@ impl<'x> OpenBlock<'x> {
block: s.block,
uncle_bytes: uncle_bytes,
last_hashes: s.last_hashes,
dao_rescue_block_gas_limit: s.dao_rescue_block_gas_limit,
unclosed_state: unclosed_state,
}
}
@@ -404,7 +416,6 @@ impl ClosedBlock {
engine: engine,
vm_factory: vm_factory,
last_hashes: self.last_hashes,
dao_rescue_block_gas_limit: self.dao_rescue_block_gas_limit,
}
}
}
@@ -436,9 +447,11 @@ impl LockedBlock {
_ => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }),
}
}
}
impl Drain for LockedBlock {
/// Drop this object and return the underlieing database.
pub fn drain(self) -> Box<JournalDB> { self.block.state.drop().1 }
fn drain(self) -> Box<JournalDB> { self.block.state.drop().1 }
}
impl SealedBlock {
@@ -450,9 +463,11 @@ impl SealedBlock {
block_rlp.append_raw(&self.uncle_bytes, 1);
block_rlp.out()
}
}
impl Drain for SealedBlock {
/// Drop this object and return the underlieing database.
pub fn drain(self) -> Box<JournalDB> { self.block.state.drop().1 }
fn drain(self) -> Box<JournalDB> { self.block.state.drop().1 }
}
impl IsBlock for SealedBlock {
@@ -470,7 +485,6 @@ pub fn enact(
db: Box<JournalDB>,
parent: &Header,
last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>,
vm_factory: &EvmFactory
) -> Result<LockedBlock, Error> {
{
@@ -480,10 +494,12 @@ pub fn enact(
}
}
let mut b = try!(OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, header.author().clone(), 3141562.into(), header.extra_data().clone()));
let mut b = try!(OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, Address::new(), (3141562.into(), 31415620.into()), vec![]));
b.set_difficulty(*header.difficulty());
b.set_gas_limit(*header.gas_limit());
b.set_timestamp(header.timestamp());
b.set_author(header.author().clone());
b.set_extra_data(header.extra_data().clone()).unwrap_or_else(|e| warn!("Couldn't set extradata: {}. Ignoring.", e));
for t in transactions { try!(b.push_transaction(t.clone(), None)); }
for u in uncles { try!(b.push_uncle(u.clone())); }
Ok(b.close_and_lock())
@@ -498,12 +514,11 @@ pub fn enact_bytes(
db: Box<JournalDB>,
parent: &Header,
last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>,
vm_factory: &EvmFactory
) -> Result<LockedBlock, Error> {
let block = BlockView::new(block_bytes);
let header = block.header();
enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory)
enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes, vm_factory)
}
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
@@ -515,11 +530,10 @@ pub fn enact_verified(
db: Box<JournalDB>,
parent: &Header,
last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>,
vm_factory: &EvmFactory
) -> Result<LockedBlock, Error> {
let view = BlockView::new(&block.bytes);
enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory)
enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, vm_factory)
}
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards
@@ -531,11 +545,10 @@ pub fn enact_and_seal(
db: Box<JournalDB>,
parent: &Header,
last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>,
vm_factory: &EvmFactory
) -> Result<SealedBlock, Error> {
let header = BlockView::new(block_bytes).header_view();
Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory)).seal(engine, header.seal())))
Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, vm_factory)).seal(engine, header.seal())))
}
#[cfg(test)]
@@ -555,7 +568,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, Address::zero(), 3141562.into(), vec![]).unwrap();
let b = OpenBlock::new(engine.deref(), &vm_factory, 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![]);
}
@@ -571,7 +584,7 @@ mod tests {
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), 3141562.into(), vec![]).unwrap()
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap()
.close_and_lock().seal(engine.deref(), vec![]).unwrap();
let orig_bytes = b.rlp_bytes();
let orig_db = b.drain();
@@ -579,7 +592,7 @@ mod tests {
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default()).unwrap();
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], &Default::default()).unwrap();
assert_eq!(e.rlp_bytes(), orig_bytes);
@@ -599,7 +612,7 @@ mod tests {
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let vm_factory = Default::default();
let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), 3141562.into(), vec![]).unwrap();
let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], 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();
@@ -614,7 +627,7 @@ mod tests {
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default()).unwrap();
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], &Default::default()).unwrap();
let bytes = e.rlp_bytes();
assert_eq!(bytes, orig_bytes);

View File

@@ -30,7 +30,7 @@ use blockchain::best_block::BestBlock;
use types::tree_route::TreeRoute;
use blockchain::update::ExtrasUpdate;
use blockchain::{CacheSize, ImportRoute, Config};
use db::{Writable, Readable, CacheUpdatePolicy};
use db::{Writable, Readable, CacheUpdatePolicy, Key};
const LOG_BLOOMS_LEVELS: usize = 3;
const LOG_BLOOMS_ELEMENTS_PER_INDEX: usize = 16;
@@ -295,7 +295,34 @@ impl BlockChain {
// load best block
let best_block_hash = match bc.extras_db.get(b"best").unwrap() {
Some(best) => H256::from_slice(&best),
Some(best) => {
let best = H256::from_slice(&best);
let mut b = best.clone();
let mut removed = 0;
let mut best_num = 0;
while !bc.blocks_db.get(&b).unwrap().is_some() {
// track back to the best block we have in the blocks database
let extras: BlockDetails = bc.extras_db.read(&b).unwrap();
type DetailsKey = Key<BlockDetails, Target=H264>;
bc.extras_db.delete(&(DetailsKey::key(&b))).unwrap();
b = extras.parent;
best_num = extras.number;
removed += 1;
}
if b != best {
let batch = DBTransaction::new();
let range = (best_num + 1) as bc::Number .. (best_num + removed) as bc::Number;
let chain = bc::group::BloomGroupChain::new(bc.blooms_config, &bc);
let changes = chain.replace(&range, vec![]);
for (k, v) in changes.into_iter() {
batch.write(&LogGroupPosition::from(k), &BloomGroup::from(v));
}
batch.put(b"best", &b).unwrap();
bc.extras_db.write(batch).unwrap();
info!("Restored mismatched best block. Was: {}, new: {}", best.hex(), b.hex());
}
b
}
None => {
// best block does not exist
// we need to insert genesis into the cache
@@ -461,7 +488,6 @@ impl BlockChain {
/// Applies extras update.
fn apply_update(&self, update: ExtrasUpdate) {
let batch = DBTransaction::new();
batch.put(b"best", &update.info.hash).unwrap();
{
for hash in update.block_details.keys().cloned() {
@@ -484,14 +510,12 @@ impl BlockChain {
// These cached values must be updated last and togeterh
{
let mut best_block = self.best_block.write().unwrap();
let mut write_hashes = self.block_hashes.write().unwrap();
let mut write_txs = self.transaction_addresses.write().unwrap();
// update best block
match update.info.location {
BlockLocation::Branch => (),
_ => {
batch.put(b"best", &update.info.hash).unwrap();
let mut best_block = self.best_block.write().unwrap();
*best_block = BestBlock {
hash: update.info.hash,
number: update.info.number,
@@ -500,8 +524,11 @@ impl BlockChain {
}
}
batch.extend_with_cache(write_hashes.deref_mut(), update.block_hashes, CacheUpdatePolicy::Remove);
batch.extend_with_cache(write_txs.deref_mut(), update.transactions_addresses, CacheUpdatePolicy::Remove);
let mut write_hashes = self.block_hashes.write().unwrap();
let mut write_txs = self.transaction_addresses.write().unwrap();
batch.extend_with_cache(&mut *write_hashes, update.block_hashes, CacheUpdatePolicy::Remove);
batch.extend_with_cache(&mut *write_txs, update.transactions_addresses, CacheUpdatePolicy::Remove);
// update extras database
self.extras_db.write(batch).unwrap();
@@ -1162,4 +1189,31 @@ mod tests {
assert_eq!(blocks_b2, vec![2]);
assert_eq!(blocks_ba, vec![3]);
}
#[test]
fn test_best_block_update() {
let mut canon_chain = ChainGenerator::default();
let mut finalizer = BlockFinalizer::default();
let genesis = canon_chain.generate(&mut finalizer).unwrap();
let temp = RandomTempPath::new();
{
let bc = BlockChain::new(Config::default(), &genesis, temp.as_path());
let uncle = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap();
// create a longer fork
for _ in 0..5 {
let canon_block = canon_chain.generate(&mut finalizer).unwrap();
bc.insert_block(&canon_block, vec![]);
}
assert_eq!(bc.best_block_number(), 5);
bc.insert_block(&uncle, vec![]);
}
// re-loading the blockchain should load the correct best block.
let bc = BlockChain::new(Config::default(), &genesis, temp.as_path());
assert_eq!(bc.best_block_number(), 5);
}
}

View File

@@ -20,7 +20,7 @@ use util::HeapSizeOf;
use basic_types::LogBloom;
/// Helper structure representing bloom of the trace.
#[derive(Clone)]
#[derive(Debug, Clone)]
pub struct Bloom(LogBloom);
impl From<LogBloom> for Bloom {

View File

@@ -20,7 +20,7 @@ use util::HeapSizeOf;
use super::Bloom;
/// Represents group of X consecutive blooms.
#[derive(Clone)]
#[derive(Debug, Clone)]
pub struct BloomGroup {
blooms: Vec<Bloom>,
}

View File

@@ -16,21 +16,22 @@
//! Blockchain database client.
use std::marker::PhantomData;
use std::path::PathBuf;
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
use util::*;
use util::panics::*;
use views::BlockView;
use error::{Error, ImportError, ExecutionError, BlockError, ImportResult};
use error::{ImportError, ExecutionError, BlockError, ImportResult};
use header::{BlockNumber, Header};
use state::State;
use spec::Spec;
use basic_types::Seal;
use engine::Engine;
use views::HeaderView;
use service::{NetSyncMessage, SyncMessage};
use env_info::LastHashes;
use verification::*;
use verification;
use verification::{PreverifiedBlock, Verifier};
use block::*;
use transaction::{LocalizedTransaction, SignedTransaction, Action};
use blockchain::extras::TransactionAddress;
@@ -38,7 +39,8 @@ use 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};
use client::{BlockID, TransactionID, UncleID, TraceId, ClientConfig, DatabaseCompactionProfile,
BlockChainClient, MiningBlockChainClient, TraceFilter, CallAnalytics };
use client::Error as ClientError;
use env_info::EnvInfo;
use executive::{Executive, Executed, TransactOptions, contract_address};
@@ -46,10 +48,13 @@ use receipt::LocalizedReceipt;
pub use blockchain::CacheSize as BlockChainCacheSize;
use trace::{TraceDB, ImportRequest as TraceImportRequest, LocalizedTrace, Database as TraceDatabase};
use trace;
use trace::FlatTransactionTraces;
// re-export
pub use types::blockchain_info::BlockChainInfo;
pub use types::block_status::BlockStatus;
use evm::Factory as EvmFactory;
use miner::{Miner, MinerService, TransactionImportResult, AccountDetails};
use miner::{Miner, MinerService};
const MAX_TX_QUEUE_SIZE: usize = 4096;
@@ -83,7 +88,7 @@ impl ClientReport {
/// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue.
/// Call `import_block()` to import a block asynchronously; `flush_queue()` flushes the queue.
pub struct Client<V = CanonVerifier> where V: Verifier {
pub struct Client {
chain: Arc<BlockChain>,
tracedb: Arc<TraceDB<BlockChain>>,
engine: Arc<Box<Engine>>,
@@ -92,7 +97,7 @@ pub struct Client<V = CanonVerifier> where V: Verifier {
report: RwLock<ClientReport>,
import_lock: Mutex<()>,
panic_handler: Arc<PanicHandler>,
verifier: PhantomData<V>,
verifier: Box<Verifier>,
vm_factory: Arc<EvmFactory>,
miner: Arc<Miner>,
io_channel: IoChannel<NetSyncMessage>,
@@ -107,13 +112,6 @@ const HISTORY: u64 = 1200;
// of which you actually want force an upgrade.
const CLIENT_DB_VER_STR: &'static str = "5.3";
impl Client<CanonVerifier> {
/// Create a new client with given spec and DB path.
pub fn new(config: ClientConfig, spec: Spec, path: &Path, miner: Arc<Miner>, message_channel: IoChannel<NetSyncMessage> ) -> Result<Arc<Client>, ClientError> {
Client::<CanonVerifier>::new_with_verifier(config, spec, path, miner, message_channel)
}
}
/// Get the path for the databases given the root path and information on the databases.
pub fn get_db_path(path: &Path, pruning: journaldb::Algorithm, genesis_hash: H256) -> PathBuf {
let mut dir = path.to_path_buf();
@@ -131,25 +129,35 @@ pub fn append_path(path: &Path, item: &str) -> String {
p.to_str().unwrap().to_owned()
}
impl<V> Client<V> where V: Verifier {
impl Client {
/// Create a new client with given spec and DB path and custom verifier.
pub fn new_with_verifier(
pub fn new(
config: ClientConfig,
spec: Spec,
path: &Path,
miner: Arc<Miner>,
message_channel: IoChannel<NetSyncMessage>)
-> Result<Arc<Client<V>>, ClientError>
-> Result<Arc<Client>, ClientError>
{
let path = get_db_path(path, config.pruning, spec.genesis_header().hash());
let gb = spec.genesis_block();
let chain = Arc::new(BlockChain::new(config.blockchain, &gb, &path));
let tracedb = Arc::new(try!(TraceDB::new(config.tracing, &path, chain.clone())));
let mut state_db_config = match config.db_cache_size {
None => DatabaseConfig::default(),
Some(cache_size) => DatabaseConfig::with_cache(cache_size),
};
if config.db_compaction == DatabaseCompactionProfile::HDD {
state_db_config = state_db_config.compaction(CompactionProfile::hdd());
}
let mut state_db = journaldb::new(
&append_path(&path, "state"),
config.pruning,
config.db_cache_size);
state_db_config
);
if state_db.is_empty() && spec.ensure_db_good(state_db.as_hashdb_mut()) {
state_db.commit(0, &spec.genesis_header().hash(), None).expect("Error commiting genesis state to state DB");
@@ -170,7 +178,7 @@ impl<V> Client<V> where V: Verifier {
report: RwLock::new(Default::default()),
import_lock: Mutex::new(()),
panic_handler: panic_handler,
verifier: PhantomData,
verifier: verification::new(config.verifier_type),
vm_factory: Arc::new(EvmFactory::new(config.vm_type)),
miner: miner,
io_channel: message_channel,
@@ -212,7 +220,7 @@ impl<V> Client<V> where V: Verifier {
}
// Verify Block Family
let verify_family_result = V::verify_block_family(&header, &block.bytes, engine, self.chain.deref());
let verify_family_result = self.verifier.verify_block_family(&header, &block.bytes, engine, self.chain.deref());
if let Err(e) = verify_family_result {
warn!(target: "client", "Stage 3 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
return Err(());
@@ -230,7 +238,7 @@ impl<V> Client<V> where V: Verifier {
let last_hashes = self.build_last_hashes(header.parent_hash.clone());
let db = self.state_db.lock().unwrap().boxed_clone();
let enact_result = enact_verified(&block, engine, self.tracedb.tracing_enabled(), db, &parent, last_hashes, self.dao_rescue_block_gas_limit(header.parent_hash.clone()), &self.vm_factory);
let enact_result = enact_verified(&block, engine, self.tracedb.tracing_enabled(), db, &parent, last_hashes, &self.vm_factory);
if let Err(e) = enact_result {
warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
return Err(());
@@ -238,7 +246,7 @@ impl<V> Client<V> where V: Verifier {
// Final Verification
let locked_block = enact_result.unwrap();
if let Err(e) = V::verify_block_final(&header, locked_block.block().header()) {
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(());
}
@@ -246,7 +254,7 @@ impl<V> Client<V> where V: Verifier {
Ok(locked_block)
}
fn calculate_enacted_retracted(&self, import_results: Vec<ImportRoute>) -> (Vec<H256>, Vec<H256>) {
fn calculate_enacted_retracted(&self, import_results: &[ImportRoute]) -> (Vec<H256>, Vec<H256>) {
fn map_to_vec(map: Vec<(H256, bool)>) -> Vec<H256> {
map.into_iter().map(|(k, _v)| k).collect()
}
@@ -256,12 +264,12 @@ impl<V> Client<V> where V: Verifier {
// could be retracted in import `k+1`. This is why to understand if after all inserts
// the block is enacted or retracted we iterate over all routes and at the end final state
// will be in the hashmap
let map = import_results.into_iter().fold(HashMap::new(), |mut map, route| {
for hash in route.enacted {
map.insert(hash, true);
let map = import_results.iter().fold(HashMap::new(), |mut map, route| {
for hash in &route.enacted {
map.insert(hash.clone(), true);
}
for hash in route.retracted {
map.insert(hash, false);
for hash in &route.retracted {
map.insert(hash.clone(), false);
}
map
});
@@ -284,8 +292,6 @@ impl<V> Client<V> where V: Verifier {
let _timer = PerfTimer::new("import_verified_blocks");
let blocks = self.block_queue.drain(max_blocks_to_import);
let original_best = self.chain_info().best_block_hash;
for block in blocks {
let header = &block.header;
@@ -296,38 +302,12 @@ impl<V> Client<V> where V: Verifier {
let closed_block = self.check_and_close_block(&block);
if let Err(_) = closed_block {
invalid_blocks.insert(header.hash());
break;
continue;
}
let closed_block = closed_block.unwrap();
imported_blocks.push(header.hash());
// Are we committing an era?
let ancient = if header.number() >= HISTORY {
let n = header.number() - HISTORY;
Some((n, self.chain.block_hash(n).unwrap()))
} else {
None
};
// Commit results
let closed_block = closed_block.unwrap();
let receipts = closed_block.block().receipts().clone();
let traces = From::from(closed_block.block().traces().clone().unwrap_or_else(Vec::new));
closed_block.drain()
.commit(header.number(), &header.hash(), ancient)
.expect("State DB commit failed.");
// And update the chain after commit to prevent race conditions
// (when something is in chain but you are not able to fetch details)
let route = self.chain.insert_block(&block.bytes, receipts);
self.tracedb.import(TraceImportRequest {
traces: traces,
block_hash: header.hash(),
block_number: header.number(),
enacted: route.enacted.clone(),
retracted: route.retracted.len()
});
let route = self.commit_block(closed_block, &header.hash(), &block.bytes);
import_results.push(route);
self.report.write().unwrap().accrue_block(&block);
@@ -348,7 +328,7 @@ impl<V> Client<V> where V: Verifier {
{
if !imported_blocks.is_empty() && self.block_queue.queue_info().is_empty() {
let (enacted, retracted) = self.calculate_enacted_retracted(import_results);
let (enacted, retracted) = self.calculate_enacted_retracted(&import_results);
if self.queue_info().is_empty() {
self.miner.chain_new_blocks(self, &imported_blocks, &invalid_blocks, &enacted, &retracted);
@@ -359,29 +339,57 @@ impl<V> Client<V> where V: Verifier {
invalid: invalid_blocks,
enacted: enacted,
retracted: retracted,
})).unwrap();
}
}
{
if self.chain_info().best_block_hash != original_best {
self.miner.update_sealing(self);
sealed: Vec::new(),
})).unwrap_or_else(|e| warn!("Error sending IO notification: {:?}", e));
}
}
imported
}
fn commit_block<B>(&self, block: B, hash: &H256, block_data: &Bytes) -> ImportRoute where B: IsBlock + Drain {
let number = block.header().number();
// Are we committing an era?
let ancient = if number >= HISTORY {
let n = number - HISTORY;
Some((n, self.chain.block_hash(n).unwrap()))
} else {
None
};
// Commit results
let receipts = block.receipts().to_owned();
let traces = block.traces().clone().unwrap_or_else(Vec::new);
let traces: Vec<FlatTransactionTraces> = traces.into_iter()
.map(Into::into)
.collect();
//let traces = From::from(block.traces().clone().unwrap_or_else(Vec::new));
// 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(number, hash, ancient).expect("State DB commit failed.");
// And update the chain after commit to prevent race conditions
// (when something is in chain but you are not able to fetch details)
let route = self.chain.insert_block(block_data, receipts);
self.tracedb.import(TraceImportRequest {
traces: traces.into(),
block_hash: hash.clone(),
block_number: number,
enacted: route.enacted.clone(),
retracted: route.retracted.len()
});
route
}
/// Import transactions from the IO queue
pub fn import_queued_transactions(&self, transactions: &[Bytes]) -> usize {
let _timer = PerfTimer::new("import_queued_transactions");
self.queue_transactions.fetch_sub(transactions.len(), AtomicOrdering::SeqCst);
let fetch_account = |a: &Address| AccountDetails {
nonce: self.latest_nonce(a),
balance: self.latest_balance(a),
};
let tx = transactions.iter().filter_map(|bytes| UntrustedRlp::new(&bytes).as_val().ok()).collect();
let results = self.miner.import_transactions(self, tx, fetch_account);
let txs = transactions.iter().filter_map(|bytes| UntrustedRlp::new(&bytes).as_val().ok()).collect();
let results = self.miner.import_external_transactions(self, txs);
results.len()
}
@@ -391,8 +399,10 @@ impl<V> Client<V> where V: Verifier {
/// Otherwise, this can fail (but may not) if the DB prunes state.
pub fn state_at(&self, id: BlockID) -> Option<State> {
// fast path for latest state.
if let BlockID::Latest = id.clone() {
return Some(self.state())
match id.clone() {
BlockID::Pending => return self.miner.pending_state().or_else(|| Some(self.state())),
BlockID::Latest => return Some(self.state()),
_ => {},
}
let block_number = match self.block_number(id.clone()) {
@@ -449,7 +459,7 @@ impl<V> Client<V> where V: Verifier {
BlockID::Number(number) => Some(number),
BlockID::Hash(ref hash) => self.chain.block_number(hash),
BlockID::Earliest => Some(0),
BlockID::Latest => Some(self.chain.best_block_number())
BlockID::Latest | BlockID::Pending => Some(self.chain.best_block_number()),
}
}
@@ -458,7 +468,7 @@ impl<V> Client<V> where V: Verifier {
BlockID::Hash(hash) => Some(hash),
BlockID::Number(number) => chain.block_hash(number),
BlockID::Earliest => chain.block_hash(0),
BlockID::Latest => Some(chain.best_block_hash())
BlockID::Latest | BlockID::Pending => Some(chain.best_block_hash()),
}
}
@@ -473,7 +483,7 @@ impl<V> Client<V> where V: Verifier {
}
}
impl<V> BlockChainClient for Client<V> where V: Verifier {
impl BlockChainClient for Client {
fn call(&self, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, ExecutionError> {
let header = self.block_header(BlockID::Latest).unwrap();
let view = HeaderView::new(&header);
@@ -486,7 +496,6 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
last_hashes: last_hashes,
gas_used: U256::zero(),
gas_limit: U256::max_value(),
dao_rescue_block_gas_limit: self.dao_rescue_block_gas_limit(view.parent_hash()),
};
// that's just a copy of the state.
let mut state = self.state();
@@ -512,9 +521,6 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
ret
}
fn vm_factory(&self) -> &EvmFactory {
&self.vm_factory
}
fn block_header(&self, id: BlockID) -> Option<Bytes> {
Self::block_hash(&self.chain, id).and_then(|hash| self.chain.block(&hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec()))
@@ -533,6 +539,11 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
}
fn block(&self, id: BlockID) -> Option<Bytes> {
if let &BlockID::Pending = &id {
if let Some(block) = self.miner.pending_block() {
return Some(block.rlp_bytes(Seal::Without));
}
}
Self::block_hash(&self.chain, id).and_then(|hash| {
self.chain.block(&hash)
})
@@ -547,6 +558,11 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
}
fn block_total_difficulty(&self, id: BlockID) -> Option<U256> {
if let &BlockID::Pending = &id {
if let Some(block) = self.miner.pending_block() {
return Some(*block.header.difficulty() + self.block_total_difficulty(BlockID::Latest).expect("blocks in chain have details; qed"));
}
}
Self::block_hash(&self.chain, id).and_then(|hash| self.chain.block_details(&hash)).map(|d| d.total_difficulty)
}
@@ -767,14 +783,6 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
self.build_last_hashes(self.chain.best_block_hash())
}
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, Error>> {
let fetch_account = |a: &Address| AccountDetails {
nonce: self.latest_nonce(a),
balance: self.latest_balance(a),
};
self.miner.import_transactions(self, transactions, fetch_account)
}
fn queue_transactions(&self, transactions: Vec<Bytes>) {
if self.queue_transactions.load(AtomicOrdering::Relaxed) > MAX_TX_QUEUE_SIZE {
debug!("Ignoring {} transactions: queue is full", transactions.len());
@@ -791,13 +799,13 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
}
}
fn all_transactions(&self) -> Vec<SignedTransaction> {
self.miner.all_transactions()
fn pending_transactions(&self) -> Vec<SignedTransaction> {
self.miner.pending_transactions()
}
}
impl<V> MiningBlockChainClient for Client<V> where V: Verifier {
fn prepare_open_block(&self, author: Address, gas_floor_target: U256, extra_data: Bytes) -> OpenBlock {
impl MiningBlockChainClient for Client {
fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock {
let engine = self.engine.deref().deref();
let h = self.chain.best_block_hash();
@@ -808,9 +816,8 @@ impl<V> MiningBlockChainClient for Client<V> where V: Verifier {
self.state_db.lock().unwrap().boxed_clone(),
&self.chain.block_header(&h).expect("h is best block hash: so it's header must exist: qed"),
self.build_last_hashes(h.clone()),
self.dao_rescue_block_gas_limit(h.clone()),
author,
gas_floor_target,
gas_range_target,
extra_data,
).expect("OpenBlock::new only fails if parent state root invalid; state root of best block's header is never invalid; qed");
@@ -826,6 +833,37 @@ impl<V> MiningBlockChainClient for Client<V> where V: Verifier {
open_block
}
fn vm_factory(&self) -> &EvmFactory {
&self.vm_factory
}
fn import_sealed_block(&self, block: SealedBlock) -> ImportResult {
let _import_lock = self.import_lock.lock();
let _timer = PerfTimer::new("import_sealed_block");
let h = block.header().hash();
let number = block.header().number();
let block_data = block.rlp_bytes();
let route = self.commit_block(block, &h, &block_data);
trace!(target: "client", "Imported sealed block #{} ({})", number, h);
{
let (enacted, retracted) = self.calculate_enacted_retracted(&[route]);
self.miner.chain_new_blocks(self, &[h.clone()], &[], &enacted, &retracted);
self.io_channel.send(NetworkIoMessage::User(SyncMessage::NewChainBlocks {
imported: vec![h.clone()],
invalid: vec![],
enacted: enacted,
retracted: retracted,
sealed: vec![h.clone()],
})).unwrap_or_else(|e| warn!("Error sending IO notification: {:?}", e));
}
Ok(h)
}
}
impl MayPanic for Client {

View File

@@ -18,8 +18,22 @@ pub use block_queue::BlockQueueConfig;
pub use blockchain::Config as BlockChainConfig;
pub use trace::{Config as TraceConfig, Switch};
pub use evm::VMType;
pub use verification::VerifierType;
use util::journaldb;
/// Client state db compaction profile
#[derive(Debug, PartialEq)]
pub enum DatabaseCompactionProfile {
/// Default compaction profile
Default,
/// HDD or other slow storage io compaction profile
HDD,
}
impl Default for DatabaseCompactionProfile {
fn default() -> Self { DatabaseCompactionProfile::Default }
}
/// Client configuration. Includes configs for all sub-systems.
#[derive(Debug, Default)]
pub struct ClientConfig {
@@ -37,4 +51,8 @@ pub struct ClientConfig {
pub name: String,
/// State db cache-size if not default
pub db_cache_size: Option<usize>,
/// State db compaction profile
pub db_compaction: DatabaseCompactionProfile,
/// Type of block verifier used by client.
pub verifier_type: VerifierType,
}

View File

@@ -23,7 +23,7 @@ mod test_client;
mod trace;
pub use self::client::*;
pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig, Switch, VMType};
pub use self::config::{ClientConfig, DatabaseCompactionProfile, BlockQueueConfig, BlockChainConfig, Switch, VMType};
pub use self::error::Error;
pub use types::ids::*;
pub use self::test_client::{TestBlockChainClient, EachBlockWith};
@@ -37,18 +37,16 @@ use util::numbers::U256;
use util::Itertools;
use blockchain::TreeRoute;
use block_queue::BlockQueueInfo;
use block::OpenBlock;
use block::{OpenBlock, SealedBlock};
use header::{BlockNumber, Header};
use transaction::{LocalizedTransaction, SignedTransaction};
use log_entry::LocalizedLogEntry;
use filter::Filter;
use views::{HeaderView, BlockView};
use views::{BlockView};
use error::{ImportResult, ExecutionError};
use receipt::LocalizedReceipt;
use trace::LocalizedTrace;
use evm::Factory as EvmFactory;
use miner::{TransactionImportResult};
use error::Error as EthError;
/// Options concerning what analytics we run on the call.
#[derive(Eq, PartialEq, Default, Clone, Copy, Debug)]
@@ -172,9 +170,6 @@ pub trait BlockChainClient : Sync + Send {
// TODO: should be able to accept blockchain location for call.
fn call(&self, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, ExecutionError>;
/// Returns EvmFactory.
fn vm_factory(&self) -> &EvmFactory;
/// Returns traces matching given filter.
fn filter_traces(&self, filter: TraceFilter) -> Option<Vec<LocalizedTrace>>;
@@ -190,14 +185,11 @@ pub trait BlockChainClient : Sync + Send {
/// Get last hashes starting from best block.
fn last_hashes(&self) -> LastHashes;
/// import transactions from network/other 3rd party
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, EthError>>;
/// Queue transactions for importing.
fn queue_transactions(&self, transactions: Vec<Bytes>);
/// list all transactions
fn all_transactions(&self) -> Vec<SignedTransaction>;
fn pending_transactions(&self) -> Vec<SignedTransaction>;
/// Get the gas price distribution.
fn gas_price_statistics(&self, sample_size: usize, distribution_size: usize) -> Result<Vec<U256>, ()> {
@@ -224,33 +216,17 @@ pub trait BlockChainClient : Sync + Send {
Err(())
}
}
/// Get `Some` gas limit of SOFT_FORK_BLOCK, or `None` if chain is not yet that long.
fn dao_rescue_block_gas_limit(&self, chain_hash: H256) -> Option<U256> {
const SOFT_FORK_BLOCK: u64 = 1775000;
// shortcut if the canon chain is already known.
if self.chain_info().best_block_number > SOFT_FORK_BLOCK + 1000 {
return self.block_header(BlockID::Number(SOFT_FORK_BLOCK)).map(|header| HeaderView::new(&header).gas_limit());
}
// otherwise check according to `chain_hash`.
if let Some(mut header) = self.block_header(BlockID::Hash(chain_hash)) {
if HeaderView::new(&header).number() < SOFT_FORK_BLOCK {
None
} else {
while HeaderView::new(&header).number() != SOFT_FORK_BLOCK {
header = self.block_header(BlockID::Hash(HeaderView::new(&header).parent_hash())).expect("chain is complete; parent of chain entry must be in chain; qed");
}
Some(HeaderView::new(&header).gas_limit())
}
} else {
None
}
}
}
/// Extended client interface used for mining
pub trait MiningBlockChainClient : BlockChainClient {
/// Returns OpenBlock prepared for closing.
fn prepare_open_block(&self, author: Address, gas_floor_target: U256, extra_data: Bytes)
fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes)
-> OpenBlock;
/// Returns EvmFactory.
fn vm_factory(&self) -> &EvmFactory;
/// Import sealed block. Skips all verifications.
fn import_sealed_block(&self, block: SealedBlock) -> ImportResult;
}

View File

@@ -20,7 +20,8 @@ use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrder};
use util::*;
use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action};
use blockchain::TreeRoute;
use client::{BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockID, TransactionID, UncleID, TraceId, TraceFilter, LastHashes, CallAnalytics};
use client::{BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockID,
TransactionID, UncleID, TraceId, TraceFilter, LastHashes, CallAnalytics };
use header::{Header as BlockHeader, BlockNumber};
use filter::Filter;
use log_entry::LocalizedLogEntry;
@@ -29,16 +30,14 @@ use blockchain::extras::BlockReceipts;
use error::{ImportResult};
use evm::Factory as EvmFactory;
use miner::{Miner, MinerService};
use spec::Spec;
use block_queue::BlockQueueInfo;
use block::OpenBlock;
use block::{OpenBlock, SealedBlock};
use executive::Executed;
use error::{ExecutionError};
use trace::LocalizedTrace;
use miner::{TransactionImportResult, AccountDetails};
use error::Error as EthError;
/// Test client.
pub struct TestBlockChainClient {
/// Blocks.
@@ -105,7 +104,7 @@ impl TestBlockChainClient {
execution_result: RwLock::new(None),
receipts: RwLock::new(HashMap::new()),
queue_size: AtomicUsize::new(0),
miner: Arc::new(Miner::default()),
miner: Arc::new(Miner::with_spec(Spec::new_test())),
};
client.add_blocks(1, EachBlockWith::Nothing); // add genesis block
client.genesis_hash = client.last_hash.read().unwrap().clone();
@@ -234,13 +233,21 @@ impl TestBlockChainClient {
BlockID::Hash(hash) => Some(hash),
BlockID::Number(n) => self.numbers.read().unwrap().get(&(n as usize)).cloned(),
BlockID::Earliest => self.numbers.read().unwrap().get(&0).cloned(),
BlockID::Latest => self.numbers.read().unwrap().get(&(self.numbers.read().unwrap().len() - 1)).cloned()
BlockID::Latest | BlockID::Pending => self.numbers.read().unwrap().get(&(self.numbers.read().unwrap().len() - 1)).cloned()
}
}
}
impl MiningBlockChainClient for TestBlockChainClient {
fn prepare_open_block(&self, _author: Address, _gas_floor_target: U256, _extra_data: Bytes) -> OpenBlock {
fn prepare_open_block(&self, _author: Address, _gas_range_target: (U256, U256), _extra_data: Bytes) -> OpenBlock {
unimplemented!();
}
fn vm_factory(&self) -> &EvmFactory {
unimplemented!();
}
fn import_sealed_block(&self, _block: SealedBlock) -> ImportResult {
unimplemented!();
}
}
@@ -265,6 +272,10 @@ impl BlockChainClient for TestBlockChainClient {
}
}
fn latest_nonce(&self, address: &Address) -> U256 {
self.nonce(address, BlockID::Latest).unwrap()
}
fn code(&self, address: &Address) -> Option<Bytes> {
self.code.read().unwrap().get(address).cloned()
}
@@ -277,6 +288,10 @@ impl BlockChainClient for TestBlockChainClient {
}
}
fn latest_balance(&self, address: &Address) -> U256 {
self.balance(address, BlockID::Latest).unwrap()
}
fn storage_at(&self, address: &Address, position: &H256, id: BlockID) -> Option<H256> {
if let BlockID::Latest = id {
Some(self.storage.read().unwrap().get(&(address.clone(), position.clone())).cloned().unwrap_or_else(H256::new))
@@ -462,10 +477,6 @@ impl BlockChainClient for TestBlockChainClient {
}
}
fn vm_factory(&self) -> &EvmFactory {
unimplemented!();
}
fn filter_traces(&self, _filter: TraceFilter) -> Option<Vec<LocalizedTrace>> {
unimplemented!();
}
@@ -482,24 +493,13 @@ impl BlockChainClient for TestBlockChainClient {
unimplemented!();
}
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, EthError>> {
let nonces = self.nonces.read().unwrap();
let balances = self.balances.read().unwrap();
let fetch_account = |a: &Address| AccountDetails {
nonce: nonces[a],
balance: balances[a],
};
self.miner.import_transactions(self, transactions, &fetch_account)
}
fn queue_transactions(&self, transactions: Vec<Bytes>) {
// import right here
let tx = transactions.into_iter().filter_map(|bytes| UntrustedRlp::new(&bytes).as_val().ok()).collect();
self.import_transactions(tx);
let txs = transactions.into_iter().filter_map(|bytes| UntrustedRlp::new(&bytes).as_val().ok()).collect();
self.miner.import_external_transactions(self, txs);
}
fn all_transactions(&self) -> Vec<SignedTransaction> {
self.miner.all_transactions()
fn pending_transactions(&self) -> Vec<SignedTransaction> {
self.miner.pending_transactions()
}
}

View File

@@ -96,7 +96,7 @@ pub trait Engine : Sync + Send {
/// Don't forget to call Super::populate_from_parent when subclassing & overriding.
// TODO: consider including State in the params.
fn populate_from_parent(&self, header: &mut Header, parent: &Header, _gas_floor_target: U256) {
fn populate_from_parent(&self, header: &mut Header, parent: &Header, _gas_floor_target: U256, _gas_ceil_target: U256) {
header.difficulty = parent.difficulty;
header.gas_limit = parent.gas_limit;
header.note_dirty();

View File

@@ -39,9 +39,6 @@ pub struct EnvInfo {
pub last_hashes: LastHashes,
/// The gas used.
pub gas_used: U256,
/// Block gas limit at DAO rescue block SOFT_FORK_BLOCK or None if not yet there.
pub dao_rescue_block_gas_limit: Option<U256>,
}
impl Default for EnvInfo {
@@ -54,7 +51,6 @@ impl Default for EnvInfo {
gas_limit: 0.into(),
last_hashes: vec![],
gas_used: 0.into(),
dao_rescue_block_gas_limit: None,
}
}
}
@@ -70,7 +66,6 @@ impl From<ethjson::vm::Env> for EnvInfo {
timestamp: e.timestamp.into(),
last_hashes: (1..cmp::min(number + 1, 257)).map(|i| format!("{}", number - i).as_bytes().sha3()).collect(),
gas_used: U256::zero(),
dao_rescue_block_gas_limit: None,
}
}
}

View File

@@ -58,8 +58,6 @@ pub enum TransactionError {
},
/// Transaction's gas limit (aka gas) is invalid.
InvalidGasLimit(OutOfBounds<U256>),
/// Transaction is invalid for some other reason.
DAORescue,
}
impl fmt::Display for TransactionError {
@@ -78,7 +76,6 @@ impl fmt::Display for TransactionError {
GasLimitExceeded { limit, got } =>
format!("Gas limit exceeded. Limit={}, Given={}", limit, got),
InvalidGasLimit(ref err) => format!("Invalid gas limit. {}", err),
DAORescue => "Transaction is invalid due to the DAO rescue.".into(),
};
f.write_fmt(format_args!("Transaction error ({})", msg))

View File

@@ -14,9 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
extern crate ethash;
use self::ethash::{quick_get_difficulty, EthashManager, H256 as EH256};
use ethash::{quick_get_difficulty, EthashManager, H256 as EH256};
use common::*;
use block::*;
use spec::CommonParams;
@@ -41,8 +39,12 @@ pub struct EthashParams {
pub registrar: Address,
/// Homestead transition block number.
pub frontier_compatibility_mode_limit: u64,
/// Enable the soft-fork logic.
pub dao_rescue_soft_fork: bool,
/// 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>,
}
impl From<ethjson::spec::EthashParams> for EthashParams {
@@ -53,9 +55,11 @@ impl From<ethjson::spec::EthashParams> for EthashParams {
difficulty_bound_divisor: p.difficulty_bound_divisor.into(),
duration_limit: p.duration_limit.into(),
block_reward: p.block_reward.into(),
registrar: p.registrar.into(),
frontier_compatibility_mode_limit: p.frontier_compatibility_mode_limit.into(),
dao_rescue_soft_fork: p.dao_rescue_soft_fork.into(),
registrar: p.registrar.map(Into::into).unwrap_or(Address::new()),
frontier_compatibility_mode_limit: p.frontier_compatibility_mode_limit.map(Into::into).unwrap_or(0),
dao_hardfork_transition: p.dao_hardfork_transition.map(Into::into).unwrap_or(0x7fffffffffffffff),
dao_hardfork_beneficiary: p.dao_hardfork_beneficiary.map(Into::into).unwrap_or(Address::new()),
dao_hardfork_accounts: p.dao_hardfork_accounts.unwrap_or(vec![]).into_iter().map(Into::into).collect(),
}
}
}
@@ -104,29 +108,47 @@ impl Engine for Ethash {
if env_info.number < self.ethash_params.frontier_compatibility_mode_limit {
Schedule::new_frontier()
} else {
let mut s = Schedule::new_homestead();
if self.ethash_params.dao_rescue_soft_fork {
s.reject_dao_transactions = env_info.dao_rescue_block_gas_limit.map_or(false, |x| x <= 4_000_000.into());
}
s
Schedule::new_homestead()
}
}
fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256) {
fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, gas_ceil_target: U256) {
header.difficulty = self.calculate_difficuty(header, parent);
header.gas_limit = {
let gas_limit = parent.gas_limit;
let bound_divisor = self.ethash_params.gas_limit_bound_divisor;
if gas_limit < gas_floor_target {
min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into())
} else if gas_limit > gas_ceil_target {
max(gas_ceil_target, gas_limit - gas_limit / bound_divisor + 1.into())
} else {
max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1.into() + (header.gas_used * 6.into() / 5.into()) / bound_divisor)
min(gas_ceil_target,
max(gas_floor_target,
gas_limit - gas_limit / bound_divisor + 1.into() +
(header.gas_used * 6.into() / 5.into()) / bound_divisor))
}
};
if header.number >= self.ethash_params.dao_hardfork_transition &&
header.number <= self.ethash_params.dao_hardfork_transition + 9 {
header.extra_data = b"dao-hard-fork"[..].to_owned();
}
header.note_dirty();
// info!("ethash: populate_from_parent #{}: difficulty={} and gas_limit={}", header.number, header.difficulty, header.gas_limit);
}
fn on_new_block(&self, block: &mut ExecutedBlock) {
if block.fields().header.number == self.ethash_params.dao_hardfork_transition {
// TODO: enable trigger function maybe?
// if block.fields().header.gas_limit <= 4_000_000.into() {
let mut state = block.fields_mut().state;
for child in self.ethash_params.dao_hardfork_accounts.iter() {
let b = state.balance(child);
state.transfer_balance(child, &self.ethash_params.dao_hardfork_beneficiary, &b);
}
// }
}
}
/// Apply the block reward on finalisation of the block.
/// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current).
fn on_close_block(&self, block: &mut ExecutedBlock) {
@@ -168,6 +190,17 @@ impl Engine for Ethash {
if difficulty < header.difficulty {
return Err(From::from(BlockError::InvalidProofOfWork(OutOfBounds { min: Some(header.difficulty), max: None, found: difficulty })));
}
if header.number >= self.ethash_params.dao_hardfork_transition &&
header.number <= self.ethash_params.dao_hardfork_transition + 9 &&
header.extra_data[..] != b"dao-hard-fork"[..] {
return Err(From::from(BlockError::ExtraDataOutOfBounds(OutOfBounds { min: None, max: None, found: 0 })));
}
if header.gas_limit > 0x7fffffffffffffffu64.into() {
return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds { min: None, max: Some(0x7fffffffffffffffu64.into()), found: header.gas_limit })));
}
Ok(())
}
@@ -237,8 +270,7 @@ impl Ethash {
let mut target = if header.number < frontier_limit {
if header.timestamp >= parent.timestamp + duration_limit {
parent.difficulty - (parent.difficulty / difficulty_bound_divisor)
}
else {
} else {
parent.difficulty + (parent.difficulty / difficulty_bound_divisor)
}
}
@@ -323,7 +355,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, Address::zero(), 3141562.into(), vec![]).unwrap();
let b = OpenBlock::new(engine.deref(), &vm_factory, 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());
}
@@ -338,7 +370,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default();
let mut b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, Address::zero(), 3141562.into(), vec![]).unwrap();
let mut b = OpenBlock::new(engine.deref(), &vm_factory, 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();
@@ -367,7 +399,6 @@ mod tests {
last_hashes: vec![],
gas_used: 0.into(),
gas_limit: 0.into(),
dao_rescue_block_gas_limit: None,
});
assert!(schedule.stack_limit > 0);
@@ -380,7 +411,6 @@ mod tests {
last_hashes: vec![],
gas_used: 0.into(),
gas_limit: 0.into(),
dao_rescue_block_gas_limit: None,
});
assert!(!schedule.have_delegate_call);

View File

@@ -33,11 +33,13 @@ use super::spec::*;
pub fn new_olympic() -> Spec { Spec::load(include_bytes!("../../res/ethereum/olympic.json")) }
/// Create a new Frontier mainnet chain spec.
pub fn new_frontier(dao_rescue: bool) -> Spec {
Spec::load(match dao_rescue {
true => include_bytes!("../../res/ethereum/frontier_dao_rescue.json"),
false => include_bytes!("../../res/ethereum/frontier.json"),
})
pub fn new_frontier() -> Spec {
Spec::load(include_bytes!("../../res/ethereum/frontier.json"))
}
/// Create a new Frontier mainnet chain spec without the DAO hardfork.
pub fn new_frontier_dogmatic() -> Spec {
Spec::load(include_bytes!("../../res/ethereum/frontier-dogmatic.json"))
}
/// Create a new Frontier chain spec as though it never changes to Homestead.
@@ -46,6 +48,9 @@ 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 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")) }
/// 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")) }
@@ -89,7 +94,7 @@ mod tests {
#[test]
fn frontier() {
let frontier = new_frontier(true);
let frontier = new_frontier();
assert_eq!(frontier.state_root(), H256::from_str("d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544").unwrap());
let genesis = frontier.genesis_block();

View File

@@ -18,6 +18,7 @@
use util::common::*;
use evm::{self, Schedule};
use types::executed::CallType;
use env_info::*;
/// Result of externalities create function.
@@ -69,13 +70,15 @@ pub trait Ext {
/// and true if subcall was successfull.
#[cfg_attr(feature="dev", allow(too_many_arguments))]
fn call(&mut self,
gas: &U256,
sender_address: &Address,
receive_address: &Address,
value: Option<U256>,
data: &[u8],
code_address: &Address,
output: &mut [u8]) -> MessageCallResult;
gas: &U256,
sender_address: &Address,
receive_address: &Address,
value: Option<U256>,
data: &[u8],
code_address: &Address,
output: &mut [u8],
call_type: CallType
) -> MessageCallResult;
/// Returns code at given address
fn extcode(&self, address: &Address) -> Bytes;

View File

@@ -20,6 +20,7 @@ use common::*;
use super::instructions as instructions;
use super::instructions::{Instruction, get_info};
use std::marker::Copy;
use types::executed::CallType;
use evm::{self, MessageCallResult, ContractCreateResult, GasLeft};
#[cfg(not(feature = "evm-debug"))]
@@ -648,16 +649,16 @@ impl Interpreter {
});
// Get sender & receive addresses, check if we have balance
let (sender_address, receive_address, has_balance) = match instruction {
let (sender_address, receive_address, has_balance, call_type) = match instruction {
instructions::CALL => {
let has_balance = ext.balance(&params.address) >= value.unwrap();
(&params.address, &code_address, has_balance)
(&params.address, &code_address, has_balance, CallType::Call)
},
instructions::CALLCODE => {
let has_balance = ext.balance(&params.address) >= value.unwrap();
(&params.address, &params.address, has_balance)
(&params.address, &params.address, has_balance, CallType::CallCode)
},
instructions::DELEGATECALL => (&params.sender, &params.address, true),
instructions::DELEGATECALL => (&params.sender, &params.address, true, CallType::DelegateCall),
_ => panic!(format!("Unexpected instruction {} in CALL branch.", instruction))
};
@@ -672,7 +673,7 @@ impl Interpreter {
// and we don't want to copy
let input = unsafe { ::std::mem::transmute(self.mem.read_slice(in_off, in_size)) };
let output = self.mem.writeable_slice(out_off, out_size);
ext.call(&call_gas, sender_address, receive_address, value, input, &code_address, output)
ext.call(&call_gas, sender_address, receive_address, value, input, &code_address, output, call_type)
};
return match call_result {

View File

@@ -80,8 +80,6 @@ pub struct Schedule {
pub tx_data_non_zero_gas: usize,
/// Gas price for copying memory
pub copy_gas: usize,
/// DAO Rescue softfork block
pub reject_dao_transactions: bool,
}
impl Schedule {
@@ -128,7 +126,6 @@ impl Schedule {
tx_data_zero_gas: 4,
tx_data_non_zero_gas: 68,
copy_gas: 3,
reject_dao_transactions: false,
}
}
}

View File

@@ -15,6 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use common::*;
use types::executed::CallType;
use evm::{self, Ext, Schedule, Factory, GasLeft, VMType, ContractCreateResult, MessageCallResult};
use std::fmt::Debug;
@@ -36,7 +37,7 @@ struct FakeCall {
receive_address: Option<Address>,
value: Option<U256>,
data: Bytes,
code_address: Option<Address>
code_address: Option<Address>,
}
/// Fake externalities test structure.
@@ -119,7 +120,9 @@ impl Ext for FakeExt {
value: Option<U256>,
data: &[u8],
code_address: &Address,
_output: &mut [u8]) -> MessageCallResult {
_output: &mut [u8],
_call_type: CallType
) -> MessageCallResult {
self.calls.insert(FakeCall {
call_type: FakeCallType::Call,

View File

@@ -18,10 +18,11 @@
use common::*;
use state::*;
use engine::*;
use types::executed::CallType;
use evm::{self, Ext, Factory, Finalize};
use externalities::*;
use substate::*;
use trace::{Trace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer};
use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer};
use crossbeam;
pub use types::executed::{Executed, ExecutionResult};
@@ -173,6 +174,7 @@ impl<'a> Executive<'a> {
value: ActionValue::Transfer(t.value),
code: Some(t.data.clone()),
data: None,
call_type: CallType::None,
};
(self.create(params, &mut substate, &mut tracer, &mut vm_tracer), vec![])
},
@@ -187,6 +189,7 @@ impl<'a> Executive<'a> {
value: ActionValue::Transfer(t.value),
code: self.state.code(address),
data: Some(t.data.clone()),
call_type: CallType::Call,
};
// TODO: move output upstream
let mut out = vec![];
@@ -195,7 +198,7 @@ impl<'a> Executive<'a> {
};
// finalize here!
Ok(try!(self.finalize(t, substate, gas_left, output, tracer.traces().pop(), vm_tracer.drain())))
Ok(try!(self.finalize(t, substate, gas_left, output, tracer.traces(), vm_tracer.drain())))
}
fn exec_vm<T, V>(
@@ -248,8 +251,6 @@ impl<'a> Executive<'a> {
}
trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info);
let delegate_call = params.code_address != params.address;
if self.engine.is_builtin(&params.code_address) {
// if destination is builtin, try to execute it
@@ -275,20 +276,15 @@ impl<'a> Executive<'a> {
trace_info,
cost,
trace_output,
self.depth,
vec![],
delegate_call
vec![]
);
}
Ok(params.gas - cost)
},
// just drain the whole gas
false => {
self.state.revert_snapshot();
tracer.trace_failed_call(trace_info, self.depth, vec![], delegate_call);
tracer.trace_failed_call(trace_info, vec![]);
Err(evm::Error::OutOfGas)
}
}
@@ -320,11 +316,9 @@ impl<'a> Executive<'a> {
trace_info,
gas - gas_left,
trace_output,
self.depth,
traces,
delegate_call
traces
),
_ => tracer.trace_failed_call(trace_info, self.depth, traces, delegate_call),
_ => tracer.trace_failed_call(trace_info, traces),
};
trace!(target: "executive", "substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate);
@@ -336,7 +330,7 @@ impl<'a> Executive<'a> {
// otherwise it's just a basic transaction, only do tracing, if necessary.
self.state.clear_snapshot();
tracer.trace_call(trace_info, U256::zero(), trace_output, self.depth, vec![], delegate_call);
tracer.trace_call(trace_info, U256::zero(), trace_output, vec![]);
Ok(params.gas)
}
}
@@ -387,10 +381,9 @@ impl<'a> Executive<'a> {
gas - gas_left,
trace_output,
created,
self.depth,
subtracer.traces()
),
_ => tracer.trace_failed_create(trace_info, self.depth, subtracer.traces())
_ => tracer.trace_failed_create(trace_info, subtracer.traces())
};
self.enact_result(&res, substate, unconfirmed_substate);
@@ -404,7 +397,7 @@ impl<'a> Executive<'a> {
substate: Substate,
result: evm::Result<U256>,
output: Bytes,
trace: Option<Trace>,
trace: Vec<FlatTrace>,
vm_trace: Option<VMTrace>
) -> ExecutionResult {
let schedule = self.engine.schedule(self.info);
@@ -496,8 +489,9 @@ mod tests {
use substate::*;
use tests::helpers::*;
use trace::trace;
use trace::{Trace, Tracer, NoopTracer, ExecutiveTracer};
use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer};
use trace::{VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, VMTracer, NoopVMTracer, ExecutiveVMTracer};
use types::executed::CallType;
#[test]
fn test_contract_address() {
@@ -631,6 +625,7 @@ mod tests {
params.gas = U256::from(100_000);
params.code = Some(code.clone());
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));
@@ -648,35 +643,37 @@ mod tests {
assert_eq!(gas_left, U256::from(44_752));
let expected_trace = vec![ Trace {
depth: 0,
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
subtraces: 1,
action: trace::Action::Call(trace::Call {
from: "cd1722f3947def4cf144679da39c4c32bdc35681".into(),
to: "b010143a42d5980c7e5ef0e4a4416dc098a4fed3".into(),
value: 100.into(),
gas: 100000.into(),
input: vec![],
call_type: CallType::Call,
}),
result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(55_248),
output: vec![],
}),
subs: vec![Trace {
depth: 1,
action: trace::Action::Create(trace::Create {
from: "b010143a42d5980c7e5ef0e4a4416dc098a4fed3".into(),
value: 23.into(),
gas: 67979.into(),
init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85]
}),
result: trace::Res::Create(trace::CreateResult {
gas_used: U256::from(3224),
address: Address::from_str("c6d80f262ae5e0f164e5fde365044d7ada2bfa34").unwrap(),
code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53]
}),
subs: vec![]
}]
}, FlatTrace {
trace_address: vec![0].into_iter().collect(),
subtraces: 0,
action: trace::Action::Create(trace::Create {
from: "b010143a42d5980c7e5ef0e4a4416dc098a4fed3".into(),
value: 23.into(),
gas: 67979.into(),
init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85]
}),
result: trace::Res::Create(trace::CreateResult {
gas_used: U256::from(3224),
address: Address::from_str("c6d80f262ae5e0f164e5fde365044d7ada2bfa34").unwrap(),
code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53]
}),
}];
assert_eq!(tracer.traces(), expected_trace);
let expected_vm_trace = VMTrace {
@@ -754,8 +751,9 @@ mod tests {
assert_eq!(gas_left, U256::from(96_776));
let expected_trace = vec![Trace {
depth: 0,
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
subtraces: 0,
action: trace::Action::Create(trace::Create {
from: params.sender,
value: 100.into(),
@@ -767,8 +765,8 @@ mod tests {
address: params.address,
code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53]
}),
subs: vec![]
}];
assert_eq!(tracer.traces(), expected_trace);
let expected_vm_trace = VMTrace {

View File

@@ -21,6 +21,7 @@ use engine::*;
use executive::*;
use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult, Factory};
use substate::*;
use types::executed::CallType;
use trace::{Tracer, VMTracer};
/// Policy for handling output data on `RETURN` opcode.
@@ -148,6 +149,7 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
value: ActionValue::Transfer(*value),
code: Some(code.to_vec()),
data: None,
call_type: CallType::None,
};
self.state.inc_nonce(&self.origin_info.address);
@@ -170,7 +172,8 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
value: Option<U256>,
data: &[u8],
code_address: &Address,
output: &mut [u8]
output: &mut [u8],
call_type: CallType
) -> MessageCallResult {
trace!(target: "externalities", "call");
@@ -184,6 +187,7 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
gas_price: self.origin_info.gas_price,
code: self.state.code(code_address),
data: Some(data.to_vec()),
call_type: call_type,
};
if let Some(value) = value {
@@ -262,6 +266,8 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
trace!("Suiciding {} -> {} (xfer: {})", address, refund_address, balance);
self.state.transfer_balance(&address, refund_address, &balance);
}
self.tracer.trace_suicide(address, balance, refund_address.clone());
self.substate.suicides.insert(address);
}
@@ -300,6 +306,7 @@ mod tests {
use tests::helpers::*;
use super::*;
use trace::{NoopTracer, NoopVMTracer};
use types::executed::CallType;
fn get_test_origin() -> OriginInfo {
OriginInfo {
@@ -319,7 +326,6 @@ mod tests {
last_hashes: vec![],
gas_used: 0.into(),
gas_limit: 0.into(),
dao_rescue_block_gas_limit: None,
}
}
@@ -419,7 +425,9 @@ mod tests {
Some(U256::from_str("0000000000000000000000000000000000000000000000000000000000150000").unwrap()),
&[],
&Address::new(),
&mut output);
&mut output,
CallType::Call
);
}
#[test]

View File

@@ -22,6 +22,7 @@ use tests::helpers::*;
use devtools::*;
use spec::Genesis;
use ethjson;
use ethjson::blockchain::BlockChain;
use miner::Miner;
pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
@@ -41,20 +42,29 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
flush!(" - {}...", name);
let mut spec = match era {
ChainEra::Frontier => ethereum::new_frontier_test(),
ChainEra::Homestead => ethereum::new_homestead_test(),
let spec = |blockchain: &BlockChain| {
let genesis = Genesis::from(blockchain.genesis());
let state = From::from(blockchain.pre_state.clone());
let mut spec = match era {
ChainEra::Frontier => ethereum::new_frontier_test(),
ChainEra::Homestead => ethereum::new_homestead_test(),
ChainEra::DaoHardfork => ethereum::new_daohardfork_test(),
};
spec.set_genesis_state(state);
spec.overwrite_genesis_params(genesis);
assert!(spec.is_state_root_valid());
spec
};
let genesis = Genesis::from(blockchain.genesis());
let state = From::from(blockchain.pre_state.clone());
spec.set_genesis_state(state);
spec.overwrite_genesis_params(genesis);
assert!(spec.is_state_root_valid());
let temp = RandomTempPath::new();
{
let client = Client::new(ClientConfig::default(), spec, temp.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap();
let client = Client::new(
ClientConfig::default(),
spec(&blockchain),
temp.as_path(),
Arc::new(Miner::with_spec(spec(&blockchain))),
IoChannel::disconnected()
).unwrap();
for b in &blockchain.blocks_rlp() {
if Block::is_good(&b) {
let _ = client.import_block(b.clone());
@@ -75,26 +85,43 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
failed
}
fn do_json_test(json_data: &[u8]) -> Vec<String> {
json_chain_test(json_data, ChainEra::Frontier)
mod frontier_era_tests {
use tests::helpers::*;
use super::json_chain_test;
fn do_json_test(json_data: &[u8]) -> Vec<String> {
json_chain_test(json_data, ChainEra::Frontier)
}
declare_test!{BlockchainTests_bcBlockGasLimitTest, "BlockchainTests/bcBlockGasLimitTest"}
declare_test!{BlockchainTests_bcForkBlockTest, "BlockchainTests/bcForkBlockTest"}
declare_test!{BlockchainTests_bcForkStressTest, "BlockchainTests/bcForkStressTest"}
declare_test!{BlockchainTests_bcForkUncle, "BlockchainTests/bcForkUncle"}
declare_test!{BlockchainTests_bcGasPricerTest, "BlockchainTests/bcGasPricerTest"}
declare_test!{BlockchainTests_bcInvalidHeaderTest, "BlockchainTests/bcInvalidHeaderTest"}
// TODO [ToDr] Ignored because of incorrect JSON (https://github.com/ethereum/tests/pull/113)
declare_test!{ignore => BlockchainTests_bcInvalidRLPTest, "BlockchainTests/bcInvalidRLPTest"}
declare_test!{BlockchainTests_bcMultiChainTest, "BlockchainTests/bcMultiChainTest"}
declare_test!{BlockchainTests_bcRPC_API_Test, "BlockchainTests/bcRPC_API_Test"}
declare_test!{BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"}
declare_test!{BlockchainTests_bcTotalDifficultyTest, "BlockchainTests/bcTotalDifficultyTest"}
declare_test!{BlockchainTests_bcUncleHeaderValiditiy, "BlockchainTests/bcUncleHeaderValiditiy"}
declare_test!{BlockchainTests_bcUncleTest, "BlockchainTests/bcUncleTest"}
declare_test!{BlockchainTests_bcValidBlockTest, "BlockchainTests/bcValidBlockTest"}
declare_test!{BlockchainTests_bcWalletTest, "BlockchainTests/bcWalletTest"}
declare_test!{BlockchainTests_RandomTests_bl10251623GO, "BlockchainTests/RandomTests/bl10251623GO"}
declare_test!{BlockchainTests_RandomTests_bl201507071825GO, "BlockchainTests/RandomTests/bl201507071825GO"}
}
declare_test!{BlockchainTests_bcBlockGasLimitTest, "BlockchainTests/bcBlockGasLimitTest"}
declare_test!{BlockchainTests_bcForkBlockTest, "BlockchainTests/bcForkBlockTest"}
declare_test!{BlockchainTests_bcForkStressTest, "BlockchainTests/bcForkStressTest"}
declare_test!{BlockchainTests_bcForkUncle, "BlockchainTests/bcForkUncle"}
declare_test!{BlockchainTests_bcGasPricerTest, "BlockchainTests/bcGasPricerTest"}
declare_test!{BlockchainTests_bcInvalidHeaderTest, "BlockchainTests/bcInvalidHeaderTest"}
// TODO [ToDr] Ignored because of incorrect JSON (https://github.com/ethereum/tests/pull/113)
declare_test!{ignore => BlockchainTests_bcInvalidRLPTest, "BlockchainTests/bcInvalidRLPTest"}
declare_test!{BlockchainTests_bcMultiChainTest, "BlockchainTests/bcMultiChainTest"}
declare_test!{BlockchainTests_bcRPC_API_Test, "BlockchainTests/bcRPC_API_Test"}
declare_test!{BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"}
declare_test!{BlockchainTests_bcTotalDifficultyTest, "BlockchainTests/bcTotalDifficultyTest"}
declare_test!{BlockchainTests_bcUncleHeaderValiditiy, "BlockchainTests/bcUncleHeaderValiditiy"}
declare_test!{BlockchainTests_bcUncleTest, "BlockchainTests/bcUncleTest"}
declare_test!{BlockchainTests_bcValidBlockTest, "BlockchainTests/bcValidBlockTest"}
declare_test!{BlockchainTests_bcWalletTest, "BlockchainTests/bcWalletTest"}
mod daohardfork_tests {
use tests::helpers::*;
use super::json_chain_test;
declare_test!{BlockchainTests_RandomTests_bl10251623GO, "BlockchainTests/RandomTests/bl10251623GO"}
declare_test!{BlockchainTests_RandomTests_bl201507071825GO, "BlockchainTests/RandomTests/bl201507071825GO"}
fn do_json_test(json_data: &[u8]) -> Vec<String> {
json_chain_test(json_data, ChainEra::DaoHardfork)
}
declare_test!{BlockchainTests_TestNetwork_bcSimpleTransitionTest, "BlockchainTests/TestNetwork/bcSimpleTransitionTest"}
declare_test!{BlockchainTests_TestNetwork_bcTheDaoTest, "BlockchainTests/TestNetwork/bcTheDaoTest"}
}

View File

@@ -22,6 +22,7 @@ use evm;
use evm::{Schedule, Ext, Factory, Finalize, VMType, ContractCreateResult, MessageCallResult};
use externalities::*;
use substate::*;
use types::executed::CallType;
use tests::helpers::*;
use ethjson;
use trace::{Tracer, NoopTracer};
@@ -109,13 +110,15 @@ impl<'a, T, V> Ext for TestExt<'a, T, V> where T: Tracer, V: VMTracer {
}
fn call(&mut self,
gas: &U256,
_sender_address: &Address,
receive_address: &Address,
value: Option<U256>,
data: &[u8],
_code_address: &Address,
_output: &mut [u8]) -> MessageCallResult {
gas: &U256,
_sender_address: &Address,
receive_address: &Address,
value: Option<U256>,
data: &[u8],
_code_address: &Address,
_output: &mut [u8],
_call_type: CallType
) -> MessageCallResult {
self.callcreates.push(CallCreate {
data: data.to_vec(),
destination: Some(receive_address.clone()),

View File

@@ -30,8 +30,9 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
let mut failed = Vec::new();
let engine = match era {
ChainEra::Frontier => ethereum::new_mainnet_like().engine,
ChainEra::Homestead => ethereum::new_homestead_test().engine
};
ChainEra::Homestead => ethereum::new_homestead_test().engine,
ChainEra::DaoHardfork => ethereum::new_daohardfork_test().engine,
};
for (name, test) in tests.into_iter() {
let mut fail = false;

View File

@@ -91,6 +91,8 @@ extern crate ethjson;
extern crate bloomchain;
#[macro_use] extern crate ethcore_ipc as ipc;
extern crate rayon;
extern crate hyper;
extern crate ethash;
pub extern crate ethstore;
#[cfg(test)] extern crate ethcore_devtools as devtools;

View File

@@ -15,85 +15,135 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use rayon::prelude::*;
use std::sync::atomic::AtomicBool;
use std::time::{Instant, Duration};
use util::*;
use util::Colour::White;
use account_provider::AccountProvider;
use views::{BlockView, HeaderView};
use state::State;
use client::{MiningBlockChainClient, Executive, Executed, EnvInfo, TransactOptions, BlockID, CallAnalytics};
use block::{ClosedBlock, IsBlock};
use block::{ClosedBlock, IsBlock, Block};
use error::*;
use transaction::SignedTransaction;
use receipt::{Receipt};
use spec::Spec;
use engine::Engine;
use miner::{MinerService, MinerStatus, TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin};
use miner::work_notify::WorkPoster;
/// Different possible definitions for pending transaction set.
#[derive(Debug)]
pub enum PendingSet {
/// Always just the transactions in the queue. These have had only cheap checks.
AlwaysQueue,
/// Always just the transactions in the sealing block. These have had full checks but
/// may be empty if the node is not actively mining or has force_sealing enabled.
AlwaysSealing,
/// Try the sealing block, but if it is not currently sealing, fallback to the queue.
SealingOrElseQueue,
}
/// Configures the behaviour of the miner.
#[derive(Debug)]
pub struct MinerOptions {
/// URLs to notify when there is new work.
pub new_work_notify: Vec<String>,
/// Force the miner to reseal, even when nobody has asked for work.
pub force_sealing: bool,
/// Reseal on receipt of new external transactions.
pub reseal_on_external_tx: bool,
/// Reseal on receipt of new local transactions.
pub reseal_on_own_tx: bool,
/// Minimum period between transaction-inspired reseals.
pub reseal_min_period: Duration,
/// Maximum amount of gas to bother considering for block insertion.
pub tx_gas_limit: U256,
/// Maximum size of the transaction queue.
pub tx_queue_size: usize,
/// 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,
}
impl Default for MinerOptions {
fn default() -> Self {
MinerOptions {
new_work_notify: vec![],
force_sealing: false,
reseal_on_external_tx: true,
reseal_on_own_tx: true,
tx_gas_limit: !U256::zero(),
tx_queue_size: 1024,
pending_set: PendingSet::AlwaysQueue,
reseal_min_period: Duration::from_secs(0),
work_queue_size: 20,
enable_resubmission: true,
}
}
}
struct SealingWork {
queue: UsingQueue<ClosedBlock>,
enabled: bool,
}
/// Keeps track of transactions using priority queue and holds currently mined block.
pub struct Miner {
// NOTE [ToDr] When locking always lock in this order!
transaction_queue: Mutex<TransactionQueue>,
sealing_work: Mutex<UsingQueue<ClosedBlock>>,
sealing_work: Mutex<SealingWork>,
// for sealing...
force_sealing: bool,
sealing_enabled: AtomicBool,
options: MinerOptions,
next_allowed_reseal: Mutex<Instant>,
sealing_block_last_request: Mutex<u64>,
gas_floor_target: RwLock<U256>,
gas_range_target: RwLock<(U256, U256)>,
author: RwLock<Address>,
extra_data: RwLock<Bytes>,
spec: Spec,
accounts: Option<Arc<AccountProvider>>,
}
impl Default for Miner {
fn default() -> Miner {
Miner {
transaction_queue: Mutex::new(TransactionQueue::new()),
force_sealing: false,
sealing_enabled: AtomicBool::new(false),
sealing_block_last_request: Mutex::new(0),
sealing_work: Mutex::new(UsingQueue::new(5)),
gas_floor_target: RwLock::new(U256::zero()),
author: RwLock::new(Address::default()),
extra_data: RwLock::new(Vec::new()),
accounts: None,
spec: Spec::new_test(),
}
}
work_poster: Option<WorkPoster>,
}
impl Miner {
/// Creates new instance of miner
pub fn new(force_sealing: bool, spec: Spec) -> Arc<Miner> {
Arc::new(Miner {
/// Creates new instance of miner without accounts, but with given spec.
pub fn with_spec(spec: Spec) -> Miner {
Miner {
transaction_queue: Mutex::new(TransactionQueue::new()),
force_sealing: force_sealing,
sealing_enabled: AtomicBool::new(force_sealing),
options: Default::default(),
next_allowed_reseal: Mutex::new(Instant::now()),
sealing_block_last_request: Mutex::new(0),
sealing_work: Mutex::new(UsingQueue::new(5)),
gas_floor_target: RwLock::new(U256::zero()),
sealing_work: Mutex::new(SealingWork{queue: UsingQueue::new(20), enabled: false}),
gas_range_target: RwLock::new((U256::zero(), U256::zero())),
author: RwLock::new(Address::default()),
extra_data: RwLock::new(Vec::new()),
accounts: None,
spec: spec,
})
work_poster: None,
}
}
/// Creates new instance of miner
pub fn with_accounts(force_sealing: bool, spec: Spec, accounts: Arc<AccountProvider>) -> Arc<Miner> {
pub fn new(options: MinerOptions, 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 };
Arc::new(Miner {
transaction_queue: Mutex::new(TransactionQueue::new()),
force_sealing: force_sealing,
sealing_enabled: AtomicBool::new(force_sealing),
transaction_queue: Mutex::new(TransactionQueue::with_limits(options.tx_queue_size, options.tx_gas_limit)),
next_allowed_reseal: Mutex::new(Instant::now()),
sealing_block_last_request: Mutex::new(0),
sealing_work: Mutex::new(UsingQueue::new(5)),
gas_floor_target: RwLock::new(U256::zero()),
sealing_work: Mutex::new(SealingWork{queue: UsingQueue::new(options.work_queue_size), enabled: options.force_sealing || !options.new_work_notify.is_empty()}),
gas_range_target: RwLock::new((U256::zero(), U256::zero())),
author: RwLock::new(Address::default()),
extra_data: RwLock::new(Vec::new()),
accounts: Some(accounts),
options: options,
accounts: accounts,
spec: spec,
work_poster: work_poster,
})
}
@@ -101,15 +151,30 @@ impl Miner {
self.spec.engine.deref()
}
fn forced_sealing(&self) -> bool {
self.options.force_sealing || !self.options.new_work_notify.is_empty()
}
/// Get `Some` `clone()` of the current pending block's state or `None` if we're not sealing.
pub fn pending_state(&self) -> Option<State> {
self.sealing_work.lock().unwrap().queue.peek_last_ref().map(|b| b.block().fields().state.clone())
}
/// Get `Some` `clone()` of the current pending block's state or `None` if we're not sealing.
pub fn pending_block(&self) -> Option<Block> {
self.sealing_work.lock().unwrap().queue.peek_last_ref().map(|b| b.base().clone())
}
/// Prepares new block for sealing including top transactions from queue.
#[cfg_attr(feature="dev", allow(match_same_arms))]
#[cfg_attr(feature="dev", allow(cyclomatic_complexity))]
fn prepare_sealing(&self, chain: &MiningBlockChainClient) {
trace!(target: "miner", "prepare_sealing: entering");
let (transactions, mut open_block) = {
let (transactions, mut open_block, original_work_hash) = {
let transactions = {self.transaction_queue.lock().unwrap().top_transactions()};
let mut sealing_work = self.sealing_work.lock().unwrap();
let last_work_hash = sealing_work.queue.peek_last_ref().map(|pb| pb.block().fields().header.hash());
let best_hash = chain.best_block_header().sha3();
/*
// check to see if last ClosedBlock in would_seals is actually same parent block.
@@ -119,7 +184,7 @@ impl Miner {
// otherwise, leave everything alone.
// otherwise, author a fresh block.
*/
let open_block = match sealing_work.pop_if(|b| b.block().fields().header.parent_hash() == &best_hash) {
let open_block = match sealing_work.queue.pop_if(|b| b.block().fields().header.parent_hash() == &best_hash) {
Some(old_block) => {
trace!(target: "miner", "Already have previous work; updating and returning");
// add transactions to old_block
@@ -131,12 +196,12 @@ impl Miner {
trace!(target: "miner", "No existing work - making new block");
chain.prepare_open_block(
self.author(),
self.gas_floor_target(),
(self.gas_floor_target(), self.gas_ceil_target()),
self.extra_data()
)
}
};
(transactions, open_block)
(transactions, open_block, last_work_hash)
};
let mut invalid_transactions = HashSet::new();
@@ -146,17 +211,23 @@ impl Miner {
let hash = tx.hash();
match open_block.push_transaction(tx, None) {
Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, .. })) => {
trace!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?}", hash);
debug!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?}", 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 {
break;
}
},
Err(Error::Transaction(TransactionError::AlreadyImported)) => {} // already have transaction - ignore
// 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);
},
// already have transaction - ignore
Err(Error::Transaction(TransactionError::AlreadyImported)) => {},
Err(e) => {
invalid_transactions.insert(hash);
trace!(target: "miner",
debug!(target: "miner",
"Error adding transaction to block: number={}. transaction_hash={:?}, Error: {:?}",
block_number, hash, e);
},
@@ -202,13 +273,31 @@ impl Miner {
}
}
let mut sealing_work = self.sealing_work.lock().unwrap();
if sealing_work.peek_last_ref().map_or(true, |pb| pb.block().fields().header.hash() != block.block().fields().header.hash()) {
trace!(target: "miner", "Pushing a new, refreshed or borrowed pending {}...", block.block().fields().header.hash());
sealing_work.push(block);
let (work, is_new) = {
let mut sealing_work = self.sealing_work.lock().unwrap();
let last_work_hash = sealing_work.queue.peek_last_ref().map(|pb| pb.block().fields().header.hash());
trace!(target: "miner", "Checking whether we need to reseal: orig={:?} last={:?}, this={:?}", original_work_hash, last_work_hash, block.block().fields().header.hash());
let (work, is_new) = if last_work_hash.map_or(true, |h| h != block.block().fields().header.hash()) {
trace!(target: "miner", "Pushing a new, refreshed or borrowed pending {}...", block.block().fields().header.hash());
let pow_hash = block.block().fields().header.hash();
let number = block.block().fields().header.number();
let difficulty = *block.block().fields().header.difficulty();
let is_new = original_work_hash.map_or(true, |h| block.block().fields().header.hash() != h);
sealing_work.queue.push(block);
// If push notifications are enabled we assume all work items are used.
if self.work_poster.is_some() && is_new {
sealing_work.queue.use_last_ref();
}
(Some((pow_hash, difficulty, number)), is_new)
} else {
(None, false)
};
trace!(target: "miner", "prepare_sealing: leaving (last={:?})", sealing_work.queue.peek_last_ref().map(|b| b.block().fields().header.hash()));
(work, is_new)
};
if is_new {
work.map(|(pow_hash, difficulty, number)| self.work_poster.as_ref().map(|ref p| p.notify(pow_hash, difficulty, number)));
}
trace!(target: "miner", "prepare_sealing: leaving (last={:?})", sealing_work.peek_last_ref().map(|b| b.block().fields().header.hash()));
}
fn update_gas_limit(&self, chain: &MiningBlockChainClient) {
@@ -220,10 +309,22 @@ impl Miner {
/// Returns true if we had to prepare new pending block
fn enable_and_prepare_sealing(&self, chain: &MiningBlockChainClient) -> bool {
trace!(target: "miner", "enable_and_prepare_sealing: entering");
let have_work = self.sealing_work.lock().unwrap().peek_last_ref().is_some();
trace!(target: "miner", "enable_and_prepare_sealing: have_work={}", have_work);
if !have_work {
self.sealing_enabled.store(true, atomic::Ordering::Relaxed);
let prepare_new = {
let mut sealing_work = self.sealing_work.lock().unwrap();
let have_work = sealing_work.queue.peek_last_ref().is_some();
trace!(target: "miner", "enable_and_prepare_sealing: have_work={}", have_work);
if !have_work {
sealing_work.enabled = true;
true
} else {
false
}
};
if prepare_new {
// --------------------------------------------------------------------------
// | NOTE Code below requires transaction_queue and sealing_work locks. |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
self.prepare_sealing(chain);
}
let mut sealing_block_last_request = self.sealing_block_last_request.lock().unwrap();
@@ -233,9 +334,25 @@ impl Miner {
*sealing_block_last_request = best_number;
}
// Return if
!have_work
// Return if we restarted
prepare_new
}
fn add_transactions_to_queue(&self, chain: &MiningBlockChainClient, transactions: Vec<SignedTransaction>, origin: TransactionOrigin, transaction_queue: &mut TransactionQueue) ->
Vec<Result<TransactionImportResult, Error>> {
let fetch_account = |a: &Address| AccountDetails {
nonce: chain.latest_nonce(a),
balance: chain.latest_balance(a),
};
transactions.into_iter()
.map(|tx| transaction_queue.add(tx, &fetch_account, origin))
.collect()
}
/// Are we allowed to do a non-mandatory reseal?
fn tx_reseal_allowed(&self) -> bool { Instant::now() > *self.next_allowed_reseal.lock().unwrap() }
}
const SEALING_TIMEOUT_IN_BLOCKS : u64 = 5;
@@ -244,6 +361,10 @@ impl MinerService for Miner {
fn clear_and_reset(&self, chain: &MiningBlockChainClient) {
self.transaction_queue.lock().unwrap().clear();
// --------------------------------------------------------------------------
// | NOTE Code below requires transaction_queue and sealing_work locks. |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
self.update_sealing(chain);
}
@@ -253,13 +374,13 @@ impl MinerService for Miner {
MinerStatus {
transactions_in_pending_queue: status.pending,
transactions_in_future_queue: status.future,
transactions_in_pending_block: sealing_work.peek_last_ref().map_or(0, |b| b.transactions().len()),
transactions_in_pending_block: sealing_work.queue.peek_last_ref().map_or(0, |b| b.transactions().len()),
}
}
fn call(&self, chain: &MiningBlockChainClient, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, ExecutionError> {
let sealing_work = self.sealing_work.lock().unwrap();
match sealing_work.peek_last_ref() {
match sealing_work.queue.peek_last_ref() {
Some(work) => {
let block = work.block();
@@ -274,7 +395,6 @@ impl MinerService for Miner {
last_hashes: last_hashes,
gas_used: U256::zero(),
gas_limit: U256::max_value(),
dao_rescue_block_gas_limit: chain.dao_rescue_block_gas_limit(header.parent_hash().clone()),
};
// that's just a copy of the state.
let mut state = block.state().clone();
@@ -307,7 +427,7 @@ impl MinerService for Miner {
fn balance(&self, chain: &MiningBlockChainClient, address: &Address) -> U256 {
let sealing_work = self.sealing_work.lock().unwrap();
sealing_work.peek_last_ref().map_or_else(
sealing_work.queue.peek_last_ref().map_or_else(
|| chain.latest_balance(address),
|b| b.block().fields().state.balance(address)
)
@@ -315,7 +435,7 @@ impl MinerService for Miner {
fn storage_at(&self, chain: &MiningBlockChainClient, address: &Address, position: &H256) -> H256 {
let sealing_work = self.sealing_work.lock().unwrap();
sealing_work.peek_last_ref().map_or_else(
sealing_work.queue.peek_last_ref().map_or_else(
|| chain.latest_storage_at(address, position),
|b| b.block().fields().state.storage_at(address, position)
)
@@ -323,12 +443,12 @@ impl MinerService for Miner {
fn nonce(&self, chain: &MiningBlockChainClient, address: &Address) -> U256 {
let sealing_work = self.sealing_work.lock().unwrap();
sealing_work.peek_last_ref().map_or_else(|| chain.latest_nonce(address), |b| b.block().fields().state.nonce(address))
sealing_work.queue.peek_last_ref().map_or_else(|| 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().unwrap();
sealing_work.peek_last_ref().map_or_else(|| chain.code(address), |b| b.block().fields().state.code(address))
sealing_work.queue.peek_last_ref().map_or_else(|| chain.code(address), |b| b.block().fields().state.code(address))
}
fn set_author(&self, author: Address) {
@@ -341,7 +461,11 @@ impl MinerService for Miner {
/// Set the gas limit we wish to target when sealing a new block.
fn set_gas_floor_target(&self, target: U256) {
*self.gas_floor_target.write().unwrap() = target;
self.gas_range_target.write().unwrap().0 = target;
}
fn set_gas_ceil_target(&self, target: U256) {
self.gas_range_target.write().unwrap().1 = target;
}
fn set_minimal_gas_price(&self, min_gas_price: U256) {
@@ -358,7 +482,7 @@ impl MinerService for Miner {
}
fn sensible_gas_limit(&self) -> U256 {
*self.gas_floor_target.read().unwrap() / 5.into()
self.gas_range_target.read().unwrap().0 / 5.into()
}
fn transactions_limit(&self) -> usize {
@@ -369,6 +493,10 @@ impl MinerService for Miner {
self.transaction_queue.lock().unwrap().set_limit(limit)
}
fn set_tx_gas_limit(&self, limit: U256) {
self.transaction_queue.lock().unwrap().set_tx_gas_limit(limit)
}
/// Get the author that we will seal blocks as.
fn author(&self) -> Address {
*self.author.read().unwrap()
@@ -381,30 +509,39 @@ impl MinerService for Miner {
/// Get the gas limit we wish to target when sealing a new block.
fn gas_floor_target(&self) -> U256 {
*self.gas_floor_target.read().unwrap()
self.gas_range_target.read().unwrap().0
}
fn import_transactions<T>(&self, chain: &MiningBlockChainClient, transactions: Vec<SignedTransaction>, fetch_account: T) ->
Vec<Result<TransactionImportResult, Error>>
where T: Fn(&Address) -> AccountDetails {
let results: Vec<Result<TransactionImportResult, Error>> = {
/// Get the gas limit we wish to target when sealing a new block.
fn gas_ceil_target(&self) -> U256 {
self.gas_range_target.read().unwrap().1
}
fn import_external_transactions(&self, chain: &MiningBlockChainClient, transactions: Vec<SignedTransaction>) ->
Vec<Result<TransactionImportResult, Error>> {
let results = {
let mut transaction_queue = self.transaction_queue.lock().unwrap();
transactions.into_iter()
.map(|tx| transaction_queue.add(tx, &fetch_account, TransactionOrigin::External))
.collect()
self.add_transactions_to_queue(
chain, transactions, TransactionOrigin::External, &mut transaction_queue
)
};
if !results.is_empty() {
if !results.is_empty() && self.options.reseal_on_external_tx && self.tx_reseal_allowed() {
// --------------------------------------------------------------------------
// | NOTE Code below requires transaction_queue and sealing_work locks. |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
self.update_sealing(chain);
}
results
}
fn import_own_transaction<T>(
fn import_own_transaction(
&self,
chain: &MiningBlockChainClient,
transaction: SignedTransaction,
fetch_account: T
) -> Result<TransactionImportResult, Error> where T: Fn(&Address) -> AccountDetails {
) -> Result<TransactionImportResult, Error> {
let hash = transaction.hash();
trace!(target: "own_tx", "Importing transaction: {:?}", transaction);
@@ -412,7 +549,7 @@ impl MinerService for Miner {
let imported = {
// Be sure to release the lock before we call enable_and_prepare_sealing
let mut transaction_queue = self.transaction_queue.lock().unwrap();
let import = transaction_queue.add(transaction, &fetch_account, TransactionOrigin::Local);
let import = self.add_transactions_to_queue(chain, vec![transaction], TransactionOrigin::Local, &mut transaction_queue).pop().unwrap();
match import {
Ok(ref res) => {
@@ -428,7 +565,11 @@ impl MinerService for Miner {
import
};
if imported.is_ok() {
// --------------------------------------------------------------------------
// | NOTE Code below requires transaction_queue and sealing_work locks. |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
if imported.is_ok() && self.options.reseal_on_own_tx && self.tx_reseal_allowed() {
// Make sure to do it after transaction is imported and lock is droped.
// We need to create pending block and enable sealing
let prepared = self.enable_and_prepare_sealing(chain);
@@ -442,26 +583,6 @@ impl MinerService for Miner {
imported
}
fn pending_transactions_hashes(&self) -> Vec<H256> {
let queue = self.transaction_queue.lock().unwrap();
match (self.sealing_enabled.load(atomic::Ordering::Relaxed), self.sealing_work.lock().unwrap().peek_last_ref()) {
(true, Some(pending)) => pending.transactions().iter().map(|t| t.hash()).collect(),
_ => {
queue.pending_hashes()
}
}
}
fn transaction(&self, hash: &H256) -> Option<SignedTransaction> {
let queue = self.transaction_queue.lock().unwrap();
match (self.sealing_enabled.load(atomic::Ordering::Relaxed), self.sealing_work.lock().unwrap().peek_last_ref()) {
(true, Some(pending)) => pending.transactions().iter().find(|t| &t.hash() == hash).cloned(),
_ => {
queue.find(hash)
}
}
}
fn all_transactions(&self) -> Vec<SignedTransaction> {
let queue = self.transaction_queue.lock().unwrap();
queue.top_transactions()
@@ -469,17 +590,47 @@ impl MinerService for Miner {
fn pending_transactions(&self) -> Vec<SignedTransaction> {
let queue = self.transaction_queue.lock().unwrap();
let sw = self.sealing_work.lock().unwrap();
// TODO: should only use the sealing_work when it's current (it could be an old block)
match (self.sealing_enabled.load(atomic::Ordering::Relaxed), self.sealing_work.lock().unwrap().peek_last_ref()) {
(true, Some(pending)) => pending.transactions().clone(),
_ => {
queue.top_transactions()
}
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().clone()),
}
}
fn pending_transactions_hashes(&self) -> Vec<H256> {
let queue = self.transaction_queue.lock().unwrap();
let sw = self.sealing_work.lock().unwrap();
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()),
}
}
fn transaction(&self, hash: &H256) -> Option<SignedTransaction> {
let queue = self.transaction_queue.lock().unwrap();
let sw = self.sealing_work.lock().unwrap();
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()),
}
}
fn pending_receipts(&self) -> BTreeMap<H256, Receipt> {
match (self.sealing_enabled.load(atomic::Ordering::Relaxed), self.sealing_work.lock().unwrap().peek_last_ref()) {
let sealing_work = self.sealing_work.lock().unwrap();
match (sealing_work.enabled, sealing_work.queue.peek_last_ref()) {
(true, Some(pending)) => {
let hashes = pending.transactions()
.iter()
@@ -498,22 +649,43 @@ impl MinerService for Miner {
}
fn update_sealing(&self, chain: &MiningBlockChainClient) {
if self.sealing_enabled.load(atomic::Ordering::Relaxed) {
let current_no = chain.chain_info().best_block_number;
let has_local_transactions = self.transaction_queue.lock().unwrap().has_local_pending_transactions();
let last_request = *self.sealing_block_last_request.lock().unwrap();
let should_disable_sealing = !self.force_sealing
&& !has_local_transactions
&& current_no > last_request
&& current_no - last_request > SEALING_TIMEOUT_IN_BLOCKS;
trace!(target: "miner", "update_sealing");
let requires_reseal = {
let mut sealing_work = self.sealing_work.lock().unwrap();
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().unwrap().has_local_pending_transactions();
let last_request = *self.sealing_block_last_request.lock().unwrap();
let should_disable_sealing = !self.forced_sealing()
&& !has_local_transactions
&& current_no > last_request
&& current_no - last_request > SEALING_TIMEOUT_IN_BLOCKS;
if should_disable_sealing {
trace!(target: "miner", "Miner sleeping (current {}, last {})", current_no, last_request);
self.sealing_enabled.store(false, atomic::Ordering::Relaxed);
self.sealing_work.lock().unwrap().reset();
trace!(target: "miner", "update_sealing: should_disable_sealing={}; current_no={}, last_request={}", should_disable_sealing, current_no, last_request);
if should_disable_sealing {
trace!(target: "miner", "Miner sleeping (current {}, last {})", current_no, last_request);
sealing_work.enabled = false;
sealing_work.queue.reset();
false
} else {
// sealing enabled and we don't want to sleep.
*self.next_allowed_reseal.lock().unwrap() = Instant::now() + self.options.reseal_min_period;
true
}
} else {
self.prepare_sealing(chain);
// sealing is disabled.
false
}
};
if requires_reseal {
// --------------------------------------------------------------------------
// | NOTE Code below requires transaction_queue and sealing_work locks. |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
self.prepare_sealing(chain);
}
}
@@ -522,42 +694,45 @@ impl MinerService for Miner {
self.enable_and_prepare_sealing(chain);
trace!(target: "miner", "map_sealing_work: sealing prepared");
let mut sealing_work = self.sealing_work.lock().unwrap();
let ret = sealing_work.use_last_ref();
let ret = sealing_work.queue.use_last_ref();
trace!(target: "miner", "map_sealing_work: leaving use_last_ref={:?}", ret.as_ref().map(|b| b.block().fields().header.hash()));
ret.map(f)
}
fn submit_seal(&self, chain: &MiningBlockChainClient, pow_hash: H256, seal: Vec<Bytes>) -> Result<(), Error> {
if let Some(b) = self.sealing_work.lock().unwrap().take_used_if(|b| &b.hash() == &pow_hash) {
match b.lock().try_seal(self.engine(), seal) {
Err(_) => {
info!(target: "miner", "Mined block rejected, PoW was invalid.");
Err(Error::PowInvalid)
}
Ok(sealed) => {
info!(target: "miner", "New block mined, hash: {}", sealed.header().hash());
// TODO: commit DB from `sealed.drain` and make a VerifiedBlock to skip running the transactions twice.
let b = sealed.rlp_bytes();
let h = b.sha3();
try!(chain.import_block(b));
info!("Block {} submitted and imported.", h);
Ok(())
}
}
let result = if let Some(b) = self.sealing_work.lock().unwrap().queue.get_used_if(if self.options.enable_resubmission { GetAction::Clone } else { GetAction::Take }, |b| &b.hash() == &pow_hash) {
b.lock().try_seal(self.engine(), seal).or_else(|_| {
warn!(target: "miner", "Mined solution rejected: Invalid.");
Err(Error::PowInvalid)
})
} else {
info!(target: "miner", "Mined block rejected, PoW hash invalid or out of date.");
warn!(target: "miner", "Mined solution rejected: Block unknown or out of date.");
Err(Error::PowHashInvalid)
}
};
result.and_then(|sealed| {
let n = sealed.header().number();
let h = sealed.header().hash();
try!(chain.import_sealed_block(sealed));
info!(target: "miner", "Mined block imported OK. #{}: {}", paint(White.bold(), format!("{}", n)), paint(White.bold(), h.hex()));
Ok(())
})
}
fn chain_new_blocks(&self, chain: &MiningBlockChainClient, _imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256]) {
trace!(target: "miner", "chain_new_blocks");
fn fetch_transactions(chain: &MiningBlockChainClient, hash: &H256) -> Vec<SignedTransaction> {
let block = chain
.block(BlockID::Hash(*hash))
// Client should send message after commit to db and inserting to chain.
.expect("Expected in-chain blocks.");
let block = BlockView::new(&block);
block.transactions()
let txs = block.transactions();
// populate sender
for tx in &txs {
let _sender = tx.sender();
}
txs
}
// 1. We ignore blocks that were `imported` (because it means that they are not in canon-chain, and transactions
@@ -574,14 +749,9 @@ impl MinerService for Miner {
.par_iter()
.map(|h| fetch_transactions(chain, h));
out_of_chain.for_each(|txs| {
// populate sender
for tx in &txs {
let _sender = tx.sender();
}
let _ = self.import_transactions(chain, txs, |a| AccountDetails {
nonce: chain.latest_nonce(a),
balance: chain.latest_balance(a),
});
let mut transaction_queue = self.transaction_queue.lock().unwrap();
let _ = self.add_transactions_to_queue(chain, txs, TransactionOrigin::External,
&mut transaction_queue);
});
}
@@ -605,7 +775,13 @@ impl MinerService for Miner {
});
}
self.update_sealing(chain);
if enacted.len() > 0 {
// --------------------------------------------------------------------------
// | NOTE Code below requires transaction_queue and sealing_work locks. |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
self.update_sealing(chain);
}
}
}
@@ -617,6 +793,7 @@ mod tests {
use util::*;
use client::{TestBlockChainClient, EachBlockWith};
use block::*;
use spec::Spec;
// TODO [ToDr] To uncomment` when TestBlockChainClient can actually return a ClosedBlock.
#[ignore]
@@ -624,7 +801,7 @@ mod tests {
fn should_prepare_block_to_seal() {
// given
let client = TestBlockChainClient::default();
let miner = Miner::default();
let miner = Miner::with_spec(Spec::new_test());
// when
let sealing_work = miner.map_sealing_work(&client, |_| ());
@@ -636,7 +813,7 @@ mod tests {
fn should_still_work_after_a_couple_of_blocks() {
// given
let client = TestBlockChainClient::default();
let miner = Miner::default();
let miner = Miner::with_spec(Spec::new_test());
let res = miner.map_sealing_work(&client, |b| b.block().fields().header.hash());
assert!(res.is_some());

View File

@@ -28,11 +28,12 @@
//! extern crate ethcore;
//! use std::env;
//! use util::network::{NetworkService, NetworkConfiguration};
//! use ethcore::ethereum;
//! use ethcore::client::{Client, ClientConfig};
//! use ethcore::miner::{Miner, MinerService};
//!
//! fn main() {
//! let miner: Miner = Miner::default();
//! let miner: Miner = Miner::with_spec(ethereum::new_frontier());
//! // get status
//! assert_eq!(miner.status().transactions_in_pending_queue, 0);
//!
@@ -44,9 +45,10 @@
mod miner;
mod external;
mod transaction_queue;
mod work_notify;
pub use self::transaction_queue::{TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin};
pub use self::miner::{Miner};
pub use self::miner::{Miner, MinerOptions, PendingSet};
pub use self::external::{ExternalMiner, ExternalMinerService};
use std::collections::BTreeMap;
@@ -81,27 +83,35 @@ pub trait MinerService : Send + Sync {
/// Set minimal gas price of transaction to be accepted for mining.
fn set_minimal_gas_price(&self, min_gas_price: U256);
/// Get the gas limit we wish to target when sealing a new block.
/// Get the lower bound of the gas limit we wish to target when sealing a new block.
fn gas_floor_target(&self) -> U256;
/// Set the gas limit we wish to target when sealing a new block.
/// Get the upper bound of the gas limit we wish to target when sealing a new block.
fn gas_ceil_target(&self) -> U256;
// TODO: coalesce into single set_range function.
/// Set the lower bound of gas limit we wish to target when sealing a new block.
fn set_gas_floor_target(&self, target: U256);
/// Set the upper bound of gas limit we wish to target when sealing a new block.
fn set_gas_ceil_target(&self, target: U256);
/// Get current transactions limit in queue.
fn transactions_limit(&self) -> usize;
/// Set maximal number of transactions kept in the queue (both current and future).
fn set_transactions_limit(&self, limit: usize);
/// Set maximum amount of gas allowed for any single transaction to mine.
fn set_tx_gas_limit(&self, limit: U256);
/// Imports transactions to transaction queue.
fn import_transactions<T>(&self, chain: &MiningBlockChainClient, transactions: Vec<SignedTransaction>, fetch_account: T) ->
Vec<Result<TransactionImportResult, Error>>
where T: Fn(&Address) -> AccountDetails, Self: Sized;
fn import_external_transactions(&self, chain: &MiningBlockChainClient, transactions: Vec<SignedTransaction>) ->
Vec<Result<TransactionImportResult, Error>>;
/// Imports own (node owner) transaction to queue.
fn import_own_transaction<T>(&self, chain: &MiningBlockChainClient, transaction: SignedTransaction, fetch_account: T) ->
Result<TransactionImportResult, Error>
where T: Fn(&Address) -> AccountDetails, Self: Sized;
fn import_own_transaction(&self, chain: &MiningBlockChainClient, transaction: SignedTransaction) ->
Result<TransactionImportResult, Error>;
/// Returns hashes of transactions currently in pending
fn pending_transactions_hashes(&self) -> Vec<H256>;

View File

@@ -334,6 +334,8 @@ const GAS_LIMIT_HYSTERESIS: usize = 10; // %
pub struct TransactionQueue {
/// Gas Price threshold for transactions that can be imported to this queue (defaults to 0)
minimal_gas_price: U256,
/// The maximum amount of gas any individual transaction may use.
tx_gas_limit: U256,
/// Current gas limit (block gas limit * factor). Transactions above the limit will not be accepted (default to !0)
gas_limit: U256,
/// Priority queue for transactions that can go to block
@@ -355,11 +357,11 @@ impl Default for TransactionQueue {
impl TransactionQueue {
/// Creates new instance of this Queue
pub fn new() -> Self {
Self::with_limit(1024)
Self::with_limits(1024, !U256::zero())
}
/// Create new instance of this Queue with specified limits
pub fn with_limit(limit: usize) -> Self {
pub fn with_limits(limit: usize, tx_gas_limit: U256) -> Self {
let current = TransactionSet {
by_priority: BTreeSet::new(),
by_address: Table::new(),
@@ -374,6 +376,7 @@ impl TransactionQueue {
TransactionQueue {
minimal_gas_price: U256::zero(),
tx_gas_limit: tx_gas_limit,
gas_limit: !U256::zero(),
current: current,
future: future,
@@ -418,6 +421,12 @@ impl TransactionQueue {
};
}
/// Set the new limit for the amount of gas any individual transaction may have.
/// Any transaction already imported to the queue is not affected.
pub fn set_tx_gas_limit(&mut self, limit: U256) {
self.tx_gas_limit = limit;
}
/// Returns current status for this queue
pub fn status(&self) -> TransactionQueueStatus {
TransactionQueueStatus {
@@ -430,12 +439,14 @@ impl TransactionQueue {
pub fn add<T>(&mut self, tx: SignedTransaction, fetch_account: &T, origin: TransactionOrigin) -> Result<TransactionImportResult, Error>
where T: Fn(&Address) -> AccountDetails {
trace!(target: "miner", "Importing: {:?}", tx.hash());
trace!(target: "txqueue", "Importing: {:?}", tx.hash());
if tx.gas_price < self.minimal_gas_price {
trace!(target: "miner",
if tx.gas_price < self.minimal_gas_price && origin != TransactionOrigin::Local {
trace!(target: "txqueue",
"Dropping transaction below minimal gas price threshold: {:?} (gp: {} < {})",
tx.hash(), tx.gas_price, self.minimal_gas_price
tx.hash(),
tx.gas_price,
self.minimal_gas_price
);
return Err(Error::Transaction(TransactionError::InsufficientGasPrice {
@@ -446,10 +457,13 @@ impl TransactionQueue {
try!(tx.check_low_s());
if tx.gas > self.gas_limit {
trace!(target: "miner",
"Dropping transaction above gas limit: {:?} ({} > {})",
tx.hash(), tx.gas, self.gas_limit
if tx.gas > self.gas_limit || tx.gas > self.tx_gas_limit {
trace!(target: "txqueue",
"Dropping transaction above gas limit: {:?} ({} > min({}, {}))",
tx.hash(),
tx.gas,
self.gas_limit,
self.tx_gas_limit
);
return Err(Error::Transaction(TransactionError::GasLimitExceeded {
@@ -463,8 +477,13 @@ impl TransactionQueue {
let cost = vtx.transaction.value + vtx.transaction.gas_price * vtx.transaction.gas;
if client_account.balance < cost {
trace!(target: "miner", "Dropping transaction without sufficient balance: {:?} ({} < {})",
vtx.hash(), client_account.balance, cost);
trace!(target: "txqueue",
"Dropping transaction without sufficient balance: {:?} ({} < {})",
vtx.hash(),
client_account.balance,
cost
);
return Err(Error::Transaction(TransactionError::InsufficientBalance {
cost: cost,
balance: client_account.balance
@@ -546,7 +565,7 @@ impl TransactionQueue {
if k >= current_nonce {
self.future.insert(*sender, k, order.update_height(k, current_nonce));
} else {
trace!(target: "miner", "Removing old transaction: {:?} (nonce: {} < {})", order.hash, k, current_nonce);
trace!(target: "txqueue", "Removing old transaction: {:?} (nonce: {} < {})", order.hash, k, current_nonce);
// Remove the transaction completely
self.by_hash.remove(&order.hash).expect("All transactions in `future` are also in `by_hash`");
}
@@ -567,7 +586,7 @@ impl TransactionQueue {
if k >= current_nonce {
self.future.insert(*sender, k, order.update_height(k, current_nonce));
} else {
trace!(target: "miner", "Removing old transaction: {:?} (nonce: {} < {})", order.hash, k, current_nonce);
trace!(target: "txqueue", "Removing old transaction: {:?} (nonce: {} < {})", order.hash, k, current_nonce);
self.by_hash.remove(&order.hash).expect("All transactions in `future` are also in `by_hash`");
}
}
@@ -655,7 +674,7 @@ impl TransactionQueue {
if self.by_hash.get(&tx.hash()).is_some() {
// Transaction is already imported.
trace!(target: "miner", "Dropping already imported transaction: {:?}", tx.hash());
trace!(target: "txqueue", "Dropping already imported transaction: {:?}", tx.hash());
return Err(TransactionError::AlreadyImported);
}
@@ -672,7 +691,7 @@ impl TransactionQueue {
// nonce height would result in overflow.
if nonce < state_nonce {
// Droping transaction
trace!(target: "miner", "Dropping old transaction: {:?} (nonce: {} < {})", tx.hash(), nonce, next_nonce);
trace!(target: "txqueue", "Dropping old transaction: {:?} (nonce: {} < {})", tx.hash(), nonce, next_nonce);
return Err(TransactionError::Old);
} else if nonce > next_nonce {
// We have a gap - put to future.
@@ -708,7 +727,7 @@ impl TransactionQueue {
// Trigger error if the transaction we are importing was removed.
try!(check_if_removed(&address, &nonce, removed));
trace!(target: "miner", "status: {:?}", self.status());
trace!(target: "txqueue", "status: {:?}", self.status());
Ok(TransactionImportResult::Current)
}
@@ -1036,7 +1055,7 @@ mod test {
}
#[test]
fn should_not_import_transaction_below_min_gas_price_threshold() {
fn should_not_import_transaction_below_min_gas_price_threshold_if_external() {
// given
let mut txq = TransactionQueue::new();
let tx = new_tx();
@@ -1055,6 +1074,23 @@ mod test {
assert_eq!(stats.future, 0);
}
#[test]
fn should_import_transaction_below_min_gas_price_threshold_if_local() {
// given
let mut txq = TransactionQueue::new();
let tx = new_tx();
txq.set_minimal_gas_price(tx.gas_price + U256::one());
// when
let res = txq.add(tx, &default_nonce, TransactionOrigin::Local);
// then
assert_eq!(res.unwrap(), TransactionImportResult::Current);
let stats = txq.status();
assert_eq!(stats.pending, 1);
assert_eq!(stats.future, 0);
}
#[test]
fn should_reject_incorectly_signed_transaction() {
// given
@@ -1288,7 +1324,7 @@ mod test {
#[test]
fn should_drop_old_transactions_when_hitting_the_limit() {
// given
let mut txq = TransactionQueue::with_limit(1);
let mut txq = TransactionQueue::with_limits(1, !U256::zero());
let (tx, tx2) = new_txs(U256::one());
let sender = tx.sender().unwrap();
let nonce = tx.nonce;
@@ -1310,7 +1346,7 @@ mod test {
#[test]
fn should_return_correct_nonces_when_dropped_because_of_limit() {
// given
let mut txq = TransactionQueue::with_limit(2);
let mut txq = TransactionQueue::with_limits(2, !U256::zero());
let tx = new_tx();
let (tx1, tx2) = new_txs(U256::one());
let sender = tx1.sender().unwrap();
@@ -1331,7 +1367,7 @@ mod test {
#[test]
fn should_limit_future_transactions() {
let mut txq = TransactionQueue::with_limit(1);
let mut txq = TransactionQueue::with_limits(1, !U256::zero());
txq.current.set_limit(10);
let (tx1, tx2) = new_txs_with_gas_price_diff(U256::from(4), U256::from(1));
let (tx3, tx4) = new_txs_with_gas_price_diff(U256::from(4), U256::from(2));
@@ -1591,7 +1627,7 @@ mod test {
#[test]
fn should_keep_right_order_in_future() {
// given
let mut txq = TransactionQueue::with_limit(1);
let mut txq = TransactionQueue::with_limits(1, !U256::zero());
let (tx1, tx2) = new_txs(U256::from(1));
let prev_nonce = |a: &Address| AccountDetails { nonce: default_nonce(a).nonce - U256::one(), balance:
default_nonce(a).balance };

View File

@@ -0,0 +1,115 @@
// 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/>.
extern crate hyper;
use hyper::header::ContentType;
use hyper::method::Method;
use hyper::client::{Request, Response, Client};
use hyper::{Next};
use hyper::net::HttpStream;
use ethash::SeedHashCompute;
use hyper::Url;
use util::*;
use ethereum::ethash::Ethash;
pub struct WorkPoster {
urls: Vec<Url>,
client: Mutex<Client<PostHandler>>,
seed_compute: Mutex<SeedHashCompute>,
}
impl WorkPoster {
pub fn new(urls: &[String]) -> Self {
let urls = urls.into_iter().filter_map(|u| {
match Url::parse(&u) {
Ok(url) => Some(url),
Err(e) => {
warn!("Error parsing URL {} : {}", u, e);
None
}
}
}).collect();
let client = WorkPoster::create_client();
WorkPoster {
client: Mutex::new(client),
urls: urls,
seed_compute: Mutex::new(SeedHashCompute::new()),
}
}
fn create_client() -> Client<PostHandler> {
let client = Client::<PostHandler>::configure()
.keep_alive(true)
.build().expect("Error creating HTTP client") as Client<PostHandler>;
client
}
pub fn notify(&self, pow_hash: H256, difficulty: U256, number: u64) {
// TODO: move this to engine
let target = Ethash::difficulty_to_boundary(&difficulty);
let seed_hash = &self.seed_compute.lock().unwrap().get_seedhash(number);
let seed_hash = H256::from_slice(&seed_hash[..]);
let body = format!(r#"{{ "result": ["0x{}","0x{}","0x{}","0x{:x}"] }}"#,
pow_hash.hex(), seed_hash.hex(), target.hex(), number);
let mut client = self.client.lock().unwrap();
for u in &self.urls {
if let Err(e) = client.request(u.clone(), PostHandler { body: body.clone() }) {
warn!("Error sending HTTP notification to {} : {}, retrying", u, e);
// TODO: remove this once https://github.com/hyperium/hyper/issues/848 is fixed
*client = WorkPoster::create_client();
if let Err(e) = client.request(u.clone(), PostHandler { body: body.clone() }) {
warn!("Error sending HTTP notification to {} : {}", u, e);
}
}
}
}
}
struct PostHandler {
body: String,
}
impl hyper::client::Handler<HttpStream> for PostHandler {
fn on_request(&mut self, request: &mut Request) -> Next {
request.set_method(Method::Post);
request.headers_mut().set(ContentType::json());
Next::write()
}
fn on_request_writable(&mut self, encoder: &mut hyper::Encoder<HttpStream>) -> Next {
if let Err(e) = encoder.write_all(self.body.as_bytes()) {
trace!("Error posting work data: {}", e);
}
encoder.close();
Next::read()
}
fn on_response(&mut self, _response: Response) -> Next {
Next::end()
}
fn on_response_readable(&mut self, _decoder: &mut hyper::Decoder<HttpStream>) -> Next {
Next::end()
}
fn on_error(&mut self, err: hyper::Error) -> Next {
trace!("Error posting work data: {}", err);
Next::end()
}
}

View File

@@ -28,8 +28,8 @@ pub struct PodAccount {
pub balance: U256,
/// The nonce of the account.
pub nonce: U256,
/// The code of the account.
pub code: Bytes,
/// The code of the account or `None` in the special case that it is unknown.
pub code: Option<Bytes>,
/// The storage of the account.
pub storage: BTreeMap<H256, H256>,
}
@@ -38,7 +38,7 @@ impl PodAccount {
/// Construct new object.
#[cfg(test)]
pub fn new(balance: U256, nonce: U256, code: Bytes, storage: BTreeMap<H256, H256>) -> PodAccount {
PodAccount { balance: balance, nonce: nonce, code: code, storage: storage }
PodAccount { balance: balance, nonce: nonce, code: Some(code), storage: storage }
}
/// Convert Account to a PodAccount.
@@ -48,7 +48,7 @@ impl 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}),
code: acc.code().unwrap().to_vec(),
code: acc.code().map(|x| x.to_vec()),
}
}
@@ -58,14 +58,15 @@ impl PodAccount {
stream.append(&self.nonce);
stream.append(&self.balance);
stream.append(&sec_trie_root(self.storage.iter().map(|(k, v)| (k.to_vec(), encode(&U256::from(v.as_slice())).to_vec())).collect()));
stream.append(&self.code.sha3());
stream.append(&self.code.as_ref().unwrap_or(&vec![]).sha3());
stream.out()
}
/// Place additional data into given hash DB.
pub fn insert_additional(&self, db: &mut AccountDBMut) {
if !self.code.is_empty() {
db.insert(&self.code);
match self.code {
Some(ref c) if !c.is_empty() => { db.insert(c); }
_ => {}
}
let mut r = H256::new();
let mut t = SecTrieDBMut::new(db, &mut r);
@@ -80,7 +81,7 @@ impl From<ethjson::blockchain::Account> for PodAccount {
PodAccount {
balance: a.balance.into(),
nonce: a.nonce.into(),
code: a.code.into(),
code: Some(a.code.into()),
storage: a.storage.into_iter().map(|(key, value)| {
let key: U256 = key.into();
let value: U256 = value.into();
@@ -95,7 +96,7 @@ impl From<ethjson::spec::Account> for PodAccount {
PodAccount {
balance: a.balance.map_or_else(U256::zero, Into::into),
nonce: a.nonce.map_or_else(U256::zero, Into::into),
code: vec![],
code: Some(vec![]),
storage: BTreeMap::new()
}
}
@@ -103,7 +104,13 @@ impl From<ethjson::spec::Account> for PodAccount {
impl fmt::Display for PodAccount {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(bal={}; nonce={}; code={} bytes, #{}; storage={} items)", self.balance, self.nonce, self.code.len(), self.code.sha3(), self.storage.len())
write!(f, "(bal={}; nonce={}; code={} bytes, #{}; storage={} items)",
self.balance,
self.nonce,
self.code.as_ref().map_or(0, |c| c.len()),
self.code.as_ref().map_or_else(H256::new, |c| c.sha3()),
self.storage.len()
)
}
}
@@ -114,13 +121,13 @@ pub fn diff_pod(pre: Option<&PodAccount>, post: Option<&PodAccount>) -> Option<A
(None, Some(x)) => Some(AccountDiff {
balance: Diff::Born(x.balance),
nonce: Diff::Born(x.nonce),
code: Diff::Born(x.code.clone()),
code: Diff::Born(x.code.as_ref().expect("account is newly created; newly created accounts must be given code; all caches should remain in place; qed").clone()),
storage: x.storage.iter().map(|(k, v)| (k.clone(), Diff::Born(v.clone()))).collect(),
}),
(Some(x), None) => Some(AccountDiff {
balance: Diff::Died(x.balance),
nonce: Diff::Died(x.nonce),
code: Diff::Died(x.code.clone()),
code: Diff::Died(x.code.as_ref().expect("account is deleted; only way to delete account is running SUICIDE; account must have had own code cached to make operation; all caches should remain in place; qed").clone()),
storage: x.storage.iter().map(|(k, v)| (k.clone(), Diff::Died(v.clone()))).collect(),
}),
(Some(pre), Some(post)) => {
@@ -130,7 +137,10 @@ pub fn diff_pod(pre: Option<&PodAccount>, post: Option<&PodAccount>) -> Option<A
let r = AccountDiff {
balance: Diff::new(pre.balance, post.balance),
nonce: Diff::new(pre.nonce, post.nonce),
code: Diff::new(pre.code.clone(), post.code.clone()),
code: match (pre.code.clone(), post.code.clone()) {
(Some(pre_code), Some(post_code)) => Diff::new(pre_code, post_code),
_ => Diff::Same,
},
storage: storage.into_iter().map(|k|
(k.clone(), Diff::new(
pre.storage.get(&k).cloned().unwrap_or_else(H256::new),
@@ -156,7 +166,7 @@ mod test {
#[test]
fn existence() {
let a = PodAccount{balance: 69.into(), nonce: 0.into(), code: vec![], storage: map![]};
let a = PodAccount{balance: 69.into(), nonce: 0.into(), code: Some(vec![]), storage: map![]};
assert_eq!(diff_pod(Some(&a), Some(&a)), None);
assert_eq!(diff_pod(None, Some(&a)), Some(AccountDiff{
balance: Diff::Born(69.into()),
@@ -168,8 +178,8 @@ mod test {
#[test]
fn basic() {
let a = PodAccount{balance: 69.into(), nonce: 0.into(), code: vec![], storage: map![]};
let b = PodAccount{balance: 42.into(), nonce: 1.into(), code: vec![], storage: map![]};
let a = PodAccount{balance: 69.into(), nonce: 0.into(), code: Some(vec![]), storage: map![]};
let b = PodAccount{balance: 42.into(), nonce: 1.into(), code: Some(vec![]), storage: map![]};
assert_eq!(diff_pod(Some(&a), Some(&b)), Some(AccountDiff {
balance: Diff::Changed(69.into(), 42.into()),
nonce: Diff::Changed(0.into(), 1.into()),
@@ -180,8 +190,8 @@ mod test {
#[test]
fn code() {
let a = PodAccount{balance: 0.into(), nonce: 0.into(), code: vec![], storage: map![]};
let b = PodAccount{balance: 0.into(), nonce: 1.into(), code: vec![0], storage: map![]};
let a = PodAccount{balance: 0.into(), nonce: 0.into(), code: Some(vec![]), storage: map![]};
let b = PodAccount{balance: 0.into(), nonce: 1.into(), code: Some(vec![0]), storage: map![]};
assert_eq!(diff_pod(Some(&a), Some(&b)), Some(AccountDiff {
balance: Diff::Same,
nonce: Diff::Changed(0.into(), 1.into()),
@@ -195,13 +205,13 @@ mod test {
let a = PodAccount {
balance: 0.into(),
nonce: 0.into(),
code: vec![],
code: Some(vec![]),
storage: map_into![1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 0, 6 => 0, 7 => 0]
};
let b = PodAccount {
balance: 0.into(),
nonce: 0.into(),
code: vec![],
code: Some(vec![]),
storage: map_into![1 => 1, 2 => 3, 3 => 0, 5 => 0, 7 => 7, 8 => 0, 9 => 9]
};
assert_eq!(diff_pod(Some(&a), Some(&b)), Some(AccountDiff {

View File

@@ -17,6 +17,7 @@
//! Creates and registers client and network services.
use util::*;
use util::Colour::{Yellow, White};
use util::panics::*;
use spec::Spec;
use error::*;
@@ -36,6 +37,8 @@ pub enum SyncMessage {
retracted: Vec<H256>,
/// Hashes of blocks that are now included in cannonical chain
enacted: Vec<H256>,
/// Hashes of blocks that are sealed by this node
sealed: Vec<H256>,
},
/// Best Block Hash in chain has been changed
NewChainHead,
@@ -69,8 +72,7 @@ impl ClientService {
try!(net_service.start());
}
info!("Starting {}", net_service.host_info());
info!("Configured for {} using {:?} engine", spec.name, spec.engine.name());
info!("Configured for {} using {} engine", paint(White.bold(), spec.name.clone()), paint(Yellow.bold(), spec.engine.name().to_owned()));
let client = try!(Client::new(config, spec, db_path, miner, net_service.io().channel()));
panic_handler.forward_from(client.deref());
let client_io = Arc::new(ClientIoHandler {
@@ -159,9 +161,15 @@ mod tests {
#[test]
fn it_can_be_started() {
let spec = get_test_spec();
let temp_path = RandomTempPath::new();
let service = ClientService::start(ClientConfig::default(), spec, NetworkConfiguration::new_local(), &temp_path.as_path(), Arc::new(Miner::default()), false);
let service = ClientService::start(
ClientConfig::default(),
get_test_spec(),
NetworkConfiguration::new_local(),
&temp_path.as_path(),
Arc::new(Miner::with_spec(get_test_spec())),
false
);
assert!(service.is_ok());
}
}

View File

@@ -38,6 +38,8 @@ pub struct CommonParams {
pub network_id: U256,
/// Minimum gas limit.
pub min_gas_limit: U256,
/// Fork block to check.
pub fork_block: Option<(BlockNumber, H256)>,
}
impl From<ethjson::spec::Params> for CommonParams {
@@ -47,6 +49,7 @@ impl From<ethjson::spec::Params> for CommonParams {
maximum_extra_data_size: p.maximum_extra_data_size.into(),
network_id: p.network_id.into(),
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 },
}
}
}
@@ -148,6 +151,9 @@ impl Spec {
/// Get the configured Network ID.
pub fn network_id(&self) -> U256 { self.params.network_id }
/// Get the configured network fork block.
pub fn fork_block(&self) -> Option<(BlockNumber, H256)> { self.params.fork_block }
/// Get the header of the genesis block.
pub fn genesis_header(&self) -> Header {
Header {

View File

@@ -19,7 +19,7 @@ use engine::Engine;
use executive::{Executive, TransactOptions};
use evm::Factory as EvmFactory;
use account_db::*;
use trace::Trace;
use trace::FlatTrace;
use pod_account::*;
use pod_state::{self, PodState};
use types::state_diff::StateDiff;
@@ -29,7 +29,7 @@ pub struct ApplyOutcome {
/// The receipt for the applied transaction.
pub receipt: Receipt,
/// The trace for the applied transaction, if None if tracing is disabled.
pub trace: Option<Trace>,
pub trace: Vec<FlatTrace>,
}
/// Result type for the execution ("application") of a transaction.
@@ -208,12 +208,17 @@ impl State {
self.require(a, false).set_storage(key, value)
}
/// Initialise the code of account `a` so that it is `value` for `key`.
/// Initialise the code of account `a` so that it is `code`.
/// NOTE: Account should have been created with `new_contract`.
pub fn init_code(&mut self, a: &Address, code: Bytes) {
self.require_or_from(a, true, || Account::new_contract(0.into(), self.account_start_nonce), |_|{}).init_code(code);
}
/// Reset the code of account `a` so that it is `code`.
pub fn reset_code(&mut self, a: &Address, code: Bytes) {
self.require_or_from(a, true, || Account::new_contract(0.into(), self.account_start_nonce), |_|{}).reset_code(code);
}
/// Execute a given transaction.
/// This will change the state accordingly.
pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, vm_factory: &EvmFactory, t: &SignedTransaction, tracing: bool) -> ApplyResult {
@@ -222,30 +227,6 @@ impl State {
let options = TransactOptions { tracing: tracing, vm_tracing: false, check_nonce: true };
let e = try!(Executive::new(self, env_info, engine, vm_factory).transact(t, options));
let broken_dao = H256::from("6a5d24750f78441e56fec050dc52fe8e911976485b7472faac7464a176a67caa");
// dao attack soft fork
if engine.schedule(&env_info).reject_dao_transactions {
let whitelisted = if let Action::Call(to) = t.action {
to == Address::from("Da4a4626d3E16e094De3225A751aAb7128e96526") ||
to == Address::from("2ba9D006C1D72E67A70b5526Fc6b4b0C0fd6D334")
} else { false };
if !whitelisted {
// collect all the addresses which have changed.
let addresses = self.cache.borrow().iter().map(|(addr, _)| addr.clone()).collect::<Vec<_>>();
for a in &addresses {
if self.code(a).map_or(false, |c| c.sha3() == broken_dao) {
// Figure out if the balance has been reduced.
let maybe_original = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR).get(&a).map(Account::from_rlp);
if maybe_original.map_or(false, |original| *original.balance() > self.balance(a)) {
return Err(Error::Transaction(TransactionError::DAORescue));
}
}
}
}
}
// TODO uncomment once to_pod() works correctly.
// trace!("Applied transaction. Diff:\n{}\n", state_diff::diff_pod(&old, &self.to_pod()));
self.commit();
@@ -408,7 +389,8 @@ use spec::*;
use transaction::*;
use util::log::init_log;
use trace::trace;
use trace::trace::{Trace};
use trace::FlatTrace;
use types::executed::CallType;
#[test]
fn should_apply_create_transaction() {
@@ -433,8 +415,9 @@ fn should_apply_create_transaction() {
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace {
depth: 0,
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
subtraces: 0,
action: trace::Action::Create(trace::Create {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
value: 100.into(),
@@ -446,8 +429,7 @@ fn should_apply_create_transaction() {
address: Address::from_str("8988167e088c87cd314df6d3c2b83da5acb93ace").unwrap(),
code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53]
}),
subs: vec![]
});
}];
assert_eq!(result.trace, expected_trace);
}
@@ -494,8 +476,8 @@ fn should_trace_failed_create_transaction() {
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace {
depth: 0,
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
action: trace::Action::Create(trace::Create {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
value: 100.into(),
@@ -503,8 +485,8 @@ fn should_trace_failed_create_transaction() {
init: vec![91, 96, 0, 86],
}),
result: trace::Res::FailedCreate,
subs: vec![]
});
subtraces: 0
}];
assert_eq!(result.trace, expected_trace);
}
@@ -533,21 +515,22 @@ fn should_trace_call_transaction() {
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace {
depth: 0,
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(),
value: 100.into(),
gas: 79000.into(),
input: vec![],
call_type: CallType::Call,
}),
result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(3),
output: vec![]
}),
subs: vec![]
});
subtraces: 0,
}];
assert_eq!(result.trace, expected_trace);
}
@@ -575,21 +558,22 @@ fn should_trace_basic_call_transaction() {
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace {
depth: 0,
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(),
value: 100.into(),
gas: 79000.into(),
input: vec![],
call_type: CallType::Call,
}),
result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(0),
output: vec![]
}),
subs: vec![]
});
subtraces: 0,
}];
assert_eq!(result.trace, expected_trace);
}
@@ -617,21 +601,24 @@ fn should_trace_call_transaction_to_builtin() {
let vm_factory = Default::default();
let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap();
assert_eq!(result.trace, Some(Trace {
depth: 0,
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: "0000000000000000000000000000000000000001".into(),
value: 0.into(),
gas: 79_000.into(),
input: vec![],
call_type: CallType::Call,
}),
result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(3000),
output: vec![]
}),
subs: vec![]
}));
subtraces: 0,
}];
assert_eq!(result.trace, expected_trace);
}
#[test]
@@ -658,21 +645,23 @@ fn should_not_trace_subcall_transaction_to_builtin() {
let vm_factory = Default::default();
let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace {
depth: 0,
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(),
value: 0.into(),
gas: 79000.into(),
input: vec![],
call_type: CallType::Call,
}),
result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(28_061),
output: vec![]
}),
subs: vec![]
});
subtraces: 0,
}];
assert_eq!(result.trace, expected_trace);
}
@@ -701,21 +690,38 @@ fn should_not_trace_callcode() {
let vm_factory = Default::default();
let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace {
depth: 0,
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
subtraces: 1,
action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(),
value: 0.into(),
gas: 79000.into(),
input: vec![],
call_type: CallType::Call,
}),
result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(64),
gas_used: 64.into(),
output: vec![]
}),
subs: vec![]
});
}, FlatTrace {
trace_address: vec![0].into_iter().collect(),
subtraces: 0,
action: trace::Action::Call(trace::Call {
from: 0xa.into(),
to: 0xa.into(),
value: 0.into(),
gas: 4096.into(),
input: vec![],
call_type: CallType::CallCode,
}),
result: trace::Res::Call(trace::CallResult {
gas_used: 3.into(),
output: vec![],
}),
}];
assert_eq!(result.trace, expected_trace);
}
@@ -747,21 +753,38 @@ fn should_not_trace_delegatecall() {
let vm_factory = Default::default();
let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace {
depth: 0,
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
subtraces: 1,
action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(),
value: 0.into(),
gas: 79000.into(),
input: vec![],
call_type: CallType::Call,
}),
result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(61),
output: vec![]
}),
subs: vec![]
});
}, FlatTrace {
trace_address: vec![0].into_iter().collect(),
subtraces: 0,
action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(),
value: 0.into(),
gas: 32768.into(),
input: vec![],
call_type: CallType::DelegateCall,
}),
result: trace::Res::Call(trace::CallResult {
gas_used: 3.into(),
output: vec![],
}),
}];
assert_eq!(result.trace, expected_trace);
}
@@ -789,20 +812,19 @@ fn should_trace_failed_call_transaction() {
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace {
depth: 0,
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(),
value: 100.into(),
gas: 79000.into(),
input: vec![],
call_type: CallType::Call,
}),
result: trace::Res::FailedCall,
subs: vec![]
});
println!("trace: {:?}", result.trace);
subtraces: 0,
}];
assert_eq!(result.trace, expected_trace);
}
@@ -832,35 +854,38 @@ fn should_trace_call_with_subcall_transaction() {
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace {
depth: 0,
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
subtraces: 1,
action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(),
value: 100.into(),
gas: 79000.into(),
input: vec![],
call_type: CallType::Call,
}),
result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(69),
output: vec![]
}),
subs: vec![Trace {
depth: 1,
action: trace::Action::Call(trace::Call {
from: 0xa.into(),
to: 0xb.into(),
value: 0.into(),
gas: 78934.into(),
input: vec![],
}),
result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(3),
output: vec![]
}),
subs: vec![]
}]
});
}, FlatTrace {
trace_address: vec![0].into_iter().collect(),
subtraces: 0,
action: trace::Action::Call(trace::Call {
from: 0xa.into(),
to: 0xb.into(),
value: 0.into(),
gas: 78934.into(),
input: vec![],
call_type: CallType::Call,
}),
result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(3),
output: vec![]
}),
}];
assert_eq!(result.trace, expected_trace);
}
@@ -889,32 +914,34 @@ fn should_trace_call_with_basic_subcall_transaction() {
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace {
depth: 0,
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
subtraces: 1,
action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(),
value: 100.into(),
gas: 79000.into(),
input: vec![],
call_type: CallType::Call,
}),
result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(31761),
output: vec![]
}),
subs: vec![Trace {
depth: 1,
action: trace::Action::Call(trace::Call {
from: 0xa.into(),
to: 0xb.into(),
value: 69.into(),
gas: 2300.into(),
input: vec![],
}),
result: trace::Res::Call(trace::CallResult::default()),
subs: vec![]
}]
});
}, FlatTrace {
trace_address: vec![0].into_iter().collect(),
subtraces: 0,
action: trace::Action::Call(trace::Call {
from: 0xa.into(),
to: 0xb.into(),
value: 69.into(),
gas: 2300.into(),
input: vec![],
call_type: CallType::Call,
}),
result: trace::Res::Call(trace::CallResult::default()),
}];
assert_eq!(result.trace, expected_trace);
}
@@ -943,21 +970,22 @@ fn should_not_trace_call_with_invalid_basic_subcall_transaction() {
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace {
depth: 0,
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
subtraces: 0,
action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(),
value: 100.into(),
gas: 79000.into(),
input: vec![],
call_type: CallType::Call,
}),
result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(31761),
output: vec![]
}),
subs: vec![]
});
}];
assert_eq!(result.trace, expected_trace);
}
@@ -987,32 +1015,34 @@ fn should_trace_failed_subcall_transaction() {
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace {
depth: 0,
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
subtraces: 1,
action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(),
value: 100.into(),
gas: 79000.into(),
input: vec![],
call_type: CallType::Call,
}),
result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(79_000),
output: vec![]
}),
subs: vec![Trace {
depth: 1,
action: trace::Action::Call(trace::Call {
from: 0xa.into(),
to: 0xb.into(),
value: 0.into(),
gas: 78934.into(),
input: vec![],
}),
result: trace::Res::FailedCall,
subs: vec![]
}]
});
}, FlatTrace {
trace_address: vec![0].into_iter().collect(),
subtraces: 0,
action: trace::Action::Call(trace::Call {
from: 0xa.into(),
to: 0xb.into(),
value: 0.into(),
gas: 78934.into(),
input: vec![],
call_type: CallType::Call,
}),
result: trace::Res::FailedCall,
}];
assert_eq!(result.trace, expected_trace);
}
@@ -1043,49 +1073,52 @@ fn should_trace_call_with_subcall_with_subcall_transaction() {
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace {
depth: 0,
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
subtraces: 1,
action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(),
value: 100.into(),
gas: 79000.into(),
input: vec![],
call_type: CallType::Call,
}),
result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(135),
output: vec![]
}),
subs: vec![Trace {
depth: 1,
action: trace::Action::Call(trace::Call {
from: 0xa.into(),
to: 0xb.into(),
value: 0.into(),
gas: 78934.into(),
input: vec![],
}),
result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(69),
output: vec![]
}),
subs: vec![Trace {
depth: 2,
action: trace::Action::Call(trace::Call {
from: 0xb.into(),
to: 0xc.into(),
value: 0.into(),
gas: 78868.into(),
input: vec![],
}),
result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(3),
output: vec![]
}),
subs: vec![]
}]
}]
});
}, FlatTrace {
trace_address: vec![0].into_iter().collect(),
subtraces: 1,
action: trace::Action::Call(trace::Call {
from: 0xa.into(),
to: 0xb.into(),
value: 0.into(),
gas: 78934.into(),
input: vec![],
call_type: CallType::Call,
}),
result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(69),
output: vec![]
}),
}, FlatTrace {
trace_address: vec![0, 0].into_iter().collect(),
subtraces: 0,
action: trace::Action::Call(trace::Call {
from: 0xb.into(),
to: 0xc.into(),
value: 0.into(),
gas: 78868.into(),
input: vec![],
call_type: CallType::Call,
}),
result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(3),
output: vec![]
}),
}];
assert_eq!(result.trace, expected_trace);
}
@@ -1116,46 +1149,104 @@ fn should_trace_failed_subcall_with_subcall_transaction() {
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace {
depth: 0,
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
subtraces: 1,
action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(),
value: 100.into(),
gas: 79000.into(),
input: vec![],
call_type: CallType::Call,
}),
result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(79_000),
output: vec![]
}),
subs: vec![Trace {
depth: 1,
})
}, FlatTrace {
trace_address: vec![0].into_iter().collect(),
subtraces: 1,
action: trace::Action::Call(trace::Call {
from: 0xa.into(),
to: 0xb.into(),
value: 0.into(),
gas: 78934.into(),
input: vec![],
}),
result: trace::Res::FailedCall,
subs: vec![Trace {
depth: 2,
action: trace::Action::Call(trace::Call {
from: 0xb.into(),
to: 0xc.into(),
value: 0.into(),
gas: 78868.into(),
input: vec![],
}),
result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(3),
output: vec![]
}),
subs: vec![]
}]
}]
});
from: 0xa.into(),
to: 0xb.into(),
value: 0.into(),
gas: 78934.into(),
input: vec![],
call_type: CallType::Call,
}),
result: trace::Res::FailedCall,
}, FlatTrace {
trace_address: vec![0, 0].into_iter().collect(),
subtraces: 0,
action: trace::Action::Call(trace::Call {
from: 0xb.into(),
to: 0xc.into(),
value: 0.into(),
gas: 78868.into(),
call_type: CallType::Call,
input: vec![],
}),
result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(3),
output: vec![]
}),
}];
assert_eq!(result.trace, expected_trace);
}
#[test]
fn should_trace_suicide() {
init_log();
let temp = RandomTempPath::new();
let mut state = get_temp_state_in(temp.as_path());
let mut info = EnvInfo::default();
info.gas_limit = 1_000_000.into();
let engine = TestEngine::new(5);
let t = Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 100_000.into(),
action: Action::Call(0xa.into()),
value: 100.into(),
data: vec![],
}.sign(&"".sha3());
state.init_code(&0xa.into(), FromHex::from_hex("73000000000000000000000000000000000000000bff").unwrap());
state.add_balance(&0xa.into(), &50.into());
state.add_balance(t.sender().as_ref().unwrap(), &100.into());
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
subtraces: 1,
action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(),
value: 100.into(),
gas: 79000.into(),
input: vec![],
call_type: CallType::Call,
}),
result: trace::Res::Call(trace::CallResult {
gas_used: 3.into(),
output: vec![]
}),
}, FlatTrace {
trace_address: vec![0].into_iter().collect(),
subtraces: 0,
action: trace::Action::Suicide(trace::Suicide {
address: 0xa.into(),
refund_address: 0xb.into(),
balance: 150.into(),
}),
result: trace::Res::None,
}];
assert_eq!(result.trace, expected_trace);
}

View File

@@ -24,7 +24,7 @@ use miner::Miner;
#[test]
fn imports_from_empty() {
let dir = RandomTempPath::new();
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap();
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::with_spec(get_test_spec())), IoChannel::disconnected()).unwrap();
client.import_verified_blocks(&IoChannel::disconnected());
client.flush_queue();
}
@@ -42,7 +42,7 @@ fn returns_state_root_basic() {
#[test]
fn imports_good_block() {
let dir = RandomTempPath::new();
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap();
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::with_spec(get_test_spec())), IoChannel::disconnected()).unwrap();
let good_block = get_good_dummy_block();
if let Err(_) = client.import_block(good_block) {
panic!("error importing block being good by definition");
@@ -57,7 +57,7 @@ fn imports_good_block() {
#[test]
fn query_none_block() {
let dir = RandomTempPath::new();
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap();
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::with_spec(get_test_spec())), IoChannel::disconnected()).unwrap();
let non_existant = client.block_header(BlockID::Number(188));
assert!(non_existant.is_none());
@@ -150,7 +150,7 @@ fn can_mine() {
let client_result = get_test_client_with_blocks(vec![dummy_blocks[0].clone()]);
let client = client_result.reference();
let b = client.prepare_open_block(Address::default(), 31415926.into(), vec![]).close();
let b = client.prepare_open_block(Address::default(), (3141562.into(), 31415620.into()), vec![]).close();
assert_eq!(*b.block().header().parent_hash(), BlockView::new(&dummy_blocks[0]).header_view().sha3());
}

View File

@@ -17,7 +17,7 @@
use client::{BlockChainClient, Client, ClientConfig};
use common::*;
use spec::*;
use block::{OpenBlock};
use block::{OpenBlock, Drain};
use blockchain::{BlockChain, Config as BlockChainConfig};
use state::*;
use evm::Schedule;
@@ -30,6 +30,7 @@ use miner::Miner;
pub enum ChainEra {
Frontier,
Homestead,
DaoHardfork,
}
#[cfg(test)]
@@ -151,7 +152,7 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
let dir = RandomTempPath::new();
let test_spec = get_test_spec();
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap();
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::with_spec(get_test_spec())), IoChannel::disconnected()).unwrap();
let test_engine = &test_spec.engine;
let mut db_result = get_temp_journal_db();
@@ -179,9 +180,8 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
db,
&last_header,
last_hashes.clone(),
None,
author.clone(),
3141562.into(),
(3141562.into(), 31415620.into()),
vec![]
).unwrap();
b.set_difficulty(U256::from(0x20000));
@@ -250,7 +250,7 @@ pub fn push_blocks_to_client(client: &Arc<Client>, timestamp_salt: u64, starting
pub fn get_test_client_with_blocks(blocks: Vec<Bytes>) -> GuardedTempResult<Arc<Client>> {
let dir = RandomTempPath::new();
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap();
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::with_spec(get_test_spec())), IoChannel::disconnected()).unwrap();
for block in &blocks {
if let Err(_) = client.import_block(block.clone()) {
panic!("panic importing block which is well-formed");
@@ -303,7 +303,7 @@ pub fn generate_dummy_empty_blockchain() -> GuardedTempResult<BlockChain> {
pub fn get_temp_journal_db() -> GuardedTempResult<Box<JournalDB>> {
let temp = RandomTempPath::new();
let journal_db = journaldb::new(temp.as_str(), journaldb::Algorithm::EarlyMerge, None);
let journal_db = journaldb::new(temp.as_str(), journaldb::Algorithm::EarlyMerge, DatabaseConfig::default());
GuardedTempResult {
_temp: temp,
result: Some(journal_db)
@@ -320,7 +320,7 @@ pub fn get_temp_state() -> GuardedTempResult<State> {
}
pub fn get_temp_journal_db_in(path: &Path) -> Box<JournalDB> {
journaldb::new(path.to_str().unwrap(), journaldb::Algorithm::EarlyMerge, None)
journaldb::new(path.to_str().unwrap(), journaldb::Algorithm::EarlyMerge, DatabaseConfig::default())
}
pub fn get_temp_state_in(path: &Path) -> State {

View File

@@ -1,58 +0,0 @@
// 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 util::rlp::*;
use basic_types::LogBloom;
use super::Trace;
/// Traces created by transactions from the same block.
#[derive(Clone)]
pub struct BlockTraces(Vec<Trace>);
impl From<Vec<Trace>> for BlockTraces {
fn from(traces: Vec<Trace>) -> Self {
BlockTraces(traces)
}
}
impl Into<Vec<Trace>> for BlockTraces {
fn into(self) -> Vec<Trace> {
self.0
}
}
impl Decodable for BlockTraces {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let traces = try!(Decodable::decode(decoder));
let block_traces = BlockTraces(traces);
Ok(block_traces)
}
}
impl Encodable for BlockTraces {
fn rlp_append(&self, s: &mut RlpStream) {
Encodable::rlp_append(&self.0, s)
}
}
impl BlockTraces {
/// Returns bloom of all traces in given block.
pub fn bloom(&self) -> LogBloom {
self.0.iter()
.fold(LogBloom::default(), |acc, trace| acc | trace.bloom())
}
}

View File

@@ -15,7 +15,6 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Trace database.
use std::ptr;
use std::ops::{Deref, DerefMut};
use std::collections::HashMap;
use std::sync::{RwLock, Arc};
@@ -24,7 +23,7 @@ use bloomchain::{Number, Config as BloomConfig};
use bloomchain::group::{BloomGroupDatabase, BloomGroupChain, GroupPosition, BloomGroup};
use util::{H256, H264, Database, DatabaseConfig, DBTransaction};
use header::BlockNumber;
use trace::{BlockTraces, LocalizedTrace, Config, Switch, Filter, Database as TraceDatabase, ImportRequest,
use trace::{LocalizedTrace, Config, Switch, Filter, Database as TraceDatabase, ImportRequest,
DatabaseExtras, Error};
use db::{Key, Writable, Readable, CacheUpdatePolicy};
use blooms;
@@ -41,15 +40,13 @@ enum TraceDBIndex {
BloomGroups = 1,
}
impl Key<BlockTraces> for H256 {
impl Key<FlatBlockTraces> for H256 {
type Target = H264;
fn key(&self) -> H264 {
let mut result = H264::default();
result[0] = TraceDBIndex::BlockTraces as u8;
unsafe {
ptr::copy(self.as_ptr(), result.as_mut_ptr().offset(1), 32);
}
result[1..33].copy_from_slice(self);
result
}
}
@@ -84,9 +81,9 @@ impl Key<blooms::BloomGroup> for TraceGroupPosition {
result[0] = TraceDBIndex::BloomGroups as u8;
result[1] = self.0.level;
result[2] = self.0.index as u8;
result[3] = (self.0.index << 8) as u8;
result[4] = (self.0.index << 16) as u8;
result[5] = (self.0.index << 24) as u8;
result[3] = (self.0.index >> 8) as u8;
result[4] = (self.0.index >> 16) as u8;
result[5] = (self.0.index >> 24) as u8;
TraceGroupKey(result)
}
}
@@ -94,7 +91,7 @@ impl Key<blooms::BloomGroup> for TraceGroupPosition {
/// Trace database.
pub struct TraceDB<T> where T: DatabaseExtras {
// cache
traces: RwLock<HashMap<H256, BlockTraces>>,
traces: RwLock<HashMap<H256, FlatBlockTraces>>,
blooms: RwLock<HashMap<TraceGroupPosition, blooms::BloomGroup>>,
// db
tracesdb: Database,
@@ -156,15 +153,13 @@ impl<T> TraceDB<T> where T: DatabaseExtras {
}
/// Returns traces for block with hash.
fn traces(&self, block_hash: &H256) -> Option<BlockTraces> {
fn traces(&self, block_hash: &H256) -> Option<FlatBlockTraces> {
self.tracesdb.read_with_cache(&self.traces, block_hash)
}
/// Returns vector of transaction traces for given block.
fn transactions_traces(&self, block_hash: &H256) -> Option<Vec<FlatTransactionTraces>> {
self.traces(block_hash)
.map(FlatBlockTraces::from)
.map(Into::into)
self.traces(block_hash).map(Into::into)
}
fn matching_block_traces(
@@ -202,7 +197,7 @@ impl<T> TraceDB<T> where T: DatabaseExtras {
action: trace.action,
result: trace.result,
subtraces: trace.subtraces,
trace_address: trace.trace_address,
trace_address: trace.trace_address.into_iter().collect(),
transaction_number: tx_number,
transaction_hash: tx_hash.clone(),
block_number: block_number,
@@ -268,12 +263,13 @@ impl<T> TraceDatabase for TraceDB<T> where T: DatabaseExtras {
}
fn trace(&self, block_number: BlockNumber, tx_position: usize, trace_position: Vec<usize>) -> Option<LocalizedTrace> {
let trace_position_deq = trace_position.into_iter().collect();
self.extras.block_hash(block_number)
.and_then(|block_hash| self.transactions_traces(&block_hash)
.and_then(|traces| traces.into_iter().nth(tx_position))
.map(Into::<Vec<FlatTrace>>::into)
// this may and should be optimized
.and_then(|traces| traces.into_iter().find(|trace| trace.trace_address == trace_position))
.and_then(|traces| traces.into_iter().find(|trace| trace.trace_address == trace_position_deq))
.map(|trace| {
let tx_hash = self.extras.transaction_hash(block_number, tx_position)
.expect("Expected to find transaction hash. Database is probably corrupted");
@@ -282,7 +278,7 @@ impl<T> TraceDatabase for TraceDB<T> where T: DatabaseExtras {
action: trace.action,
result: trace.result,
subtraces: trace.subtraces,
trace_address: trace.trace_address,
trace_address: trace.trace_address.into_iter().collect(),
transaction_number: tx_position,
transaction_hash: tx_hash,
block_number: block_number,
@@ -306,7 +302,7 @@ impl<T> TraceDatabase for TraceDB<T> where T: DatabaseExtras {
action: trace.action,
result: trace.result,
subtraces: trace.subtraces,
trace_address: trace.trace_address,
trace_address: trace.trace_address.into_iter().collect(),
transaction_number: tx_position,
transaction_hash: tx_hash.clone(),
block_number: block_number,
@@ -333,7 +329,7 @@ impl<T> TraceDatabase for TraceDB<T> where T: DatabaseExtras {
action: trace.action,
result: trace.result,
subtraces: trace.subtraces,
trace_address: trace.trace_address,
trace_address: trace.trace_address.into_iter().collect(),
transaction_number: tx_position,
transaction_hash: tx_hash.clone(),
block_number: block_number,
@@ -356,8 +352,7 @@ impl<T> TraceDatabase for TraceDB<T> where T: DatabaseExtras {
.expect("Expected to find block hash. Extras db is probably corrupted");
let traces = self.traces(&hash)
.expect("Expected to find a trace. Db is probably corrupted.");
let flat_block = FlatBlockTraces::from(traces);
self.matching_block_traces(filter, flat_block, hash, number)
self.matching_block_traces(filter, traces, hash, number)
})
.collect()
}
@@ -371,8 +366,10 @@ mod tests {
use devtools::RandomTempPath;
use header::BlockNumber;
use trace::{Config, Switch, TraceDB, Database, DatabaseExtras, ImportRequest};
use trace::{BlockTraces, Trace, Filter, LocalizedTrace, AddressesFilter};
use trace::{Filter, LocalizedTrace, AddressesFilter};
use trace::trace::{Call, Action, Res};
use trace::flat::{FlatTrace, FlatBlockTraces, FlatTransactionTraces};
use types::executed::CallType;
struct NoopExtras;
@@ -386,6 +383,7 @@ mod tests {
}
}
#[derive(Clone)]
struct Extras {
block_hashes: HashMap<BlockNumber, H256>,
transaction_hashes: HashMap<BlockNumber, Vec<H256>>,
@@ -490,18 +488,19 @@ mod tests {
fn create_simple_import_request(block_number: BlockNumber, block_hash: H256) -> ImportRequest {
ImportRequest {
traces: BlockTraces::from(vec![Trace {
depth: 0,
traces: FlatBlockTraces::from(vec![FlatTransactionTraces::from(vec![FlatTrace {
trace_address: Default::default(),
subtraces: 0,
action: Action::Call(Call {
from: Address::from(1),
to: Address::from(2),
value: U256::from(3),
gas: U256::from(4),
from: 1.into(),
to: 2.into(),
value: 3.into(),
gas: 4.into(),
input: vec![],
call_type: CallType::Call,
}),
result: Res::FailedCall,
subs: vec![],
}]),
}])]),
block_hash: block_hash.clone(),
block_number: block_number,
enacted: vec![block_hash],
@@ -517,6 +516,7 @@ mod tests {
value: U256::from(3),
gas: U256::from(4),
input: vec![],
call_type: CallType::Call,
}),
result: Res::FailedCall,
trace_address: vec![],

View File

@@ -18,13 +18,53 @@
use util::{Bytes, Address, U256};
use action_params::ActionParams;
use trace::trace::{Trace, Call, Create, Action, Res, CreateResult, CallResult, VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff};
use trace::{Tracer, VMTracer};
use trace::trace::{Call, Create, Action, Res, CreateResult, CallResult, VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, Suicide};
use trace::{Tracer, VMTracer, FlatTrace};
/// Simple executive tracer. Traces all calls and creates. Ignores delegatecalls.
#[derive(Default)]
pub struct ExecutiveTracer {
traces: Vec<Trace>,
traces: Vec<FlatTrace>,
}
fn top_level_subtraces(traces: &[FlatTrace]) -> usize {
traces.iter().filter(|t| t.trace_address.is_empty()).count()
}
fn update_trace_address(traces: Vec<FlatTrace>) -> Vec<FlatTrace> {
// input traces are expected to be ordered like
// []
// [0]
// [0, 0]
// [0, 1]
// []
// [0]
//
// so they can be transformed to
//
// [0]
// [0, 0]
// [0, 0, 0]
// [0, 0, 1]
// [1]
// [1, 0]
let mut top_subtrace_index = 0;
let mut subtrace_subtraces_left = 0;
traces.into_iter().map(|mut trace| {
let is_top_subtrace = trace.trace_address.is_empty();
trace.trace_address.push_front(top_subtrace_index);
if is_top_subtrace {
subtrace_subtraces_left = trace.subtraces;
} else {
subtrace_subtraces_left -= 1;
}
if subtrace_subtraces_left == 0 {
top_subtrace_index += 1;
}
trace
}).collect()
}
impl Tracer for ExecutiveTracer {
@@ -40,59 +80,67 @@ impl Tracer for ExecutiveTracer {
Some(vec![])
}
fn trace_call(&mut self, call: Option<Call>, gas_used: U256, output: Option<Bytes>, depth: usize, subs: Vec<Trace>, delegate_call: bool) {
// don't trace if it's DELEGATECALL or CALLCODE.
if delegate_call {
return;
}
let trace = Trace {
depth: depth,
subs: subs,
fn trace_call(&mut self, call: Option<Call>, gas_used: U256, output: Option<Bytes>, subs: Vec<FlatTrace>) {
let trace = FlatTrace {
trace_address: Default::default(),
subtraces: top_level_subtraces(&subs),
action: Action::Call(call.expect("self.prepare_trace_call().is_some(): so we must be tracing: qed")),
result: Res::Call(CallResult {
gas_used: gas_used,
output: output.expect("self.prepare_trace_output().is_some(): so we must be tracing: qed")
})
}),
};
self.traces.push(trace);
self.traces.extend(update_trace_address(subs));
}
fn trace_create(&mut self, create: Option<Create>, gas_used: U256, code: Option<Bytes>, address: Address, depth: usize, subs: Vec<Trace>) {
let trace = Trace {
depth: depth,
subs: subs,
fn trace_create(&mut self, create: Option<Create>, gas_used: U256, code: Option<Bytes>, address: Address, subs: Vec<FlatTrace>) {
let trace = FlatTrace {
subtraces: top_level_subtraces(&subs),
action: Action::Create(create.expect("self.prepare_trace_create().is_some(): so we must be tracing: qed")),
result: Res::Create(CreateResult {
gas_used: gas_used,
code: code.expect("self.prepare_trace_output.is_some(): so we must be tracing: qed"),
address: address
})
}),
trace_address: Default::default(),
};
self.traces.push(trace);
self.traces.extend(update_trace_address(subs));
}
fn trace_failed_call(&mut self, call: Option<Call>, depth: usize, subs: Vec<Trace>, delegate_call: bool) {
// don't trace if it's DELEGATECALL or CALLCODE.
if delegate_call {
return;
}
let trace = Trace {
depth: depth,
subs: subs,
fn trace_failed_call(&mut self, call: Option<Call>, subs: Vec<FlatTrace>) {
let trace = FlatTrace {
trace_address: Default::default(),
subtraces: top_level_subtraces(&subs),
action: Action::Call(call.expect("self.prepare_trace_call().is_some(): so we must be tracing: qed")),
result: Res::FailedCall,
};
self.traces.push(trace);
self.traces.extend(update_trace_address(subs));
}
fn trace_failed_create(&mut self, create: Option<Create>, depth: usize, subs: Vec<Trace>) {
let trace = Trace {
depth: depth,
subs: subs,
fn trace_failed_create(&mut self, create: Option<Create>, subs: Vec<FlatTrace>) {
let trace = FlatTrace {
subtraces: top_level_subtraces(&subs),
action: Action::Create(create.expect("self.prepare_trace_create().is_some(): so we must be tracing: qed")),
result: Res::FailedCreate,
trace_address: Default::default(),
};
self.traces.push(trace);
self.traces.extend(update_trace_address(subs));
}
fn trace_suicide(&mut self, address: Address, balance: U256, refund_address: Address) {
let trace = FlatTrace {
subtraces: 0,
action: Action::Suicide(Suicide {
address: address,
refund_address: refund_address,
balance: balance,
}),
result: Res::None,
trace_address: Default::default(),
};
self.traces.push(trace);
}
@@ -101,7 +149,7 @@ impl Tracer for ExecutiveTracer {
ExecutiveTracer::default()
}
fn traces(self) -> Vec<Trace> {
fn traces(self) -> Vec<FlatTrace> {
self.traces
}
}

View File

@@ -1,183 +0,0 @@
// 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/>.
//! Flat trace module
use trace::BlockTraces;
use super::trace::{Trace, Action, Res};
/// Trace localized in vector of traces produced by a single transaction.
///
/// Parent and children indexes refer to positions in this vector.
pub struct FlatTrace {
/// Type of action performed by a transaction.
pub action: Action,
/// Result of this action.
pub result: Res,
/// Number of subtraces.
pub subtraces: usize,
/// Exact location of trace.
///
/// [index in root, index in first CALL, index in second CALL, ...]
pub trace_address: Vec<usize>,
}
/// Represents all traces produced by a single transaction.
pub struct FlatTransactionTraces(Vec<FlatTrace>);
impl Into<Vec<FlatTrace>> for FlatTransactionTraces {
fn into(self) -> Vec<FlatTrace> {
self.0
}
}
/// Represents all traces produced by transactions in a single block.
pub struct FlatBlockTraces(Vec<FlatTransactionTraces>);
impl From<BlockTraces> for FlatBlockTraces {
fn from(block_traces: BlockTraces) -> Self {
let traces: Vec<Trace> = block_traces.into();
let ordered = traces.into_iter()
.map(|trace| FlatBlockTraces::flatten(vec![], trace))
.map(FlatTransactionTraces)
.collect();
FlatBlockTraces(ordered)
}
}
impl Into<Vec<FlatTransactionTraces>> for FlatBlockTraces {
fn into(self) -> Vec<FlatTransactionTraces> {
self.0
}
}
impl FlatBlockTraces {
/// Helper function flattening nested tree structure to vector of ordered traces.
fn flatten(address: Vec<usize>, trace: Trace) -> Vec<FlatTrace> {
let subtraces = trace.subs.len();
let all_subs = trace.subs
.into_iter()
.enumerate()
.flat_map(|(index, subtrace)| {
let mut subtrace_address = address.clone();
subtrace_address.push(index);
FlatBlockTraces::flatten(subtrace_address, subtrace)
})
.collect::<Vec<_>>();
let ordered = FlatTrace {
action: trace.action,
result: trace.result,
subtraces: subtraces,
trace_address: address,
};
let mut result = vec![ordered];
result.extend(all_subs);
result
}
}
#[cfg(test)]
mod tests {
use super::{FlatBlockTraces, FlatTransactionTraces, FlatTrace};
use util::{U256, Address};
use trace::trace::{Action, Res, CallResult, Call, Create, Trace};
use trace::BlockTraces;
#[test]
fn test_block_from() {
let trace = Trace {
depth: 2,
action: Action::Call(Call {
from: Address::from(1),
to: Address::from(2),
value: U256::from(3),
gas: U256::from(4),
input: vec![0x5]
}),
subs: vec![
Trace {
depth: 3,
action: Action::Create(Create {
from: Address::from(6),
value: U256::from(7),
gas: U256::from(8),
init: vec![0x9]
}),
subs: vec![
Trace {
depth: 3,
action: Action::Create(Create {
from: Address::from(6),
value: U256::from(7),
gas: U256::from(8),
init: vec![0x9]
}),
subs: vec![
],
result: Res::FailedCreate
},
Trace {
depth: 3,
action: Action::Create(Create {
from: Address::from(6),
value: U256::from(7),
gas: U256::from(8),
init: vec![0x9]
}),
subs: vec![
],
result: Res::FailedCreate
}
],
result: Res::FailedCreate
},
Trace {
depth: 3,
action: Action::Create(Create {
from: Address::from(6),
value: U256::from(7),
gas: U256::from(8),
init: vec![0x9]
}),
subs: vec![],
result: Res::FailedCreate,
}
],
result: Res::Call(CallResult {
gas_used: U256::from(10),
output: vec![0x11, 0x12]
})
};
let block_traces = FlatBlockTraces::from(BlockTraces::from(vec![trace]));
let transaction_traces: Vec<FlatTransactionTraces> = block_traces.into();
assert_eq!(transaction_traces.len(), 1);
let ordered_traces: Vec<FlatTrace> = transaction_traces.into_iter().nth(0).unwrap().into();
assert_eq!(ordered_traces.len(), 5);
assert_eq!(ordered_traces[0].trace_address, vec![]);
assert_eq!(ordered_traces[0].subtraces, 2);
assert_eq!(ordered_traces[1].trace_address, vec![0]);
assert_eq!(ordered_traces[1].subtraces, 2);
assert_eq!(ordered_traces[2].trace_address, vec![0, 0]);
assert_eq!(ordered_traces[2].subtraces, 0);
assert_eq!(ordered_traces[3].trace_address, vec![0, 1]);
assert_eq!(ordered_traces[3].subtraces, 0);
assert_eq!(ordered_traces[4].trace_address, vec![1]);
assert_eq!(ordered_traces[4].subtraces, 0);
}
}

View File

@@ -17,12 +17,12 @@
//! Traces import request.
use util::H256;
use header::BlockNumber;
use trace::BlockTraces;
use trace::FlatBlockTraces;
/// Traces import request.
pub struct ImportRequest {
/// Traces to import.
pub traces: BlockTraces,
pub traces: FlatBlockTraces,
/// Hash of traces block.
pub block_hash: H256,
/// Number of traces block.

View File

@@ -16,22 +16,20 @@
//! Tracing
mod block;
mod bloom;
mod config;
mod db;
mod error;
mod executive_tracer;
pub mod flat;
mod import;
mod noop_tracer;
pub use types::trace_types::*;
pub use self::block::BlockTraces;
pub use self::config::{Config, Switch};
pub use self::db::TraceDB;
pub use self::error::Error;
pub use types::trace_types::trace::{Trace, VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff};
pub use types::trace_types::trace::{VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff};
pub use types::trace_types::flat::{FlatTrace, FlatTransactionTraces, FlatBlockTraces};
pub use self::noop_tracer::{NoopTracer, NoopVMTracer};
pub use self::executive_tracer::{ExecutiveTracer, ExecutiveVMTracer};
pub use types::trace_types::filter::{Filter, AddressesFilter};
@@ -59,9 +57,7 @@ pub trait Tracer: Send {
call: Option<Call>,
gas_used: U256,
output: Option<Bytes>,
depth: usize,
subs: Vec<Trace>,
delegate_call: bool
subs: Vec<FlatTrace>,
);
/// Stores trace create info.
@@ -71,21 +67,23 @@ pub trait Tracer: Send {
gas_used: U256,
code: Option<Bytes>,
address: Address,
depth: usize,
subs: Vec<Trace>
subs: Vec<FlatTrace>
);
/// Stores failed call trace.
fn trace_failed_call(&mut self, call: Option<Call>, depth: usize, subs: Vec<Trace>, delegate_call: bool);
fn trace_failed_call(&mut self, call: Option<Call>, subs: Vec<FlatTrace>);
/// Stores failed create trace.
fn trace_failed_create(&mut self, create: Option<Create>, depth: usize, subs: Vec<Trace>);
fn trace_failed_create(&mut self, create: Option<Create>, subs: Vec<FlatTrace>);
/// Stores suicide info.
fn trace_suicide(&mut self, address: Address, balance: U256, refund_address: Address);
/// Spawn subtracer which will be used to trace deeper levels of execution.
fn subtracer(&self) -> Self where Self: Sized;
/// Consumes self and returns all traces.
fn traces(self) -> Vec<Trace>;
fn traces(self) -> Vec<FlatTrace>;
}
/// Used by executive to build VM traces.

View File

@@ -18,8 +18,8 @@
use util::{Bytes, Address, U256};
use action_params::ActionParams;
use trace::{Tracer, VMTracer};
use trace::trace::{Trace, Call, Create, VMTrace};
use trace::{Tracer, VMTracer, FlatTrace};
use trace::trace::{Call, Create, VMTrace};
/// Nonoperative tracer. Does not trace anything.
pub struct NoopTracer;
@@ -37,29 +37,32 @@ impl Tracer for NoopTracer {
None
}
fn trace_call(&mut self, call: Option<Call>, _: U256, output: Option<Bytes>, _: usize, _: Vec<Trace>, _: bool) {
fn trace_call(&mut self, call: Option<Call>, _: U256, output: Option<Bytes>, _: Vec<FlatTrace>) {
assert!(call.is_none(), "self.prepare_trace_call().is_none(): so we can't be tracing: qed");
assert!(output.is_none(), "self.prepare_trace_output().is_none(): so we can't be tracing: qed");
}
fn trace_create(&mut self, create: Option<Create>, _: U256, code: Option<Bytes>, _: Address, _: usize, _: Vec<Trace>) {
fn trace_create(&mut self, create: Option<Create>, _: U256, code: Option<Bytes>, _: Address, _: Vec<FlatTrace>) {
assert!(create.is_none(), "self.prepare_trace_create().is_none(): so we can't be tracing: qed");
assert!(code.is_none(), "self.prepare_trace_output().is_none(): so we can't be tracing: qed");
}
fn trace_failed_call(&mut self, call: Option<Call>, _: usize, _: Vec<Trace>, _: bool) {
fn trace_failed_call(&mut self, call: Option<Call>, _: Vec<FlatTrace>) {
assert!(call.is_none(), "self.prepare_trace_call().is_none(): so we can't be tracing: qed");
}
fn trace_failed_create(&mut self, create: Option<Create>, _: usize, _: Vec<Trace>) {
fn trace_failed_create(&mut self, create: Option<Create>, _: Vec<FlatTrace>) {
assert!(create.is_none(), "self.prepare_trace_create().is_none(): so we can't be tracing: qed");
}
fn trace_suicide(&mut self, _address: Address, _balance: U256, _refund_address: Address) {
}
fn subtracer(&self) -> Self {
NoopTracer
}
fn traces(self) -> Vec<Trace> {
fn traces(self) -> Vec<FlatTrace> {
vec![]
}
}

View File

@@ -18,7 +18,8 @@
use util::numbers::*;
use util::Bytes;
use trace::{Trace, VMTrace};
use util::rlp::*;
use trace::{VMTrace, FlatTrace};
use types::log_entry::LogEntry;
use types::state_diff::StateDiff;
use ipc::binary::BinaryConvertError;
@@ -26,6 +27,43 @@ use std::fmt;
use std::mem;
use std::collections::VecDeque;
/// The type of the call-like instruction.
#[derive(Debug, PartialEq, Clone, Binary)]
pub enum CallType {
/// Not a CALL.
None,
/// CALL.
Call,
/// CALLCODE.
CallCode,
/// DELEGATECALL.
DelegateCall,
}
impl Encodable for CallType {
fn rlp_append(&self, s: &mut RlpStream) {
let v = match *self {
CallType::None => 0u32,
CallType::Call => 1,
CallType::CallCode => 2,
CallType::DelegateCall => 3,
};
s.append(&v);
}
}
impl Decodable for CallType {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
decoder.as_rlp().as_val().and_then(|v| Ok(match v {
0u32 => CallType::None,
1 => CallType::Call,
2 => CallType::CallCode,
3 => CallType::DelegateCall,
_ => return Err(DecoderError::Custom("Invalid value of CallType item")),
}))
}
}
/// Transaction execution receipt.
#[derive(Debug, PartialEq, Clone)]
pub struct Executed {
@@ -59,7 +97,7 @@ pub struct Executed {
/// Transaction output.
pub output: Bytes,
/// The trace of this transaction.
pub trace: Option<Trace>,
pub trace: Vec<FlatTrace>,
/// The VM trace of this transaction.
pub vm_trace: Option<VMTrace>,
/// The state diff, if we traced it.
@@ -135,3 +173,12 @@ impl fmt::Display for ExecutionError {
/// Transaction execution result.
pub type ExecutionResult = Result<Executed, ExecutionError>;
#[test]
fn should_encode_and_decode_call_type() {
use util::rlp;
let original = CallType::Call;
let encoded = rlp::encode(&original);
let decoded = rlp::decode(&encoded);
assert_eq!(original, decoded);
}

View File

@@ -33,7 +33,9 @@ pub enum BlockID {
/// Earliest block (genesis).
Earliest,
/// Latest mined block.
Latest
Latest,
/// Pending block.
Pending,
}
/// Uniquely identifies transaction.

View File

@@ -22,7 +22,7 @@ use util::{Address, FixedHash};
use util::sha3::Hashable;
use basic_types::LogBloom;
use trace::flat::FlatTrace;
use types::trace_types::trace::Action;
use types::trace_types::trace::{Action, Res};
use ipc::binary::BinaryConvertError;
use std::mem;
use std::collections::VecDeque;
@@ -30,7 +30,7 @@ use std::collections::VecDeque;
/// Addresses filter.
///
/// Used to create bloom possibilities and match filters.
#[derive(Binary)]
#[derive(Debug, Binary)]
pub struct AddressesFilter {
list: Vec<Address>
}
@@ -58,7 +58,7 @@ impl AddressesFilter {
true => vec![LogBloom::new()],
false => self.list.iter()
.map(|address| LogBloom::from_bloomed(&address.sha3()))
.collect()
.collect(),
}
}
@@ -71,12 +71,12 @@ impl AddressesFilter {
.flat_map(|bloom| self.list.iter()
.map(|address| bloom.with_bloomed(&address.sha3()))
.collect::<Vec<_>>())
.collect()
.collect(),
}
}
}
#[derive(Binary)]
#[derive(Debug, Binary)]
/// Traces filter.
pub struct Filter {
/// Block range.
@@ -110,29 +110,40 @@ impl Filter {
/// Returns true if given trace matches the filter.
pub fn matches(&self, trace: &FlatTrace) -> bool {
match trace.action {
let action = match trace.action {
Action::Call(ref call) => {
let from_matches = self.from_address.matches(&call.from);
let to_matches = self.to_address.matches(&call.to);
from_matches && to_matches
},
}
Action::Create(ref create) => {
let from_matches = self.from_address.matches(&create.from);
let to_matches = self.to_address.matches_all();
from_matches && to_matches
},
Action::Suicide(ref suicide) => {
let from_matches = self.from_address.matches(&suicide.address);
let to_matches = self.to_address.matches(&suicide.refund_address);
from_matches && to_matches
}
};
action || match trace.result {
Res::Create(ref create) => self.to_address.matches(&create.address),
_ => false
}
}
}
#[cfg(test)]
mod tests {
use util::{FixedHash, Address, U256};
use util::{FixedHash, Address};
use util::sha3::Hashable;
use trace::trace::{Action, Call, Res};
use trace::trace::{Action, Call, Res, Create, CreateResult, Suicide};
use trace::flat::FlatTrace;
use trace::{Filter, AddressesFilter};
use basic_types::LogBloom;
use types::executed::CallType;
#[test]
fn empty_trace_filter_bloom_possibilities() {
@@ -270,14 +281,15 @@ mod tests {
let trace = FlatTrace {
action: Action::Call(Call {
from: Address::from(1),
to: Address::from(2),
value: U256::from(3),
gas: U256::from(4),
from: 1.into(),
to: 2.into(),
value: 3.into(),
gas: 4.into(),
input: vec![0x5],
call_type: CallType::Call,
}),
result: Res::FailedCall,
trace_address: vec![0],
trace_address: vec![0].into_iter().collect(),
subtraces: 0,
};
@@ -288,5 +300,48 @@ mod tests {
assert!(f4.matches(&trace));
assert!(f5.matches(&trace));
assert!(!f6.matches(&trace));
let trace = FlatTrace {
action: Action::Create(Create {
from: 1.into(),
value: 3.into(),
gas: 4.into(),
init: vec![0x5],
}),
result: Res::Create(CreateResult {
gas_used: 10.into(),
code: vec![],
address: 2.into(),
}),
trace_address: vec![0].into_iter().collect(),
subtraces: 0,
};
assert!(f0.matches(&trace));
assert!(f1.matches(&trace));
assert!(f2.matches(&trace));
assert!(f3.matches(&trace));
assert!(f4.matches(&trace));
assert!(f5.matches(&trace));
assert!(!f6.matches(&trace));
let trace = FlatTrace {
action: Action::Suicide(Suicide {
address: 1.into(),
refund_address: 2.into(),
balance: 3.into(),
}),
result: Res::None,
trace_address: vec![].into_iter().collect(),
subtraces: 0
};
assert!(f0.matches(&trace));
assert!(f1.matches(&trace));
assert!(f2.matches(&trace));
assert!(f3.matches(&trace));
assert!(f4.matches(&trace));
assert!(f5.matches(&trace));
assert!(!f6.matches(&trace));
}
}

View File

@@ -0,0 +1,210 @@
// 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/>.
//! Flat trace module
use std::collections::VecDeque;
use std::mem;
use ipc::binary::BinaryConvertError;
use util::rlp::*;
use basic_types::LogBloom;
use super::trace::{Action, Res};
/// Trace localized in vector of traces produced by a single transaction.
///
/// Parent and children indexes refer to positions in this vector.
#[derive(Debug, PartialEq, Clone, Binary)]
pub struct FlatTrace {
/// Type of action performed by a transaction.
pub action: Action,
/// Result of this action.
pub result: Res,
/// Number of subtraces.
pub subtraces: usize,
/// Exact location of trace.
///
/// [index in root, index in first CALL, index in second CALL, ...]
pub trace_address: VecDeque<usize>,
}
impl FlatTrace {
/// Returns bloom of the trace.
pub fn bloom(&self) -> LogBloom {
self.action.bloom() | self.result.bloom()
}
}
impl Encodable for FlatTrace {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(4);
s.append(&self.action);
s.append(&self.result);
s.append(&self.subtraces);
s.append(&self.trace_address.clone().into_iter().collect::<Vec<_>>());
}
}
impl Decodable for FlatTrace {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let d = decoder.as_rlp();
let v: Vec<usize> = try!(d.val_at(3));
let res = FlatTrace {
action: try!(d.val_at(0)),
result: try!(d.val_at(1)),
subtraces: try!(d.val_at(2)),
trace_address: v.into_iter().collect(),
};
Ok(res)
}
}
/// Represents all traces produced by a single transaction.
#[derive(Debug, PartialEq, Clone)]
pub struct FlatTransactionTraces(Vec<FlatTrace>);
impl From<Vec<FlatTrace>> for FlatTransactionTraces {
fn from(v: Vec<FlatTrace>) -> Self {
FlatTransactionTraces(v)
}
}
impl FlatTransactionTraces {
/// Returns bloom of the trace.
pub fn bloom(&self) -> LogBloom {
self.0.iter().fold(Default::default(), | bloom, trace | bloom | trace.bloom())
}
}
impl Encodable for FlatTransactionTraces {
fn rlp_append(&self, s: &mut RlpStream) {
s.append(&self.0);
}
}
impl Decodable for FlatTransactionTraces {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
Ok(FlatTransactionTraces(try!(Decodable::decode(decoder))))
}
}
impl Into<Vec<FlatTrace>> for FlatTransactionTraces {
fn into(self) -> Vec<FlatTrace> {
self.0
}
}
/// Represents all traces produced by transactions in a single block.
#[derive(Debug, PartialEq, Clone)]
pub struct FlatBlockTraces(Vec<FlatTransactionTraces>);
impl From<Vec<FlatTransactionTraces>> for FlatBlockTraces {
fn from(v: Vec<FlatTransactionTraces>) -> Self {
FlatBlockTraces(v)
}
}
impl FlatBlockTraces {
/// Returns bloom of the trace.
pub fn bloom(&self) -> LogBloom {
self.0.iter().fold(Default::default(), | bloom, tx_traces | bloom | tx_traces.bloom())
}
}
impl Encodable for FlatBlockTraces {
fn rlp_append(&self, s: &mut RlpStream) {
s.append(&self.0);
}
}
impl Decodable for FlatBlockTraces {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
Ok(FlatBlockTraces(try!(Decodable::decode(decoder))))
}
}
impl Into<Vec<FlatTransactionTraces>> for FlatBlockTraces {
fn into(self) -> Vec<FlatTransactionTraces> {
self.0
}
}
#[cfg(test)]
mod tests {
use super::{FlatBlockTraces, FlatTransactionTraces, FlatTrace};
use trace::trace::{Action, Res, CallResult, Call, Suicide};
use types::executed::CallType;
#[test]
fn test_trace_serialization() {
use util::rlp;
// block #51921
let flat_trace = FlatTrace {
action: Action::Call(Call {
from: "8dda5e016e674683241bf671cced51e7239ea2bc".parse().unwrap(),
to: "37a5e19cc2d49f244805d5c268c0e6f321965ab9".parse().unwrap(),
value: "3627e8f712373c0000".parse().unwrap(),
gas: 0x03e8.into(),
input: vec![],
call_type: CallType::Call,
}),
result: Res::Call(CallResult {
gas_used: 0.into(),
output: vec![],
}),
trace_address: Default::default(),
subtraces: 0,
};
let flat_trace1 = FlatTrace {
action: Action::Call(Call {
from: "3d0768da09ce77d25e2d998e6a7b6ed4b9116c2d".parse().unwrap(),
to: "412fda7643b37d436cb40628f6dbbb80a07267ed".parse().unwrap(),
value: 0.into(),
gas: 0x010c78.into(),
input: vec![0x41, 0xc0, 0xe1, 0xb5],
call_type: CallType::Call,
}),
result: Res::Call(CallResult {
gas_used: 0x0127.into(),
output: vec![],
}),
trace_address: Default::default(),
subtraces: 1,
};
let flat_trace2 = FlatTrace {
action: Action::Suicide(Suicide {
address: "412fda7643b37d436cb40628f6dbbb80a07267ed".parse().unwrap(),
balance: 0.into(),
refund_address: "3d0768da09ce77d25e2d998e6a7b6ed4b9116c2d".parse().unwrap(),
}),
result: Res::None,
trace_address: vec![0].into_iter().collect(),
subtraces: 0,
};
let block_traces = FlatBlockTraces(vec![
FlatTransactionTraces(vec![flat_trace]),
FlatTransactionTraces(vec![flat_trace1, flat_trace2])
]);
let encoded = rlp::encode(&block_traces);
let decoded = rlp::decode(&encoded);
assert_eq!(block_traces, decoded);
}
}

View File

@@ -17,5 +17,6 @@
//! Types used in the public api
pub mod filter;
pub mod flat;
pub mod trace;
pub mod localized;

View File

@@ -21,6 +21,7 @@ use util::rlp::*;
use util::sha3::Hashable;
use action_params::ActionParams;
use basic_types::LogBloom;
use types::executed::CallType;
use ipc::binary::BinaryConvertError;
use std::mem;
use std::collections::VecDeque;
@@ -87,6 +88,13 @@ impl Decodable for CreateResult {
}
}
impl CreateResult {
/// Returns bloom.
pub fn bloom(&self) -> LogBloom {
LogBloom::from_bloomed(&self.address.sha3())
}
}
/// Description of a _call_ action, either a `CALL` operation or a message transction.
#[derive(Debug, Clone, PartialEq, Binary)]
pub struct Call {
@@ -100,6 +108,8 @@ pub struct Call {
pub gas: U256,
/// The input data provided to the call.
pub input: Bytes,
/// The type of the call.
pub call_type: CallType,
}
impl From<ActionParams> for Call {
@@ -110,18 +120,20 @@ impl From<ActionParams> for Call {
value: p.value.value(),
gas: p.gas,
input: p.data.unwrap_or_else(Vec::new),
call_type: p.call_type,
}
}
}
impl Encodable for Call {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(5);
s.begin_list(6);
s.append(&self.from);
s.append(&self.to);
s.append(&self.value);
s.append(&self.gas);
s.append(&self.input);
s.append(&self.call_type);
}
}
@@ -134,6 +146,7 @@ impl Decodable for Call {
value: try!(d.val_at(2)),
gas: try!(d.val_at(3)),
input: try!(d.val_at(4)),
call_type: try!(d.val_at(5)),
};
Ok(res)
@@ -205,6 +218,48 @@ impl Create {
}
}
/// Suicide action.
#[derive(Debug, Clone, PartialEq, Binary)]
pub struct Suicide {
/// Suicided address.
pub address: Address,
/// Suicided contract heir.
pub refund_address: Address,
/// Balance of the contract just before suicide.
pub balance: U256,
}
impl Suicide {
/// Return suicide action bloom.
pub fn bloom(&self) -> LogBloom {
LogBloom::from_bloomed(&self.address.sha3())
.with_bloomed(&self.refund_address.sha3())
}
}
impl Encodable for Suicide {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(3);
s.append(&self.address);
s.append(&self.refund_address);
s.append(&self.balance);
}
}
impl Decodable for Suicide {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let d = decoder.as_rlp();
let res = Suicide {
address: try!(d.val_at(0)),
refund_address: try!(d.val_at(1)),
balance: try!(d.val_at(2)),
};
Ok(res)
}
}
/// Description of an action that we trace; will be either a call or a create.
#[derive(Debug, Clone, PartialEq, Binary)]
pub enum Action {
@@ -212,6 +267,8 @@ pub enum Action {
Call(Call),
/// It's a create action.
Create(Create),
/// Suicide.
Suicide(Suicide),
}
impl Encodable for Action {
@@ -225,6 +282,10 @@ impl Encodable for Action {
Action::Create(ref create) => {
s.append(&1u8);
s.append(create);
},
Action::Suicide(ref suicide) => {
s.append(&2u8);
s.append(suicide);
}
}
}
@@ -237,6 +298,7 @@ impl Decodable for Action {
match action_type {
0 => d.val_at(1).map(Action::Call),
1 => d.val_at(1).map(Action::Create),
2 => d.val_at(1).map(Action::Suicide),
_ => Err(DecoderError::Custom("Invalid action type.")),
}
}
@@ -248,6 +310,7 @@ impl Action {
match *self {
Action::Call(ref call) => call.bloom(),
Action::Create(ref create) => create.bloom(),
Action::Suicide(ref suicide) => suicide.bloom(),
}
}
}
@@ -263,6 +326,8 @@ pub enum Res {
FailedCall,
/// Failed create.
FailedCreate,
/// None
None,
}
impl Encodable for Res {
@@ -285,6 +350,10 @@ impl Encodable for Res {
Res::FailedCreate => {
s.begin_list(1);
s.append(&3u8);
},
Res::None => {
s.begin_list(1);
s.append(&4u8);
}
}
}
@@ -299,53 +368,19 @@ impl Decodable for Res {
1 => d.val_at(1).map(Res::Create),
2 => Ok(Res::FailedCall),
3 => Ok(Res::FailedCreate),
4 => Ok(Res::None),
_ => Err(DecoderError::Custom("Invalid result type.")),
}
}
}
#[derive(Debug, Clone, PartialEq, Binary)]
/// A trace; includes a description of the action being traced and sub traces of each interior action.
pub struct Trace {
/// The number of EVM execution environments active when this action happened; 0 if it's
/// the outer action of the transaction.
pub depth: usize,
/// The action being performed.
pub action: Action,
/// The sub traces for each interior action performed as part of this call.
pub subs: Vec<Trace>,
/// The result of the performed action.
pub result: Res,
}
impl Encodable for Trace {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(4);
s.append(&self.depth);
s.append(&self.action);
s.append(&self.subs);
s.append(&self.result);
}
}
impl Decodable for Trace {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let d = decoder.as_rlp();
let res = Trace {
depth: try!(d.val_at(0)),
action: try!(d.val_at(1)),
subs: try!(d.val_at(2)),
result: try!(d.val_at(3)),
};
Ok(res)
}
}
impl Trace {
/// Returns trace bloom.
impl Res {
/// Returns result bloom.
pub fn bloom(&self) -> LogBloom {
self.subs.iter().fold(self.action.bloom(), |b, s| b | s.bloom())
match *self {
Res::Create(ref create) => create.bloom(),
Res::Call(_) | Res::FailedCall | Res::FailedCreate | Res::None => Default::default(),
}
}
}
@@ -513,84 +548,3 @@ impl Decodable for VMTrace {
}
}
#[cfg(test)]
mod tests {
use util::{Address, U256, FixedHash};
use util::rlp::{encode, decode};
use util::sha3::Hashable;
use trace::trace::{Call, CallResult, Create, Res, Action, Trace};
#[test]
fn traces_rlp() {
let trace = Trace {
depth: 2,
action: Action::Call(Call {
from: Address::from(1),
to: Address::from(2),
value: U256::from(3),
gas: U256::from(4),
input: vec![0x5]
}),
subs: vec![
Trace {
depth: 3,
action: Action::Create(Create {
from: Address::from(6),
value: U256::from(7),
gas: U256::from(8),
init: vec![0x9]
}),
subs: vec![],
result: Res::FailedCreate
}
],
result: Res::Call(CallResult {
gas_used: U256::from(10),
output: vec![0x11, 0x12]
})
};
let encoded = encode(&trace);
let decoded: Trace = decode(&encoded);
assert_eq!(trace, decoded);
}
#[test]
fn traces_bloom() {
let trace = Trace {
depth: 2,
action: Action::Call(Call {
from: Address::from(1),
to: Address::from(2),
value: U256::from(3),
gas: U256::from(4),
input: vec![0x5]
}),
subs: vec![
Trace {
depth: 3,
action: Action::Create(Create {
from: Address::from(6),
value: U256::from(7),
gas: U256::from(8),
init: vec![0x9]
}),
subs: vec![],
result: Res::FailedCreate
}
],
result: Res::Call(CallResult {
gas_used: U256::from(10),
output: vec![0x11, 0x12]
})
};
let bloom = trace.bloom();
// right now only addresses are bloomed
assert!(bloom.contains_bloomed(&Address::from(1).sha3()));
assert!(bloom.contains_bloomed(&Address::from(2).sha3()));
assert!(!bloom.contains_bloomed(&Address::from(20).sha3()));
assert!(bloom.contains_bloomed(&Address::from(6).sha3()));
}
}

View File

@@ -91,7 +91,7 @@ impl Transaction {
impl From<ethjson::state::Transaction> for SignedTransaction {
fn from(t: ethjson::state::Transaction) -> Self {
let to: Option<_> = t.to.into();
let to: Option<ethjson::hash::Address> = t.to.into();
Transaction {
nonce: t.nonce.into(),
gas_price: t.gas_price.into(),
@@ -108,7 +108,7 @@ impl From<ethjson::state::Transaction> for SignedTransaction {
impl From<ethjson::transaction::Transaction> for SignedTransaction {
fn from(t: ethjson::transaction::Transaction) -> Self {
let to: Option<_> = t.to.into();
let to: Option<ethjson::hash::Address> = t.to.into();
SignedTransaction {
unsigned: Transaction {
nonce: t.nonce.into(),

View File

@@ -24,11 +24,11 @@ use super::verification;
pub struct CanonVerifier;
impl Verifier for CanonVerifier {
fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &BlockProvider) -> Result<(), Error> {
fn verify_block_family(&self, header: &Header, bytes: &[u8], engine: &Engine, bc: &BlockProvider) -> Result<(), Error> {
verification::verify_block_family(header, bytes, engine, bc)
}
fn verify_block_final(expected: &Header, got: &Header) -> Result<(), Error> {
fn verify_block_final(&self, expected: &Header, got: &Header) -> Result<(), Error> {
verification::verify_block_final(expected, got)
}
}

View File

@@ -17,11 +17,32 @@
pub mod verification;
pub mod verifier;
mod canon_verifier;
#[cfg(test)]
mod noop_verifier;
pub use self::verification::*;
pub use self::verifier::Verifier;
pub use self::canon_verifier::CanonVerifier;
#[cfg(test)]
pub use self::noop_verifier::NoopVerifier;
/// Verifier type.
#[derive(Debug)]
pub enum VerifierType {
/// Verifies block normally.
Canon,
/// Does not verify block at all.
/// Used in tests.
Noop,
}
impl Default for VerifierType {
fn default() -> Self {
VerifierType::Canon
}
}
pub fn new(v: VerifierType) -> Box<Verifier> {
match v {
VerifierType::Canon => Box::new(CanonVerifier),
VerifierType::Noop => Box::new(NoopVerifier),
}
}

View File

@@ -24,11 +24,11 @@ use super::Verifier;
pub struct NoopVerifier;
impl Verifier for NoopVerifier {
fn verify_block_family(_header: &Header, _bytes: &[u8], _engine: &Engine, _bc: &BlockProvider) -> Result<(), Error> {
fn verify_block_family(&self, _header: &Header, _bytes: &[u8], _engine: &Engine, _bc: &BlockProvider) -> Result<(), Error> {
Ok(())
}
fn verify_block_final(_expected: &Header, _got: &Header) -> Result<(), Error> {
fn verify_block_final(&self, _expected: &Header, _got: &Header) -> Result<(), Error> {
Ok(())
}
}

View File

@@ -21,6 +21,6 @@ use header::Header;
/// Should be used to verify blocks.
pub trait Verifier: Send + Sync {
fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &BlockProvider) -> Result<(), Error>;
fn verify_block_final(expected: &Header, got: &Header) -> Result<(), Error>;
fn verify_block_family(&self, header: &Header, bytes: &[u8], engine: &Engine, bc: &BlockProvider) -> Result<(), Error>;
fn verify_block_final(&self, expected: &Header, got: &Header) -> Result<(), Error>;
}

View File

@@ -1,339 +0,0 @@
// 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/>.
//! Block oriented views onto rlp.
use util::*;
use header::*;
use transaction::*;
/// View onto transaction rlp.
pub struct TransactionView<'a> {
rlp: Rlp<'a>
}
impl<'a> TransactionView<'a> {
/// Creates new view onto block from raw bytes.
pub fn new(bytes: &'a [u8]) -> TransactionView<'a> {
TransactionView {
rlp: Rlp::new(bytes)
}
}
/// Creates new view onto block from rlp.
pub fn new_from_rlp(rlp: Rlp<'a>) -> TransactionView<'a> {
TransactionView {
rlp: rlp
}
}
/// Return reference to underlaying rlp.
pub fn rlp(&self) -> &Rlp<'a> {
&self.rlp
}
/// Get the nonce field of the transaction.
pub fn nonce(&self) -> U256 { self.rlp.val_at(0) }
/// Get the gas_price field of the transaction.
pub fn gas_price(&self) -> U256 { self.rlp.val_at(1) }
/// Get the gas field of the transaction.
pub fn gas(&self) -> U256 { self.rlp.val_at(2) }
/// Get the value field of the transaction.
pub fn value(&self) -> U256 { self.rlp.val_at(4) }
/// Get the data field of the transaction.
pub fn data(&self) -> Bytes { self.rlp.val_at(5) }
/// Get the v field of the transaction.
pub fn v(&self) -> u8 { let r: u16 = self.rlp.val_at(6); r as u8 }
/// Get the r field of the transaction.
pub fn r(&self) -> U256 { self.rlp.val_at(7) }
/// Get the s field of the transaction.
pub fn s(&self) -> U256 { self.rlp.val_at(8) }
// TODO: something like pub fn action(&self) -> Action { self.rlp.val_at(3) }
}
impl<'a> Hashable for TransactionView<'a> {
fn sha3(&self) -> H256 {
self.rlp.as_raw().sha3()
}
}
/// View onto transaction rlp.
pub struct AccountView<'a> {
rlp: Rlp<'a>
}
impl<'a> AccountView<'a> {
/// Creates new view onto block from raw bytes.
pub fn new(bytes: &'a [u8]) -> AccountView<'a> {
AccountView {
rlp: Rlp::new(bytes)
}
}
/// Creates new view onto block from rlp.
pub fn new_from_rlp(rlp: Rlp<'a>) -> AccountView<'a> {
AccountView {
rlp: rlp
}
}
/// Return reference to underlaying rlp.
pub fn rlp(&self) -> &Rlp<'a> {
&self.rlp
}
/// Get the nonce field of the transaction.
pub fn nonce(&self) -> U256 { self.rlp.val_at(0) }
/// Get the gas_price field of the transaction.
pub fn balance(&self) -> U256 { self.rlp.val_at(1) }
/// Get the gas field of the transaction.
pub fn storage_root(&self) -> H256 { self.rlp.val_at(2) }
/// Get the value field of the transaction.
pub fn code_hash(&self) -> H256 { self.rlp.val_at(3) }
}
/// View onto block rlp.
pub struct BlockView<'a> {
rlp: Rlp<'a>
}
impl<'a> BlockView<'a> {
/// Creates new view onto block from raw bytes.
pub fn new(bytes: &'a [u8]) -> BlockView<'a> {
BlockView {
rlp: Rlp::new(bytes)
}
}
/// Creates new view onto block from rlp.
pub fn new_from_rlp(rlp: Rlp<'a>) -> BlockView<'a> {
BlockView {
rlp: rlp
}
}
/// Return reference to underlaying rlp.
pub fn rlp(&self) -> &Rlp<'a> {
&self.rlp
}
/// Create new Header object from header rlp.
pub fn header(&self) -> Header {
self.rlp.val_at(0)
}
/// Create new header view obto block head rlp.
pub fn header_view(&self) -> HeaderView<'a> {
HeaderView::new_from_rlp(self.rlp.at(0))
}
/// Return List of transactions in given block.
pub fn transactions(&self) -> Vec<SignedTransaction> {
self.rlp.val_at(1)
}
/// Return List of transactions with additional localization info.
pub fn localized_transactions(&self) -> Vec<LocalizedTransaction> {
let header = self.header_view();
let block_hash = header.sha3();
let block_number = header.number();
self.transactions()
.into_iter()
.enumerate()
.map(|(i, t)| LocalizedTransaction {
signed: t,
block_hash: block_hash.clone(),
block_number: block_number,
transaction_index: i
}).collect()
}
/// Return number of transactions in given block, without deserializing them.
pub fn transactions_count(&self) -> usize {
self.rlp.at(1).iter().count()
}
/// Return List of transactions in given block.
pub fn transaction_views(&self) -> Vec<TransactionView> {
self.rlp.at(1).iter().map(TransactionView::new_from_rlp).collect()
}
/// Return transaction hashes.
pub fn transaction_hashes(&self) -> Vec<H256> {
self.rlp.at(1).iter().map(|rlp| rlp.as_raw().sha3()).collect()
}
/// Returns transaction at given index without deserializing unnecessary data.
pub fn transaction_at(&self, index: usize) -> Option<SignedTransaction> {
self.rlp.at(1).iter().nth(index).map(|rlp| rlp.as_val())
}
/// Returns localized transaction at given index.
pub fn localized_transaction_at(&self, index: usize) -> Option<LocalizedTransaction> {
let header = self.header_view();
let block_hash = header.sha3();
let block_number = header.number();
self.transaction_at(index).map(|t| LocalizedTransaction {
signed: t,
block_hash: block_hash,
block_number: block_number,
transaction_index: index
})
}
/// Return list of uncles of given block.
pub fn uncles(&self) -> Vec<Header> {
self.rlp.val_at(2)
}
/// Return number of uncles in given block, without deserializing them.
pub fn uncles_count(&self) -> usize {
self.rlp.at(2).iter().count()
}
/// Return List of transactions in given block.
pub fn uncle_views(&self) -> Vec<HeaderView> {
self.rlp.at(2).iter().map(HeaderView::new_from_rlp).collect()
}
/// Return list of uncle hashes of given block.
pub fn uncle_hashes(&self) -> Vec<H256> {
self.rlp.at(2).iter().map(|rlp| rlp.as_raw().sha3()).collect()
}
/// Return nth uncle.
pub fn uncle_at(&self, index: usize) -> Option<Header> {
self.rlp.at(2).iter().nth(index).map(|rlp| rlp.as_val())
}
}
impl<'a> Hashable for BlockView<'a> {
fn sha3(&self) -> H256 {
self.header_view().sha3()
}
}
/// View onto block header rlp.
pub struct HeaderView<'a> {
rlp: Rlp<'a>
}
impl<'a> HeaderView<'a> {
/// Creates new view onto header from raw bytes.
pub fn new(bytes: &'a [u8]) -> HeaderView<'a> {
HeaderView {
rlp: Rlp::new(bytes)
}
}
/// Creates new view onto header from rlp.
pub fn new_from_rlp(rlp: Rlp<'a>) -> HeaderView<'a> {
HeaderView {
rlp: rlp
}
}
/// Returns header hash.
pub fn hash(&self) -> H256 { self.sha3() }
/// Returns raw rlp.
pub fn rlp(&self) -> &Rlp<'a> { &self.rlp }
/// Returns parent hash.
pub fn parent_hash(&self) -> H256 { self.rlp.val_at(0) }
/// Returns uncles hash.
pub fn uncles_hash(&self) -> H256 { self.rlp.val_at(1) }
/// Returns author.
pub fn author(&self) -> Address { self.rlp.val_at(2) }
/// Returns state root.
pub fn state_root(&self) -> H256 { self.rlp.val_at(3) }
/// Returns transactions root.
pub fn transactions_root(&self) -> H256 { self.rlp.val_at(4) }
/// Returns block receipts root.
pub fn receipts_root(&self) -> H256 { self.rlp.val_at(5) }
/// Returns block log bloom.
pub fn log_bloom(&self) -> H2048 { self.rlp.val_at(6) }
/// Returns block difficulty.
pub fn difficulty(&self) -> U256 { self.rlp.val_at(7) }
/// Returns block number.
pub fn number(&self) -> BlockNumber { self.rlp.val_at(8) }
/// Returns block gas limit.
pub fn gas_limit(&self) -> U256 { self.rlp.val_at(9) }
/// Returns block gas used.
pub fn gas_used(&self) -> U256 { self.rlp.val_at(10) }
/// Returns timestamp.
pub fn timestamp(&self) -> u64 { self.rlp.val_at(11) }
/// Returns block extra data.
pub fn extra_data(&self) -> Bytes { self.rlp.val_at(12) }
/// Returns a vector of post-RLP-encoded seal fields.
pub fn seal(&self) -> Vec<Bytes> {
let mut seal = vec![];
for i in 13..self.rlp.item_count() {
seal.push(self.rlp.at(i).as_raw().to_vec());
}
seal
}
}
impl<'a> Hashable for HeaderView<'a> {
fn sha3(&self) -> H256 {
self.rlp.as_raw().sha3()
}
}
#[cfg(test)]
mod tests {
use rustc_serialize::hex::FromHex;
use super::BlockView;
#[test]
fn test_header_view_seal_fields() {
// that's rlp of block created with ethash engine.
let block_rlp = "f90261f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23f862f86002018304cb2f94ec0e71ad0a90ffe1909d27dac207f7680abba42d01801ba03a347e72953c860f32b1eb2c78a680d8734b2ea08085d949d729479796f218d5a047ea6239d9e31ccac8af3366f5ca37184d26e7646e3191a3aeb81c4cf74de500c0".from_hex().unwrap();
let mix_hash = "a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd".from_hex().unwrap();
let nonce = "88ab4e252a7e8c2a23".from_hex().unwrap();
let block_view = BlockView::new(&block_rlp);
let header_view = block_view.header_view();
let seal_fields = header_view.seal();
assert_eq!(seal_fields.len(), 2);
assert_eq!(seal_fields[0], mix_hash);
assert_eq!(seal_fields[1], nonce);
}
}

167
ethcore/src/views/block.rs Normal file
View File

@@ -0,0 +1,167 @@
// 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/>.
//! View onto block rlp.
use util::*;
use header::*;
use transaction::*;
use super::{TransactionView, HeaderView};
/// View onto block rlp.
pub struct BlockView<'a> {
rlp: Rlp<'a>
}
impl<'a> BlockView<'a> {
/// Creates new view onto block from raw bytes.
pub fn new(bytes: &'a [u8]) -> BlockView<'a> {
BlockView {
rlp: Rlp::new(bytes)
}
}
/// Creates new view onto block from rlp.
pub fn new_from_rlp(rlp: Rlp<'a>) -> BlockView<'a> {
BlockView {
rlp: rlp
}
}
/// Block header hash.
pub fn hash(&self) -> H256 {
self.sha3()
}
/// Return reference to underlaying rlp.
pub fn rlp(&self) -> &Rlp<'a> {
&self.rlp
}
/// Create new Header object from header rlp.
pub fn header(&self) -> Header {
self.rlp.val_at(0)
}
/// Create new header view obto block head rlp.
pub fn header_view(&self) -> HeaderView<'a> {
HeaderView::new_from_rlp(self.rlp.at(0))
}
/// Return List of transactions in given block.
pub fn transactions(&self) -> Vec<SignedTransaction> {
self.rlp.val_at(1)
}
/// Return List of transactions with additional localization info.
pub fn localized_transactions(&self) -> Vec<LocalizedTransaction> {
let header = self.header_view();
let block_hash = header.sha3();
let block_number = header.number();
self.transactions()
.into_iter()
.enumerate()
.map(|(i, t)| LocalizedTransaction {
signed: t,
block_hash: block_hash.clone(),
block_number: block_number,
transaction_index: i
}).collect()
}
/// Return number of transactions in given block, without deserializing them.
pub fn transactions_count(&self) -> usize {
self.rlp.at(1).iter().count()
}
/// Return List of transactions in given block.
pub fn transaction_views(&self) -> Vec<TransactionView> {
self.rlp.at(1).iter().map(TransactionView::new_from_rlp).collect()
}
/// Return transaction hashes.
pub fn transaction_hashes(&self) -> Vec<H256> {
self.rlp.at(1).iter().map(|rlp| rlp.as_raw().sha3()).collect()
}
/// Returns transaction at given index without deserializing unnecessary data.
pub fn transaction_at(&self, index: usize) -> Option<SignedTransaction> {
self.rlp.at(1).iter().nth(index).map(|rlp| rlp.as_val())
}
/// Returns localized transaction at given index.
pub fn localized_transaction_at(&self, index: usize) -> Option<LocalizedTransaction> {
let header = self.header_view();
let block_hash = header.sha3();
let block_number = header.number();
self.transaction_at(index).map(|t| LocalizedTransaction {
signed: t,
block_hash: block_hash,
block_number: block_number,
transaction_index: index
})
}
/// Return list of uncles of given block.
pub fn uncles(&self) -> Vec<Header> {
self.rlp.val_at(2)
}
/// Return number of uncles in given block, without deserializing them.
pub fn uncles_count(&self) -> usize {
self.rlp.at(2).iter().count()
}
/// Return List of transactions in given block.
pub fn uncle_views(&self) -> Vec<HeaderView> {
self.rlp.at(2).iter().map(HeaderView::new_from_rlp).collect()
}
/// Return list of uncle hashes of given block.
pub fn uncle_hashes(&self) -> Vec<H256> {
self.rlp.at(2).iter().map(|rlp| rlp.as_raw().sha3()).collect()
}
/// Return nth uncle.
pub fn uncle_at(&self, index: usize) -> Option<Header> {
self.rlp.at(2).iter().nth(index).map(|rlp| rlp.as_val())
}
}
impl<'a> Hashable for BlockView<'a> {
fn sha3(&self) -> H256 {
self.header_view().sha3()
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use rustc_serialize::hex::FromHex;
use util::H256;
use super::BlockView;
#[test]
fn test_block_view() {
// that's rlp of block created with ethash engine.
let rlp = "f90261f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23f862f86002018304cb2f94ec0e71ad0a90ffe1909d27dac207f7680abba42d01801ba03a347e72953c860f32b1eb2c78a680d8734b2ea08085d949d729479796f218d5a047ea6239d9e31ccac8af3366f5ca37184d26e7646e3191a3aeb81c4cf74de500c0".from_hex().unwrap();
let view = BlockView::new(&rlp);
assert_eq!(view.hash(), H256::from_str("2c9747e804293bd3f1a986484343f23bc88fd5be75dfe9d5c2860aff61e6f259").unwrap());
assert_eq!(view.transactions_count(), 1);
assert_eq!(view.uncles_count(), 0);
}
}

134
ethcore/src/views/header.rs Normal file
View File

@@ -0,0 +1,134 @@
// 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/>.
//! View onto block header rlp
use util::{Rlp, U256, Bytes, Hashable, H256, Address, H2048, View};
use header::BlockNumber;
/// View onto block header rlp.
pub struct HeaderView<'a> {
rlp: Rlp<'a>
}
impl<'a> HeaderView<'a> {
/// Creates new view onto header from raw bytes.
pub fn new(bytes: &'a [u8]) -> HeaderView<'a> {
HeaderView {
rlp: Rlp::new(bytes)
}
}
/// Creates new view onto header from rlp.
pub fn new_from_rlp(rlp: Rlp<'a>) -> HeaderView<'a> {
HeaderView {
rlp: rlp
}
}
/// Returns header hash.
pub fn hash(&self) -> H256 { self.sha3() }
/// Returns raw rlp.
pub fn rlp(&self) -> &Rlp<'a> { &self.rlp }
/// Returns parent hash.
pub fn parent_hash(&self) -> H256 { self.rlp.val_at(0) }
/// Returns uncles hash.
pub fn uncles_hash(&self) -> H256 { self.rlp.val_at(1) }
/// Returns author.
pub fn author(&self) -> Address { self.rlp.val_at(2) }
/// Returns state root.
pub fn state_root(&self) -> H256 { self.rlp.val_at(3) }
/// Returns transactions root.
pub fn transactions_root(&self) -> H256 { self.rlp.val_at(4) }
/// Returns block receipts root.
pub fn receipts_root(&self) -> H256 { self.rlp.val_at(5) }
/// Returns block log bloom.
pub fn log_bloom(&self) -> H2048 { self.rlp.val_at(6) }
/// Returns block difficulty.
pub fn difficulty(&self) -> U256 { self.rlp.val_at(7) }
/// Returns block number.
pub fn number(&self) -> BlockNumber { self.rlp.val_at(8) }
/// Returns block gas limit.
pub fn gas_limit(&self) -> U256 { self.rlp.val_at(9) }
/// Returns block gas used.
pub fn gas_used(&self) -> U256 { self.rlp.val_at(10) }
/// Returns timestamp.
pub fn timestamp(&self) -> u64 { self.rlp.val_at(11) }
/// Returns block extra data.
pub fn extra_data(&self) -> Bytes { self.rlp.val_at(12) }
/// Returns a vector of post-RLP-encoded seal fields.
pub fn seal(&self) -> Vec<Bytes> {
let mut seal = vec![];
for i in 13..self.rlp.item_count() {
seal.push(self.rlp.at(i).as_raw().to_vec());
}
seal
}
}
impl<'a> Hashable for HeaderView<'a> {
fn sha3(&self) -> H256 {
self.rlp.as_raw().sha3()
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use rustc_serialize::hex::FromHex;
use util::{H256, Address, H2048, U256};
use super::HeaderView;
#[test]
fn test_header_view() {
// that's rlp of block header created with ethash engine.
let rlp = "f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23".from_hex().unwrap();
let mix_hash = "a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd".from_hex().unwrap();
let nonce = "88ab4e252a7e8c2a23".from_hex().unwrap();
let view = HeaderView::new(&rlp);
assert_eq!(view.hash(), H256::from_str("2c9747e804293bd3f1a986484343f23bc88fd5be75dfe9d5c2860aff61e6f259").unwrap());
assert_eq!(view.parent_hash(), H256::from_str("d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7").unwrap());
assert_eq!(view.uncles_hash(), H256::from_str("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347").unwrap());
assert_eq!(view.author(), Address::from_str("8888f1f195afa192cfee860698584c030f4c9db1").unwrap());
assert_eq!(view.state_root(), H256::from_str("5fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25").unwrap());
assert_eq!(view.transactions_root(), H256::from_str("88d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158").unwrap());
assert_eq!(view.receipts_root(), H256::from_str("07c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1").unwrap());
assert_eq!(view.log_bloom(), H2048::default());
assert_eq!(view.difficulty(), U256::from(0x02_00_80));
assert_eq!(view.number(), 3);
assert_eq!(view.gas_limit(), U256::from(0x2f_ef_ba));
assert_eq!(view.gas_used(), U256::from(0x52_4d));
assert_eq!(view.timestamp(), 0x56_8e_93_2a);
assert_eq!(view.extra_data(), vec![] as Vec<u8>);
assert_eq!(view.seal(), vec![mix_hash, nonce]);
}
}

25
ethcore/src/views/mod.rs Normal file
View File

@@ -0,0 +1,25 @@
// 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/>.
//! Block oriented views onto rlp.
mod block;
mod header;
mod transaction;
pub use self::block::BlockView;
pub use self::header::HeaderView;
pub use self::transaction::TransactionView;

View File

@@ -0,0 +1,97 @@
// 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/>.
//! View onto transaction rlp
use util::{Rlp, U256, Bytes, Hashable, H256, View};
/// View onto transaction rlp.
pub struct TransactionView<'a> {
rlp: Rlp<'a>
}
impl<'a> TransactionView<'a> {
/// Creates new view onto block from raw bytes.
pub fn new(bytes: &'a [u8]) -> TransactionView<'a> {
TransactionView {
rlp: Rlp::new(bytes)
}
}
/// Creates new view onto block from rlp.
pub fn new_from_rlp(rlp: Rlp<'a>) -> TransactionView<'a> {
TransactionView {
rlp: rlp
}
}
/// Return reference to underlaying rlp.
pub fn rlp(&self) -> &Rlp<'a> {
&self.rlp
}
/// Get the nonce field of the transaction.
pub fn nonce(&self) -> U256 { self.rlp.val_at(0) }
/// Get the gas_price field of the transaction.
pub fn gas_price(&self) -> U256 { self.rlp.val_at(1) }
/// Get the gas field of the transaction.
pub fn gas(&self) -> U256 { self.rlp.val_at(2) }
/// Get the value field of the transaction.
pub fn value(&self) -> U256 { self.rlp.val_at(4) }
/// Get the data field of the transaction.
pub fn data(&self) -> Bytes { self.rlp.val_at(5) }
/// Get the v field of the transaction.
pub fn v(&self) -> u8 { let r: u16 = self.rlp.val_at(6); r as u8 }
/// Get the r field of the transaction.
pub fn r(&self) -> U256 { self.rlp.val_at(7) }
/// Get the s field of the transaction.
pub fn s(&self) -> U256 { self.rlp.val_at(8) }
}
impl<'a> Hashable for TransactionView<'a> {
fn sha3(&self) -> H256 {
self.rlp.as_raw().sha3()
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use rustc_serialize::hex::FromHex;
use util::U256;
use super::TransactionView;
#[test]
fn test_transaction_view() {
let rlp = "f87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804".from_hex().unwrap();
let view = TransactionView::new(&rlp);
assert_eq!(view.nonce(), U256::from(0));
assert_eq!(view.gas_price(), U256::from(1));
assert_eq!(view.gas(), U256::from(0x61a8));
assert_eq!(view.value(), U256::from(0xa));
assert_eq!(view.data(), "0000000000000000000000000000000000000000000000000000000000".from_hex().unwrap());
assert_eq!(view.r(), U256::from_str("48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353").unwrap());
assert_eq!(view.s(), U256::from_str("efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap());
assert_eq!(view.v(), 0x1b);
}
}

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env bash
PARITY_DEB_URL=https://github.com/ethcore/parity/releases/download/v1.1.0/parity_linux_1.1.0-0_amd64.deb
PARITY_DEB_URL=https://github.com/ethcore/parity/releases/download/v1.2.1/parity_linux_1.2.1-0_amd64.deb
function run_installer()

View File

@@ -139,6 +139,74 @@ impl<R: BinaryConvertable, E: BinaryConvertable> BinaryConvertable for Result<R,
}
}
impl<T> BinaryConvertable for VecDeque<T> where T: BinaryConvertable {
fn size(&self) -> usize {
match T::len_params() {
0 => mem::size_of::<T>() * self.len(),
_ => self.iter().fold(0usize, |acc, t| acc + t.size()),
}
}
fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque<usize>) -> Result<(), BinaryConvertError> {
let mut offset = 0usize;
for item in self.iter() {
let next_size = match T::len_params() {
0 => mem::size_of::<T>(),
_ => { let size = item.size(); length_stack.push_back(size); size },
};
if next_size > 0 {
let item_end = offset + next_size;
try!(item.to_bytes(&mut buffer[offset..item_end], length_stack));
offset = item_end;
}
}
Ok(())
}
fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque<usize>) -> Result<Self, BinaryConvertError> {
let mut index = 0;
let mut result = Self::with_capacity(
match T::len_params() {
0 => buffer.len() / mem::size_of::<T>(),
_ => 128,
});
if buffer.len() == 0 { return Ok(result); }
loop {
let next_size = match T::len_params() {
0 => mem::size_of::<T>(),
_ => try!(length_stack.pop_front().ok_or(BinaryConvertError)),
};
let item = if next_size == 0 {
try!(T::from_empty_bytes())
}
else {
try!(T::from_bytes(&buffer[index..index+next_size], length_stack))
};
result.push_back(item);
index = index + next_size;
if index == buffer.len() { break; }
if index + next_size > buffer.len() {
return Err(BinaryConvertError)
}
}
Ok(result)
}
fn from_empty_bytes() -> Result<Self, BinaryConvertError> {
Ok(Self::new())
}
fn len_params() -> usize {
1
}
}
//
impl<T> BinaryConvertable for Vec<T> where T: BinaryConvertable {
fn size(&self) -> usize {
match T::len_params() {

View File

@@ -54,7 +54,9 @@ mod tests {
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit" : "0x",
"daoRescueSoftFork": true
"daoHardforkTransition": "0xffffffffffffffff",
"daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000",
"daoHardforkAccounts": []
}
}
}"#;

View File

@@ -19,32 +19,38 @@
use uint::Uint;
use hash::Address;
/// Ethash params deserialization.
/// Deserializable doppelganger of EthashParams.
#[derive(Debug, PartialEq, Deserialize)]
pub struct EthashParams {
/// Gas limit divisor.
/// See main EthashParams docs.
#[serde(rename="gasLimitBoundDivisor")]
pub gas_limit_bound_divisor: Uint,
/// Minimum difficulty.
/// See main EthashParams docs.
#[serde(rename="minimumDifficulty")]
pub minimum_difficulty: Uint,
/// Difficulty bound divisor.
/// See main EthashParams docs.
#[serde(rename="difficultyBoundDivisor")]
pub difficulty_bound_divisor: Uint,
/// Block duration.
/// See main EthashParams docs.
#[serde(rename="durationLimit")]
pub duration_limit: Uint,
/// Block reward.
/// See main EthashParams docs.
#[serde(rename="blockReward")]
pub block_reward: Uint,
/// Namereg contract address.
pub registrar: Address,
/// Homestead transition block number.
/// See main EthashParams docs.
pub registrar: Option<Address>,
/// See main EthashParams docs.
#[serde(rename="frontierCompatibilityModeLimit")]
pub frontier_compatibility_mode_limit: Uint,
/// DAO rescue soft-fork?
#[serde(rename="daoRescueSoftFork")]
pub dao_rescue_soft_fork: bool,
pub frontier_compatibility_mode_limit: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="daoHardforkTransition")]
pub dao_hardfork_transition: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="daoHardforkBeneficiary")]
pub dao_hardfork_beneficiary: Option<Address>,
/// See main EthashParams docs.
#[serde(rename="daoHardforkAccounts")]
pub dao_hardfork_accounts: Option<Vec<Address>>,
}
/// Ethash engine deserialization.
@@ -70,7 +76,45 @@ mod tests {
"blockReward": "0x4563918244F40000",
"registrar": "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0x42",
"daoRescueSoftFork": true
"daoHardforkTransition": "0x08",
"daoHardforkBeneficiary": "0xabcabcabcabcabcabcabcabcabcabcabcabcabca",
"daoHardforkAccounts": [
"0x304a554a310c7e546dfe434669c62820b7d83490",
"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79",
"0xfe24cdd8648121a43a7c86d289be4dd2951ed49f",
"0x17802f43a0137c506ba92291391a8a8f207f487d",
"0xb136707642a4ea12fb4bae820f03d2562ebff487",
"0xdbe9b615a3ae8709af8b93336ce9b477e4ac0940",
"0xf14c14075d6c4ed84b86798af0956deef67365b5",
"0xca544e5c4687d109611d0f8f928b53a25af72448",
"0xaeeb8ff27288bdabc0fa5ebb731b6f409507516c",
"0xcbb9d3703e651b0d496cdefb8b92c25aeb2171f7",
"0xaccc230e8a6e5be9160b8cdf2864dd2a001c28b6",
"0x2b3455ec7fedf16e646268bf88846bd7a2319bb2",
"0x4613f3bca5c44ea06337a9e439fbc6d42e501d0a",
"0xd343b217de44030afaa275f54d31a9317c7f441e",
"0x84ef4b2357079cd7a7c69fd7a37cd0609a679106",
"0xda2fef9e4a3230988ff17df2165440f37e8b1708",
"0xf4c64518ea10f995918a454158c6b61407ea345c",
"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97",
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
]
}
}"#;
let _deserialized: Ethash = serde_json::from_str(s).unwrap();
}
#[test]
fn ethash_deserialization_missing_optionals() {
let s = r#"{
"params": {
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000"
}
}"#;

View File

@@ -17,6 +17,7 @@
//! Spec params deserialization.
use uint::Uint;
use hash::H256;
/// Spec params.
#[derive(Debug, PartialEq, Deserialize)]
@@ -33,6 +34,12 @@ pub struct Params {
/// Minimum gas limit.
#[serde(rename="minGasLimit")]
pub min_gas_limit: Uint,
/// Option fork block number to check.
#[serde(rename="forkBlock")]
pub fork_block: Option<Uint>,
/// Expected fork block hash.
#[serde(rename="forkCanonHash")]
pub fork_hash: Option<H256>,
}
#[cfg(test)]

View File

@@ -64,7 +64,9 @@ mod tests {
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit" : "0x",
"daoRescueSoftFork": false
"daoHardforkTransition": "0xffffffffffffffff",
"daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000",
"daoHardforkAccounts": []
}
}
},
@@ -73,7 +75,9 @@ mod tests {
"frontierCompatibilityModeLimit": "0x789b0",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x2"
"networkID" : "0x2",
"forkBlock": "0xffffffffffffffff",
"forkCanonHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
"genesis": {
"seal": {

View File

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

View File

@@ -35,22 +35,14 @@ Usage:
Protocol Options:
--chain CHAIN Specify the blockchain type. CHAIN may be either a
JSON chain specification file or olympic, frontier,
homestead, mainnet, morden, or testnet
[default: homestead].
homestead, mainnet, morden, homestead-dogmatic, or
testnet [default: homestead].
-d --db-path PATH Specify the database & configuration directory path
[default: $HOME/.parity].
--keys-path PATH Specify the path for JSON key files to be found
[default: $HOME/.parity/keys].
--identity NAME Specify your node's name.
DAO-Rescue Soft-fork Options:
--help-rescue-dao Does nothing - on by default.
--dont-help-rescue-dao Votes against the DAO-rescue soft-fork, but supports
it if it is triggered anyway.
Equivalent to --gas-floor-target=3141592.
--dogmatic Ignores all DAO-rescue soft-fork behaviour. Even if
it means losing mining rewards.
Account Options:
--unlock ACCOUNTS Unlock ACCOUNTS for the duration of the execution.
ACCOUNTS is a comma-delimited list of addresses.
@@ -117,7 +109,9 @@ API and Console Options:
[default: $HOME/.parity/dapps]
--signer Enable Trusted Signer WebSocket endpoint used by
Signer UIs.
Signer UIs. Default if run with ui command.
--no-signer Disable Trusted Signer WebSocket endpoint used by
Signer UIs. Default if no command is specified.
--signer-port PORT Specify the port of Trusted Signer server
[default: 8180].
--signer-path PATH Specify directory where Signer UIs tokens should
@@ -126,8 +120,34 @@ API and Console Options:
output on start up. This will prevent it.
Sealing/Mining Options:
--author ADDRESS Specify the block author (aka "coinbase") address
for sending block rewards from sealed blocks.
NOTE: MINING WILL NOT WORK WITHOUT THIS OPTION.
--force-sealing Force the node to author new blocks as if it were
always sealing/mining.
--reseal-on-txs SET Specify which transactions should force the node
to reseal a block. SET is one of:
none - never reseal on new transactions;
own - reseal only on a new local transaction;
ext - reseal only on a new external transaction;
all - reseal on all new transactions [default: own].
--reseal-min-period MS Specify the minimum time between reseals from
incoming transactions. MS is time measured in
milliseconds [default: 2000].
--work-queue-size ITEMS Specify the number of historical work packages
which are kept cached lest a solution is found for
them later. High values take more memory but result
in fewer unusable solutions [default: 20].
--tx-gas-limit GAS Apply a limit of GAS as the maximum amount of gas
a single transaction may have for it to be mined.
--relay-set SET Set of transactions to relay. SET may be:
cheap - Relay any transaction in the queue (this
may include invalid transactions);
strict - Relay only executed transactions (this
guarantees we don't relay invalid transactions, but
means we relay nothing if not mining);
lenient - Same as strict when mining, and cheap
when not [default: cheap].
--usd-per-tx USD Amount of USD to be paid for a basic transaction
[default: 0.005]. The minimum gas price is set
accordingly.
@@ -136,14 +156,19 @@ Sealing/Mining Options:
web service in turn and fallback on the last known
good value [default: auto].
--gas-floor-target GAS Amount of gas per block to target when sealing a new
block [default: 3141592].
--author ADDRESS Specify the block author (aka "coinbase") address
for sending block rewards from sealed blocks
[default: 0037a6b811ffeb6e072da21179d11b1406371c63].
block [default: 4700000].
--gas-cap GAS A cap on how large we will raise the gas limit per
block due to transaction volume [default: 6283184].
--extra-data STRING Specify a custom extra-data for authored blocks, no
more than 32 characters.
--tx-limit LIMIT Limit of transactions kept in the queue (waiting to
be included in next block) [default: 1024].
--tx-queue-size LIMIT Maximum amount of transactions in the queue (waiting
to be included in next block) [default: 1024].
--remove-solved Move solved blocks from the work package queue
instead of cloning them. This gives a slightly
faster import speed, but means that extra solutions
submitted for the same work package will go unused.
--notify-work URLS URLs to which work package notifications are pushed.
URLS should be a comma-delimited list of HTTP URLs.
Footprint Options:
--tracing BOOL Indicates if full transaction tracing should be
@@ -152,13 +177,9 @@ Footprint Options:
off. auto uses last used value of this option (off
if it does not exist) [default: auto].
--pruning METHOD Configure pruning of the state/storage trie. METHOD
may be one of auto, archive, fast, basic, light:
may be one of auto, archive, fast:
archive - keep all state trie data. No pruning.
fast - maintain journal overlay. Fast but 50MB used.
basic - reference count in disk DB. Slow, light, and
experimental!
light - early merges with partial tracking. Fast,
light, and experimental!
auto - use the method most recently synced or
default to fast if none synced [default: auto].
--cache-pref-size BYTES Specify the prefered size of the blockchain cache in
@@ -170,7 +191,12 @@ Footprint Options:
--cache MEGABYTES Set total amount of discretionary memory to use for
the entire system, overrides other cache and queue
options.
--db-cache-size MB Database cache size.
Database Options:
--db-cache-size MB Override RocksDB database cache size.
--db-compaction TYPE Database compaction type. TYPE may be one of:
ssd - suitable for SSDs and fast HDDs;
hdd - suitable for slow HDDs [default: ssd].
Import/Export Options:
--from BLOCK Export from block BLOCK, which may be an index or
@@ -241,8 +267,6 @@ pub struct Args {
pub flag_chain: String,
pub flag_db_path: String,
pub flag_identity: String,
pub flag_dont_help_rescue_dao: bool,
pub flag_dogmatic: bool,
pub flag_unlock: Option<String>,
pub flag_password: Vec<String>,
pub flag_cache: Option<usize>,
@@ -278,16 +302,25 @@ pub struct Args {
pub flag_dapps_pass: Option<String>,
pub flag_dapps_path: String,
pub flag_signer: bool,
pub flag_no_signer: bool,
pub flag_signer_port: u16,
pub flag_signer_path: String,
pub flag_no_token: bool,
pub flag_force_sealing: bool,
pub flag_author: String,
pub flag_reseal_on_txs: String,
pub flag_reseal_min_period: u64,
pub flag_work_queue_size: usize,
pub flag_remove_solved: bool,
pub flag_tx_gas_limit: Option<String>,
pub flag_relay_set: String,
pub flag_author: Option<String>,
pub flag_usd_per_tx: String,
pub flag_usd_per_eth: String,
pub flag_gas_floor_target: String,
pub flag_gas_cap: String,
pub flag_extra_data: Option<String>,
pub flag_tx_limit: usize,
pub flag_tx_queue_size: usize,
pub flag_notify_work: Option<String>,
pub flag_logging: Option<String>,
pub flag_version: bool,
pub flag_from: String,
@@ -321,6 +354,7 @@ pub struct Args {
pub flag_ipcpath: Option<String>,
pub flag_ipcapi: Option<String>,
pub flag_db_cache_size: Option<usize>,
pub flag_db_compaction: String,
}
pub fn print_version() {

View File

@@ -16,6 +16,7 @@
use std::env;
use std::fs::File;
use std::time::Duration;
use std::io::{BufRead, BufReader};
use std::net::{SocketAddr, IpAddr};
use std::path::PathBuf;
@@ -24,9 +25,11 @@ use docopt::Docopt;
use die::*;
use util::*;
use util::log::Colour::*;
use ethcore::account_provider::AccountProvider;
use util::network_settings::NetworkSettings;
use ethcore::client::{append_path, get_db_path, ClientConfig, Switch, VMType};
use ethcore::client::{append_path, get_db_path, ClientConfig, DatabaseCompactionProfile, Switch, VMType};
use ethcore::miner::{MinerOptions, PendingSet};
use ethcore::ethereum;
use ethcore::spec::Spec;
use ethsync::SyncConfig;
@@ -67,25 +70,66 @@ impl Configuration {
self.args.flag_maxpeers.unwrap_or(self.args.flag_peers) as u32
}
pub fn author(&self) -> Address {
let d = self.args.flag_etherbase.as_ref().unwrap_or(&self.args.flag_author);
Address::from_str(clean_0x(d)).unwrap_or_else(|_| {
die!("{}: Invalid address for --author. Must be 40 hex characters, with or without the 0x at the beginning.", d)
})
fn decode_u256(d: &str, argument: &str) -> U256 {
U256::from_dec_str(d).unwrap_or_else(|_|
U256::from_str(clean_0x(d)).unwrap_or_else(|_|
die!("{}: Invalid numeric value for {}. Must be either a decimal or a hex number.", d, argument)
)
)
}
pub fn gas_floor_target(&self) -> U256 {
if self.args.flag_dont_help_rescue_dao || self.args.flag_dogmatic {
4_700_000.into()
} else {
let d = &self.args.flag_gas_floor_target;
U256::from_dec_str(d).unwrap_or_else(|_| {
die!("{}: Invalid target gas floor given. Must be a decimal unsigned 256-bit number.", d)
})
fn work_notify(&self) -> Vec<String> {
self.args.flag_notify_work.as_ref().map_or_else(Vec::new, |s| s.split(',').map(|s| s.to_owned()).collect())
}
pub fn miner_options(&self) -> MinerOptions {
let (own, ext) = match self.args.flag_reseal_on_txs.as_str() {
"none" => (false, false),
"own" => (true, false),
"ext" => (false, true),
"all" => (true, true),
x => die!("{}: Invalid value for --reseal option. Use --help for more information.", x)
};
MinerOptions {
new_work_notify: self.work_notify(),
force_sealing: self.args.flag_force_sealing,
reseal_on_external_tx: ext,
reseal_on_own_tx: own,
tx_gas_limit: self.args.flag_tx_gas_limit.as_ref().map_or(!U256::zero(), |d| Self::decode_u256(d, "--tx-gas-limit")),
tx_queue_size: self.args.flag_tx_queue_size,
pending_set: match self.args.flag_relay_set.as_str() {
"cheap" => PendingSet::AlwaysQueue,
"strict" => PendingSet::AlwaysSealing,
"lenient" => PendingSet::SealingOrElseQueue,
x => die!("{}: Invalid value for --relay-set option. Use --help for more information.", x)
},
reseal_min_period: Duration::from_millis(self.args.flag_reseal_min_period),
work_queue_size: self.args.flag_work_queue_size,
enable_resubmission: !self.args.flag_remove_solved,
}
}
pub fn author(&self) -> Option<Address> {
self.args.flag_etherbase.as_ref()
.or(self.args.flag_author.as_ref())
.map(|d| Address::from_str(clean_0x(d)).unwrap_or_else(|_| {
die!("{}: Invalid address for --author. Must be 40 hex characters, with or without the 0x at the beginning.", d)
}))
}
pub fn gas_floor_target(&self) -> U256 {
let d = &self.args.flag_gas_floor_target;
U256::from_dec_str(d).unwrap_or_else(|_| {
die!("{}: Invalid target gas floor given. Must be a decimal unsigned 256-bit number.", d)
})
}
pub fn gas_ceil_target(&self) -> U256 {
let d = &self.args.flag_gas_cap;
U256::from_dec_str(d).unwrap_or_else(|_| {
die!("{}: Invalid target gas ceiling given. Must be a decimal unsigned 256-bit number.", d)
})
}
pub fn gas_price(&self) -> U256 {
match self.args.flag_gasprice.as_ref() {
@@ -114,27 +158,24 @@ impl Configuration {
let wei_per_usd: f32 = 1.0e18 / usd_per_eth;
let gas_per_tx: f32 = 21000.0;
let wei_per_gas: f32 = wei_per_usd * usd_per_tx / gas_per_tx;
info!("Using a conversion rate of Ξ1 = US${} ({} wei/gas)", usd_per_eth, wei_per_gas);
info!("Using a conversion rate of Ξ1 = {} ({} wei/gas)", paint(White.bold(), format!("US${}", usd_per_eth)), paint(Yellow.bold(), format!("{}", wei_per_gas)));
U256::from_dec_str(&format!("{:.0}", wei_per_gas)).unwrap()
}
}
}
pub fn extra_data(&self) -> Bytes {
if !self.args.flag_dont_help_rescue_dao {
(b"rescuedao"[..]).to_owned()
} else {
match self.args.flag_extradata.as_ref().or(self.args.flag_extra_data.as_ref()) {
Some(ref x) if x.len() <= 32 => x.as_bytes().to_owned(),
None => version_data(),
Some(ref x) => { die!("{}: Extra data must be at most 32 characters.", x); }
}
match self.args.flag_extradata.as_ref().or(self.args.flag_extra_data.as_ref()) {
Some(ref x) if x.len() <= 32 => x.as_bytes().to_owned(),
None => version_data(),
Some(ref x) => { die!("{}: Extra data must be at most 32 characters.", x); }
}
}
pub fn spec(&self) -> Spec {
match self.chain().as_str() {
"frontier" | "homestead" | "mainnet" => ethereum::new_frontier(!self.args.flag_dogmatic),
"frontier" | "homestead" | "mainnet" => ethereum::new_frontier(),
"homestead-dogmatic" => ethereum::new_frontier_dogmatic(),
"morden" | "testnet" => ethereum::new_morden(),
"olympic" => ethereum::new_olympic(),
f => Spec::load(contents(f).unwrap_or_else(|_| {
@@ -221,7 +262,7 @@ impl Configuration {
let mut latest_era = None;
let jdb_types = [journaldb::Algorithm::Archive, journaldb::Algorithm::EarlyMerge, journaldb::Algorithm::OverlayRecent, journaldb::Algorithm::RefCounted];
for i in jdb_types.into_iter() {
let db = journaldb::new(&append_path(&get_db_path(Path::new(&self.path()), *i, spec.genesis_header().hash()), "state"), *i, None);
let db = journaldb::new(&append_path(&get_db_path(Path::new(&self.path()), *i, spec.genesis_header().hash()), "state"), *i, kvdb::DatabaseConfig::default());
trace!(target: "parity", "Looking for best DB: {} at {:?}", i, db.latest_era());
match (latest_era, db.latest_era()) {
(Some(best), Some(this)) if best >= this => {}
@@ -272,6 +313,13 @@ impl Configuration {
// forced state db cache size if provided
client_config.db_cache_size = self.args.flag_db_cache_size.and_then(|cs| Some(cs / 4));
// compaction profile
client_config.db_compaction = match self.args.flag_db_compaction.as_str() {
"ssd" => DatabaseCompactionProfile::Default,
"hdd" => DatabaseCompactionProfile::HDD,
_ => { die!("Invalid compaction profile given (--db-compaction argument), expected hdd/default."); }
};
if self.args.flag_jitvm {
client_config.vm_type = VMType::jit().unwrap_or_else(|| die!("Parity built without jit vm."))
}
@@ -287,6 +335,7 @@ impl Configuration {
sync_config.network_id = self.args.flag_network_id.as_ref().or(self.args.flag_networkid.as_ref()).map_or(spec.network_id(), |id| {
U256::from_str(id).unwrap_or_else(|_| die!("{}: Invalid index given with --network-id/--networkid", id))
});
sync_config.fork_block = spec.fork_block().clone();
sync_config
}
@@ -432,12 +481,37 @@ impl Configuration {
}
pub fn signer_port(&self) -> Option<u16> {
if !self.args.flag_signer {
if !self.signer_enabled() {
None
} else {
Some(self.args.flag_signer_port)
}
}
pub fn rpc_interface(&self) -> String {
match self.network_settings().rpc_interface.as_str() {
"all" => "0.0.0.0",
"local" => "127.0.0.1",
x => x,
}.into()
}
pub fn dapps_interface(&self) -> String {
match self.args.flag_dapps_interface.as_str() {
"all" => "0.0.0.0",
"local" => "127.0.0.1",
x => x,
}.into()
}
pub fn dapps_enabled(&self) -> bool {
!self.args.flag_dapps_off && !self.args.flag_no_dapps
}
pub fn signer_enabled(&self) -> bool {
(self.args.cmd_ui && !self.args.flag_no_signer) ||
(!self.args.cmd_ui && self.args.flag_signer)
}
}
#[cfg(test)]

View File

@@ -45,12 +45,7 @@ pub fn new(configuration: Configuration, deps: Dependencies) -> Option<WebappSer
return None;
}
let interface = match configuration.interface.as_str() {
"all" => "0.0.0.0",
"local" => "127.0.0.1",
x => x,
};
let url = format!("{}:{}", interface, configuration.port);
let url = format!("{}:{}", configuration.interface, configuration.port);
let addr = SocketAddr::from_str(&url).unwrap_or_else(|_| die!("{}: Invalid Webapps listen host/port given.", url));
let auth = configuration.user.as_ref().map(|username| {

View File

@@ -80,7 +80,7 @@ use std::thread::sleep;
use std::time::Duration;
use rustc_serialize::hex::FromHex;
use ctrlc::CtrlC;
use util::{H256, ToPretty, NetworkConfiguration, PayloadInfo, Bytes, UtilError};
use util::{H256, ToPretty, NetworkConfiguration, PayloadInfo, Bytes, UtilError, paint, Colour, version};
use util::panics::{MayPanic, ForwardPanic, PanicHandler};
use ethcore::client::{BlockID, BlockChainClient, ClientConfig, get_db_path};
use ethcore::error::{Error, ImportError};
@@ -97,7 +97,7 @@ use rpc::RpcServer;
use signer::{SignerServer, new_token};
use dapps::WebappServer;
use io_handler::ClientIoHandler;
use configuration::Configuration;
use configuration::{Configuration};
fn main() {
let conf = Configuration::parse();
@@ -184,22 +184,24 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
let panic_handler = PanicHandler::new_in_arc();
// Setup logging
let logger = setup_log::setup_log(&conf.args.flag_logging);
let logger = setup_log::setup_log(&conf.args.flag_logging, conf.have_color());
// Raise fdlimit
unsafe { ::fdlimit::raise_fd_limit(); }
info!("Starting {}", paint(Colour::White.bold(), format!("{}", version())));
let net_settings = conf.net_settings(&spec);
let sync_config = conf.sync_config(&spec);
// Create and display a new token for UIs.
if conf.args.flag_signer && !conf.args.flag_no_token {
if conf.signer_enabled() && !conf.args.flag_no_token {
new_token(conf.directories().signer).unwrap_or_else(|e| {
die!("Error generating token: {:?}", e)
});
}
// Display warning about using unlock with signer
if conf.args.flag_signer && conf.args.flag_unlock.is_some() {
if conf.signer_enabled() && conf.args.flag_unlock.is_some() {
warn!("Using Trusted Signer and --unlock is not recommended!");
warn!("NOTE that Signer will not ask you to confirm transactions from unlocked account.");
}
@@ -208,12 +210,13 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
let account_service = Arc::new(conf.account_service());
// Miner
let miner = Miner::with_accounts(conf.args.flag_force_sealing, conf.spec(), account_service.clone());
miner.set_author(conf.author());
let miner = Miner::new(conf.miner_options(), conf.spec(), Some(account_service.clone()));
miner.set_author(conf.author().unwrap_or_default());
miner.set_gas_floor_target(conf.gas_floor_target());
miner.set_gas_ceil_target(conf.gas_ceil_target());
miner.set_extra_data(conf.extra_data());
miner.set_minimal_gas_price(conf.gas_price());
miner.set_transactions_limit(conf.args.flag_tx_limit);
miner.set_transactions_limit(conf.args.flag_tx_queue_size);
// Build client
let mut service = ClientService::start(
@@ -252,7 +255,7 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
// Setup http rpc
let rpc_server = rpc::new_http(rpc::HttpConfiguration {
enabled: network_settings.rpc_enabled,
interface: network_settings.rpc_interface.clone(),
interface: conf.rpc_interface(),
port: network_settings.rpc_port,
apis: conf.rpc_apis(),
cors: conf.rpc_cors(),
@@ -264,8 +267,8 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
if conf.args.flag_webapp { println!("WARNING: Flag -w/--webapp is deprecated. Dapps server is now on by default. Ignoring."); }
let dapps_server = dapps::new(dapps::Configuration {
enabled: !conf.args.flag_dapps_off && !conf.args.flag_no_dapps,
interface: conf.args.flag_dapps_interface.clone(),
enabled: conf.dapps_enabled(),
interface: conf.dapps_interface(),
port: conf.args.flag_dapps_port,
user: conf.args.flag_dapps_user.clone(),
pass: conf.args.flag_dapps_pass.clone(),
@@ -277,7 +280,7 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
// Set up a signer
let signer_server = signer::start(signer::Configuration {
enabled: deps_for_rpc_apis.signer_port.is_some(),
enabled: conf.signer_enabled(),
port: conf.args.flag_signer_port,
signer_path: conf.directories().signer,
}, signer::Dependencies {
@@ -296,7 +299,10 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
service.register_io_handler(io_handler).expect("Error registering IO handler");
if conf.args.cmd_ui {
url::open("http://localhost:8080/")
if !conf.dapps_enabled() {
die_with_message("Cannot use UI command with Dapps turned off.");
}
url::open(&format!("http://{}:{}/", conf.dapps_interface(), conf.args.flag_dapps_port));
}
// Handle exit
@@ -316,6 +322,8 @@ fn execute_export(conf: Configuration) {
// Setup panic handler
let panic_handler = PanicHandler::new_in_arc();
// Setup logging
let _logger = setup_log::setup_log(&conf.args.flag_logging, conf.have_color());
// Raise fdlimit
unsafe { ::fdlimit::raise_fd_limit(); }
@@ -337,7 +345,7 @@ fn execute_export(conf: Configuration) {
// Build client
let service = ClientService::start(
client_config, spec, net_settings, Path::new(&conf.path()), Arc::new(Miner::default()), false
client_config, spec, net_settings, Path::new(&conf.path()), Arc::new(Miner::with_spec(conf.spec())), false
).unwrap_or_else(|e| die_with_error("Client", e));
panic_handler.forward_from(&service);
@@ -388,6 +396,8 @@ fn execute_import(conf: Configuration) {
// Setup panic handler
let panic_handler = PanicHandler::new_in_arc();
// Setup logging
let _logger = setup_log::setup_log(&conf.args.flag_logging, conf.have_color());
// Raise fdlimit
unsafe { ::fdlimit::raise_fd_limit(); }
@@ -409,7 +419,7 @@ fn execute_import(conf: Configuration) {
// Build client
let service = ClientService::start(
client_config, spec, net_settings, Path::new(&conf.path()), Arc::new(Miner::default()), false
client_config, spec, net_settings, Path::new(&conf.path()), Arc::new(Miner::with_spec(conf.spec())), false
).unwrap_or_else(|e| die_with_error("Client", e));
panic_handler.forward_from(&service);

View File

@@ -20,7 +20,7 @@ use std::io::{Read, Write, Error as IoError, ErrorKind};
use std::path::PathBuf;
use std::fmt::{Display, Formatter, Error as FmtError};
use util::migration::{Manager as MigrationManager, Config as MigrationConfig, MigrationIterator};
use util::kvdb::{Database, DatabaseConfig};
use util::kvdb::{Database, DatabaseConfig, CompactionProfile};
use ethcore::migrations;
/// Database is assumed to be at default version, when no version file is found.
@@ -163,6 +163,7 @@ fn migrate_database(version: u32, path: PathBuf, migrations: MigrationManager) -
prefix_size: None,
max_open_files: 64,
cache_size: None,
compaction: CompactionProfile::default(),
};
// open old database

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