Compare commits

..

201 Commits

Author SHA1 Message Date
Marek Kotewicz
70389b2888 Merge pull request #922 from ethcore/beta-staging
Master to beta v1.0.2
2016-04-11 16:42:09 +02:00
debris
8f63f6d32a fixed transaction deadlock 2016-04-11 14:39:01 +02:00
debris
f02f99cd3f fixed eth_getLogs 2016-04-11 14:38:18 +02:00
Gav Wood
bbbd6f01fc --unlock is comma-delimited. 2016-04-11 14:37:10 +02:00
debris
ddbce9f014 removed empty lines 2016-04-11 14:36:27 +02:00
debris
423c5e87da fixed eth_getLogs 2016-04-11 14:36:16 +02:00
NikVolf
a15d2882d0 removing lower-level defaults 2016-04-11 14:36:02 +02:00
NikVolf
6d5809757f create provided custom dir for keys if none 2016-04-11 14:35:55 +02:00
Gav Wood
e179b0e0c2 Merge pull request #908 from ethcore/beta-staging
Master to beta 1.0.2
2016-04-09 10:18:41 -07:00
arkpar
37eb0fb04e Use new json RPC server 2016-04-09 13:31:34 +02:00
Tomasz Drwięga
32b0a80a18 Removing Option from setup_rpc_server method return type 2016-04-09 13:29:13 +02:00
Tomasz Drwięga
9df9937922 Fixing compilation with rpc feature disabled 2016-04-09 13:29:06 +02:00
debris
eae66568a9 fixed #895 2016-04-09 13:28:55 +02:00
Tomasz Drwięga
ece348d173 Avoid signalling readiness when app is about to be closed 2016-04-09 13:28:43 +02:00
arkpar
cc0c54a45c Propagate transaction queue 2016-04-09 13:28:37 +02:00
Tomasz Drwięga
3f139116b2 Reverting order of shutdown event 2016-04-09 13:26:14 +02:00
Tomasz Drwięga
771e3998a9 Updating rpc comments 2016-04-09 13:26:08 +02:00
Tomasz Drwięga
03fbde9723 More descriptive message when closing 2016-04-09 13:26:00 +02:00
Tomasz Drwięga
3303aa73ff Tracing shutdown and changed order of IoManager shutdown process 2016-04-09 13:25:54 +02:00
Tomasz Drwięga
8367be6992 Rewriting messages 2016-04-09 13:25:46 +02:00
Tomasz Drwięga
e6237ed05e Removing additional thread from JSON-RPC 2016-04-09 13:25:39 +02:00
Tomasz Drwięga
0abdcedc03 Additional logging and error messages 2016-04-09 13:25:28 +02:00
Tomasz Drwięga
59a735e2c4 Removing match on constant 2016-04-09 13:25:20 +02:00
arkpar
bf24355480 Fixed eth_call nonce and gas handling 2016-04-09 13:25:16 +02:00
NikVolf
4ed15931af replacing /home/nikky also 2016-04-09 13:21:18 +02:00
NikVolf
c5553c1f21 passing key path to all invocations 2016-04-09 13:19:09 +02:00
debris
33d633eed1 fixed #875 and added tests for eth_sendTransaction 2016-04-09 13:16:40 +02:00
Nikolay Volf
a3a0de096d replace add with or 2016-04-09 13:10:20 +02:00
Tomasz Drwięga
aed708ffd8 More descriptive expectations to transaction queue consistency. 2016-04-09 13:09:55 +02:00
Tomasz Drwięga
66d3d7ec11 Fixing typo in bigint 2016-04-09 13:09:45 +02:00
Nikolay Volf
8503aeb2df [ci skip] update misleading cli help msg for author 2016-04-09 13:09:06 +02:00
arkpar
a7ebc1dd25 Handle geth keys with lowercase crypto key 2016-04-09 13:08:52 +02:00
Robert Habermeier
584d89f964 Find geth data store cross-platform.
Fixes #869
2016-04-09 13:08:40 +02:00
arkpar
4aeaab3a2f Fixed bootnode URL and error message 2016-04-09 13:08:03 +02:00
NikVolf
9750a31336 replace popcnt with mov 2016-04-09 13:07:48 +02:00
debris
404005cc93 fixed #855 2016-04-09 13:06:51 +02:00
Gav Wood
9b5bd37dc5 Merge pull request #905 from ethcore/sync-beta
Imporved sync error handling
2016-04-08 17:43:42 -07:00
arkpar
f96e5bc0d5 v1.0.2 2016-04-06 16:15:36 +02:00
arkpar
444c9c4375 Track import errors and restart sync 2016-04-06 16:15:31 +02:00
Gav Wood
2a2c24855c Fix build. 2016-03-28 21:19:28 +02:00
Gav Wood
712302391c Use sensible gas price. 2016-03-28 20:42:23 +02:00
Gav Wood
3023d76a46 Publish locally-made transactions to peers. 2016-03-28 19:43:49 +02:00
Gav Wood
f60d74b231 Merge pull request #844 from ethcore/sync-beta
Full sync restart on bad block
2016-03-28 15:49:39 +02:00
arkpar
3e192ab486 Full restart on bad block 2016-03-28 13:05:59 +02:00
Gav Wood
fe313677b3 Merge pull request #845 from ethcore/beta-staging
Merge fixes from master to beta
2016-03-28 10:00:50 +02:00
arkpar
20f3f356e5 v1.0.1 2016-03-28 02:25:12 +02:00
NikVolf
b9141b830b test for pending 2016-03-28 02:19:29 +02:00
NikVolf
a938385692 checking tx queue 2016-03-28 02:19:19 +02:00
debris
c9ac0392d8 tests for deserialization of issue #835 2016-03-28 02:18:50 +02:00
NikVolf
02dfc8632e fix test 2016-03-28 02:17:32 +02:00
NikVolf
ac2a62707a in cli call 2016-03-28 02:17:28 +02:00
NikVolf
6f78523bf0 unlimited unlock 2016-03-28 02:15:12 +02:00
Gav Wood
5dbbf9db13 Allow passwords on multiple lines in --password files. 2016-03-28 02:13:47 +02:00
Gav Wood
0d6ffa2a97 Minor refactor. 2016-03-28 02:13:47 +02:00
Gav Wood
3afb6370f9 Unlock accounts on CLI. 2016-03-28 02:13:47 +02:00
Gav Wood
dad4bfecdf Merge pull request #828 from ethcore/optionalblocknumberinrpc
Make BlockNumber optional, fix eth_call
2016-03-26 23:29:45 +01:00
Gav Wood
902b44c94f Remove info!s. 2016-03-26 13:44:42 +01:00
Gav Wood
54bf237e4f Fix backport. 2016-03-26 13:31:04 +01:00
Gav Wood
f835ce8253 Fix eth_call so it doesn't need the secret of the sender. 2016-03-26 13:30:50 +01:00
Gav Wood
4d04668c48 Make BlockNumber optional. 2016-03-26 12:35:15 +01:00
Arkadiy Paronyan
b4d95089d4 Merge pull request #826 from ethcore/web3sha3-beta
Web3sha3 beta
2016-03-26 12:08:30 +01:00
Gav Wood
cca30f964e Update web3.rs
[ci-skip]
2016-03-26 11:22:29 +01:00
NikVolf
f11cc80561 wiki test 2016-03-26 11:22:23 +01:00
NikVolf
4f71fd5d4d avoid copy 2016-03-26 11:22:13 +01:00
NikVolf
0340466f5f web3_sha3 2016-03-26 11:22:06 +01:00
Nikolay Volf
8847819b31 Merge pull request #821 from ethcore/netidfix-beta
Use network id for the web3_net_version return.
2016-03-26 04:01:53 +04:00
Gav Wood
ca91fd5e76 Use network id for the web3_net_version return. 2016-03-26 00:22:09 +01:00
Arkadiy Paronyan
df2619a37d Merge pull request #806 from ethcore/tracegetwork-beta
Fix mining from spinning
2016-03-24 17:34:07 +01:00
arkpar
4840371635 Fixed test 2016-03-24 17:07:54 +01:00
Gav Wood
68e4156143 Don't care if engaged in sync since it's typically doing so. 2016-03-24 14:29:54 +00:00
Gav Wood
83f812b176 Fix logic. agaib. 2016-03-24 14:24:58 +00:00
Gav Wood
36c5525e3f Fix logic error. 2016-03-24 14:15:55 +00:00
Gav Wood
78b5c12cf9 Fix mining. 2016-03-24 14:13:43 +00:00
Gav Wood
0564e7c168 Fix compile. 2016-03-24 14:00:15 +00:00
Gav Wood
7a4e91d26d Add tracing. 2016-03-24 14:00:09 +00:00
Tomasz Drwięga
ec26827f58 Fixing future-current transactions clash 2016-03-23 14:45:02 +01:00
arkpar
01b71bf9ba Merge with master 2016-03-22 22:09:44 +01:00
Gav Wood
42040438ed Fix author reporting. num_cpus for JSONRPC threads. 2016-03-22 21:58:28 +01:00
Gav Wood
799828b51e Increase threads to 4. 2016-03-22 21:58:28 +01:00
debris
f78e8c3a38 fixed eth_call, eth_sendTransaction and eth_estimateGas 2016-03-22 21:58:28 +01:00
debris
4f242996d1 uncle 2016-03-22 21:58:28 +01:00
debris
daecf5db3e removed outdated comment 2016-03-22 21:58:28 +01:00
debris
9a09f52679 implemented eth_sendRawTransaction 2016-03-22 21:58:28 +01:00
debris
841a996fa6 test for eth_getTransactionReceipt 2016-03-22 21:58:28 +01:00
Alexander Orlov
ff99ccaf82 complete getting started steps for OS X
You get 
`multirust: no default toolchain configured` 
when 
`multirust default stable`
is not executed.
2016-03-22 21:58:28 +01:00
arkpar
60f2aadb8e Prettier version wo git dir; Use rustc compile time version 2016-03-22 21:53:29 +01:00
Tomasz Drwięga
c143b1b783 Validating senders balance before importing transaction to queue 2016-03-22 21:52:28 +01:00
Tomasz Drwięga
2377d46c59 Speeding up build 2016-03-22 21:44:58 +01:00
Arkadiy Paronyan
10d361aec5 Merge pull request #796 from ethcore/beta-staging
Merge master to beta
2016-03-22 20:55:57 +01:00
arkpar
bf4e4df4c8 Fixed sync tests 2016-03-21 18:51:22 +01:00
arkpar
3b766f01f2 Fixed rpc tests 2016-03-21 18:07:07 +01:00
arkpar
2aa3864d67 Merge with master 2016-03-21 15:55:46 +01:00
debris
04082d1514 client implementation of transaction receipt 2016-03-21 00:05:45 +01:00
debris
85fa07728c LocalizedReceipt 2016-03-21 00:05:45 +01:00
Tomasz Drwięga
a36ac996a0 Avoiding possible overflow when block number gets smaller. 2016-03-21 00:05:45 +01:00
Tomasz Drwięga
6e666ecac7 Fixing ethminer doctest 2016-03-21 00:05:45 +01:00
Tomasz Drwięga
08dc83205c Flipping sealing_enabled flag after no requests for sealing_block for some time 2016-03-21 00:05:43 +01:00
Gav Wood
bff142828d JSONRPC interface defaults to local.
Please enter the commit message for your changes. Lines starting
2016-03-21 00:04:55 +01:00
Gav Wood
6d1ae888ca Listen on all interfaces for JSONRPC by default. 2016-03-21 00:04:55 +01:00
debris
d5cc2c9e67 implemented rpc eth_estimateGas method, added tests for rpc eth_call and eth_estimateGas 2016-03-21 00:04:55 +01:00
debris
048dba7ef3 fixed indentation 2016-03-21 00:04:55 +01:00
debris
280c5e8a99 implementation of eth_estimateGas 2016-03-21 00:04:55 +01:00
debris
1257ad2993 fixes after merge 2016-03-21 00:04:55 +01:00
debris
5c72e60b14 implemented eth_call 2016-03-21 00:04:55 +01:00
debris
aa6b6e477c added output to execution result 2016-03-21 00:04:55 +01:00
Gav Wood
245ef854dd Allow 0x prefix for --author. 2016-03-21 00:04:55 +01:00
debris
c2cffd1e06 improvements to build, updated dependencies, moved rpctest to its own submodule 2016-03-21 00:04:53 +01:00
debris
ddab958e61 fixed missing import 2016-03-20 23:56:57 +01:00
debris
a10160bd56 use ethjson module to load chain json tests 2016-03-20 23:56:57 +01:00
debris
49be60e984 test ethjson module on travis 2016-03-20 23:56:57 +01:00
debris
2b8a151b82 fixed failing eth rpc tests 2016-03-20 23:56:57 +01:00
debris
9bcc6c9e69 next batch of rpc fixes, 103 still failing 2016-03-20 23:56:57 +01:00
debris
0fc605face rpc tests, now 421 passing / 116 failing 2016-03-20 23:56:57 +01:00
debris
8f1618687c fixed parsing blockchain file, added default account to rpc tests 2016-03-20 23:56:57 +01:00
debris
cb246c26c0 fixed invalid json files 2016-03-20 23:56:56 +01:00
debris
086e45671b removed warnings by adding missing documentation 2016-03-20 23:56:56 +01:00
debris
f3ad643b69 pricing { linear: {} } 2016-03-20 23:56:56 +01:00
debris
c5a4993e39 fixed failing builin test 2016-03-20 23:56:56 +01:00
debris
32cc0bddf6 fixed od builting parsing 2016-03-20 23:56:56 +01:00
debris
d87286c5c3 updated rpc helpers docs 2016-03-20 23:56:56 +01:00
debris
ac3acdef71 linear -> pricing 2016-03-20 23:56:56 +01:00
debris
dffa9bcef6 fixed compilation with --release flag 2016-03-20 23:56:56 +01:00
debris
9ce75a173e fixed name of rpctest executable in rpctest --help 2016-03-20 23:56:56 +01:00
debris
755faf37e3 running rpc tests 2016-03-20 23:56:56 +01:00
debris
de21fef868 new way of loading PodState 2016-03-20 23:56:56 +01:00
debris
39aa02ed26 moved ethcores spec to its own module, added genesis 2016-03-20 23:56:54 +01:00
debris
7a0dfec115 added genesis method to ethjson blockchain 2016-03-20 23:54:53 +01:00
debris
1fa019d92a ethjson spec submodule 2016-03-20 23:54:53 +01:00
debris
7105ed3f61 rpctest executable 2016-03-20 23:54:53 +01:00
Tomasz Drwięga
2f411c93fd Removing update_seal when new transactions arrives 2016-03-20 23:54:53 +01:00
Tomasz Drwięga
808f959a94 Common error handling 2016-03-20 23:54:51 +01:00
Tomasz Drwięga
2aae862330 Updating sealing when new transactions are received 2016-03-20 23:54:24 +01:00
Tomasz Drwięga
b18a7bde9a Updating gas_limit in test_client generated blocks 2016-03-20 23:53:23 +01:00
Tomasz Drwięga
a0cdf5c420 Ignoring transactions slightly above gas_limit 2016-03-20 23:53:21 +01:00
Tomasz Drwięga
b3dd72ab0a BlockGasLimit taken from push_transaction result 2016-03-20 23:52:58 +01:00
Tomasz Drwięga
4d984ead4f Fixing compilation 2016-03-20 23:52:58 +01:00
Tomasz Drwięga
fbc85e31c2 Refactoring removing invalid transactions from queue 2016-03-20 23:52:58 +01:00
Tomasz Drwięga
177d26a25e Stop adding transactions right after we know that no other will make it to block. 2016-03-20 23:52:58 +01:00
Tomasz Drwięga
1f363b22fc Removing invalid transactions from queue 2016-03-20 23:52:58 +01:00
Tomasz Drwięga
5aed421fa3 Removing allow dead_code 2016-03-20 23:52:58 +01:00
Tomasz Drwięga
f4df9c8dfd Fixing warnings 2016-03-20 23:52:58 +01:00
Tomasz Drwięga
144385e67d Bumping clippy 2016-03-20 23:52:56 +01:00
Tomasz Drwięga
9b6abb5861 Attempting to add all transactions to mined block 2016-03-20 23:52:31 +01:00
arkpar
6c81f1fb74 Prettier version wo git dir; Use rustc compile time version 2016-03-20 23:52:29 +01:00
Nikolay Volf
7371beb26c get rid of the function 2016-03-20 23:52:00 +01:00
Nikolay Volf
7acdc80b27 propagation is out 2016-03-20 23:51:59 +01:00
Nikolay Volf
3847f8a9fc no flag also 2016-03-20 23:51:58 +01:00
Tomasz Drwięga
56e977b425 Fixing doctest 2016-03-20 23:51:22 +01:00
Tomasz Drwięga
2f8e6be2ea Adding missing commas 2016-03-20 23:51:22 +01:00
Tomasz Drwięga
180debb260 Reverting check if block queue is empty 2016-03-20 23:51:22 +01:00
Tomasz Drwięga
b79c7f05c0 Increasing balance in tests 2016-03-20 23:51:22 +01:00
Tomasz Drwięga
d17c629b71 Full transaction cost 2016-03-20 23:51:22 +01:00
Tomasz Drwięga
4be4a1c151 Fixing sync test 2016-03-20 23:51:22 +01:00
Tomasz Drwięga
b0d7d48391 Adding test 2016-03-20 23:51:22 +01:00
Tomasz Drwięga
164cd268ad Fixing build 2016-03-20 23:51:22 +01:00
Tomasz Drwięga
3a16ef19c1 Removing unused import 2016-03-20 23:51:22 +01:00
Tomasz Drwięga
74ea9cc74c Validating senders balance before importing transaction to queue 2016-03-20 23:51:22 +01:00
Tomasz Drwięga
2e88183df4 Removing printlns 2016-03-20 23:51:22 +01:00
Tomasz Drwięga
fca8eb5810 Importing transactions from hashset. Notifying about every block 2016-03-20 23:51:22 +01:00
Tomasz Drwięga
df4b326cb3 Adding missing space 2016-03-20 23:51:22 +01:00
Tomasz Drwięga
4db397ecb1 Renaming status fields to something more descriptive. 2016-03-20 23:51:20 +01:00
Tomasz Drwięga
e767fd88f6 Returning number of transactions pending in block not queue 2016-03-20 23:50:59 +01:00
Tomasz Drwięga
fae7039fda Disabling benches and beta tests 2016-03-20 23:50:59 +01:00
Tomasz Drwięga
69d6f3ed3e Enabling fast finish 2016-03-20 23:50:59 +01:00
Tomasz Drwięga
4292e75dca More cleaning 2016-03-20 23:50:59 +01:00
Tomasz Drwięga
2b4640c94c Cleaning 2016-03-20 23:50:59 +01:00
Tomasz Drwięga
42a6954ec9 Speeding up build 2016-03-20 23:50:57 +01:00
Nikolay Volf
114bab66c4 overhaul to flag 2016-03-20 23:50:31 +01:00
Nikolay Volf
13d0d6d006 adding helper can_sync 2016-03-20 23:50:31 +01:00
debris
c15e78cd95 tests for loading test json files 2016-03-20 23:50:31 +01:00
debris
24993b8d4e finished blockchain test deserialization 2016-03-20 23:50:31 +01:00
debris
69d89583ca proper blockchain json parsing 2016-03-20 23:50:29 +01:00
Arkadiy Paronyan
3c8fb60cbd Update install-parity.sh 2016-03-20 23:49:34 +01:00
arkpar
9f8a131fa4 restart sync on getting old unknown header 2016-03-20 23:49:34 +01:00
Nikolay Volf
31f4a214a9 adding message from client to sync and disabling sending transactions to the queue while syncing 2016-03-20 23:49:34 +01:00
Gav Wood
81f8f939b9 Update sync_provider.rs 2016-03-20 23:49:34 +01:00
Nikolay Volf
28e4847b59 tests 2016-03-20 23:49:34 +01:00
Nikolay Volf
30ecff3959 checking queue also 2016-03-20 23:49:34 +01:00
Nikolay Volf
8add773b12 [ci skip] grammar fix 2016-03-20 23:49:34 +01:00
Nikolay Volf
c20e761051 adding check for a sync 2016-03-20 23:49:34 +01:00
arkpar
35be0e9943 Indent 2016-03-17 19:40:08 +01:00
arkpar
3bf0a00ba4 Prettier version wo git dir; Use rustc compile time version 2016-03-17 19:39:54 +01:00
arkpar
570d2c21d3 Merge branch 'sync' into beta 2016-03-15 19:44:15 +01:00
arkpar
b9fc5bdda0 Merge remote-tracking branch 'origin/transaction_queue_race' into beta 2016-03-15 12:56:30 +01:00
arkpar
1964ed7eb3 Merge remote-tracking branch 'origin/sync' into beta 2016-03-15 12:56:17 +01:00
arkpar
60bcab3e48 Merge remote-tracking branch 'origin/docker' into beta 2016-03-14 19:13:07 +01:00
arkpar
ebb7699da2 Merge remote-tracking branch 'origin/pv63-receipts' into beta 2016-03-14 18:58:23 +01:00
arkpar
78821bb935 Merge remote-tracking branch 'origin/unclesminingfix' into beta 2016-03-14 18:56:27 +01:00
arkpar
e8a21116f7 missing mut 2016-03-14 15:50:45 +01:00
Gav Wood
9f81b07224 Lock reports to avoid out of order badness. 2016-03-14 15:50:32 +01:00
arkpar
8eeda2b1a3 Fixed handshake leak 2016-03-14 15:50:03 +01:00
Arkadiy Paronyan
0087568c16 Merge pull request #712 from ethcore/beta-version
Version 1.0 in beta
2016-03-14 14:56:44 +01:00
arkpar
75a11ba9be Merge remote-tracking branch 'origin/targetgaslimit' into beta 2016-03-14 14:05:38 +01:00
Nikolay Volf
4ac9807bc1 fixing tests for beta 2016-03-14 11:12:15 +01:00
arkpar
1c26ffa208 Merge branch 'network' into beta 2016-03-14 11:11:36 +01:00
arkpar
f8b18d5d7b Merge remote-tracking branch 'origin/rpc-personal-tests' into beta 2016-03-14 10:30:22 +01:00
arkpar
b327e79b42 Merge remote-tracking branch 'origin/fixing_warnings' into beta 2016-03-14 10:28:38 +01:00
arkpar
8e2f35856a Merge remote-tracking branch 'origin/docoptclean' into beta 2016-03-14 10:26:59 +01:00
arkpar
a029551b0b Merge branch 'build' into beta 2016-03-14 09:56:44 +01:00
arkpar
320581a3e4 Merge branch 'fix-discovery' into beta 2016-03-14 01:33:41 +01:00
arkpar
f77b4119da Version 1.0 2016-03-14 01:01:15 +01:00
628 changed files with 25068 additions and 93401 deletions

View File

@@ -9,8 +9,3 @@ trim_trailing_whitespace=true
max_line_length=120 max_line_length=120
insert_final_newline=true insert_final_newline=true
[.travis.yml]
indent_style=space
indent_size=2
tab_width=8
end_of_line=lf

2
.gitignore vendored
View File

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

View File

@@ -1,347 +0,0 @@
stages:
- build
- test
variables:
GIT_DEPTH: "3"
SIMPLECOV: "true"
RUST_BACKTRACE: "1"
RUSTFLAGS: "-D warnings"
cache:
key: "$CI_BUILD_NAME/$CI_BUILD_REF_NAME"
untracked: true
linux-stable:
stage: build
image: ethcore/rust:stable
only:
- master
- beta
- tags
- stable
script:
- cargo build --release --verbose
- strip target/release/parity
- md5sum target/release/parity >> parity.md5
- sh scripts/deb-build.sh amd64
- cp target/release/parity deb/usr/bin/parity
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
- dpkg-deb -b deb "parity_"$VER"_amd64.deb"
- md5sum "parity_"$VER"_amd64.deb" >> "parity_"$VER"_amd64.deb.md5"
- aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/parity --body target/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/parity.md5 --body parity.md5
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/"parity_"$VER"_amd64.deb" --body "parity_"$VER"_amd64.deb"
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/"parity_"$VER"_amd64.deb.md5" --body "parity_"$VER"_amd64.deb.md5"
tags:
- rust
- rust-stable
artifacts:
paths:
- target/release/parity
name: "stable-x86_64-unknown-linux-gnu_parity"
linux-stable-14.04:
stage: build
image: ethcore/rust-14.04:latest
only:
- master
- beta
- tags
- stable
script:
- cargo build --release --verbose
- strip target/release/parity
- md5sum target/release/parity >> parity.md5
- sh scripts/deb-build.sh amd64
- cp target/release/parity deb/usr/bin/parity
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
- dpkg-deb -b deb "parity_"$VER"_amd64.deb"
- md5sum "parity_"$VER"_amd64.deb" >> "parity_"$VER"_amd64.deb.md5"
- aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-ubuntu_14_04-gnu/parity --body target/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-ubuntu_14_04-gnu/parity.md5 --body parity.md5
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-ubuntu_14_04-gnu/"parity_"$VER"_amd64.deb" --body "parity_"$VER"_amd64.deb"
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-ubuntu_14_04-gnu/"parity_"$VER"_amd64.deb.md5" --body "parity_"$VER"_amd64.deb.md5"
tags:
- rust
- rust-14.04
artifacts:
paths:
- target/release/parity
name: "stable-x86_64-unknown-ubuntu_14_04-gnu_parity"
linux-beta:
stage: build
image: ethcore/rust:beta
only:
- master
- beta
- tags
- stable
script:
- cargo build --release --verbose
- strip target/release/parity
tags:
- rust
- rust-beta
artifacts:
paths:
- target/release/parity
name: "beta-x86_64-unknown-linux-gnu_parity"
allow_failure: true
linux-nightly:
stage: build
image: ethcore/rust:nightly
only:
- master
- beta
- tags
- stable
script:
- cargo build --release --verbose
- strip target/release/parity
tags:
- rust
- rust-nightly
artifacts:
paths:
- target/release/parity
name: "nigthly-x86_64-unknown-linux-gnu_parity"
allow_failure: true
linux-centos:
stage: build
image: ethcore/rust-centos:latest
only:
- master
- beta
- tags
- stable
script:
- export CXX="g++"
- export CC="gcc"
- cargo build --release --verbose
- strip target/release/parity
- md5sum target/release/parity >> parity.md5
- aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/parity --body target/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/parity.md5 --body parity.md5
tags:
- rust
- rust-centos
artifacts:
paths:
- target/release/parity
name: "x86_64-unknown-centos-gnu_parity"
linux-armv7:
stage: build
image: ethcore/rust-armv7:latest
only:
- beta
- tags
- stable
script:
- rm -rf .cargo
- mkdir -p .cargo
- echo "[target.armv7-unknown-linux-gnueabihf]" >> .cargo/config
- echo "linker= \"arm-linux-gnueabihf-gcc\"" >> .cargo/config
- cat .cargo/config
- cargo build --target armv7-unknown-linux-gnueabihf --release --verbose
- arm-linux-gnueabihf-strip target/armv7-unknown-linux-gnueabihf/release/parity
- md5sum target/armv7-unknown-linux-gnueabihf/release/parity >> parity.md5
- sh scripts/deb-build.sh armhf
- cp target/armv7-unknown-linux-gnueabihf/release/parity deb/usr/bin/parity
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
- dpkg-deb -b deb "parity_"$VER"_armhf.deb"
- md5sum "parity_"$VER"_armhf.deb" >> "parity_"$VER"_armhf.deb.md5"
- aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/parity --body target/armv7-unknown-linux-gnueabihf/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/parity.md5 --body parity.md5
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/"parity_"$VER"_armhf.deb" --body "parity_"$VER"_armhf.deb"
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/"parity_"$VER"_armhf.deb.md5" --body "parity_"$VER"_armhf.deb.md5"
tags:
- rust
- rust-arm
artifacts:
paths:
- target/armv7-unknown-linux-gnueabihf/release/parity
name: "armv7_unknown_linux_gnueabihf_parity"
allow_failure: true
linux-arm:
stage: build
image: ethcore/rust-arm:latest
only:
- beta
- tags
- stable
script:
- rm -rf .cargo
- mkdir -p .cargo
- echo "[target.arm-unknown-linux-gnueabihf]" >> .cargo/config
- echo "linker= \"arm-linux-gnueabihf-gcc\"" >> .cargo/config
- cat .cargo/config
- cargo build --target arm-unknown-linux-gnueabihf --release --verbose
- arm-linux-gnueabihf-strip target/arm-unknown-linux-gnueabihf/release/parity
- md5sum target/arm-unknown-linux-gnueabihf/release/parity >> parity.md5
- sh scripts/deb-build.sh armhf
- cp target/arm-unknown-linux-gnueabihf/release/parity deb/usr/bin/parity
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
- dpkg-deb -b deb "parity_"$VER"_armhf.deb"
- md5sum "parity_"$VER"_armhf.deb" >> "parity_"$VER"_armhf.deb.md5"
- aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/parity --body target/arm-unknown-linux-gnueabihf/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/parity.md5 --body parity.md5
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/"parity_"$VER"_armhf.deb" --body "parity_"$VER"_armhf.deb"
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/"parity_"$VER"_armhf.deb.md5" --body "parity_"$VER"_armhf.deb.md5"
tags:
- rust
- rust-arm
artifacts:
paths:
- target/arm-unknown-linux-gnueabihf/release/parity
name: "arm-unknown-linux-gnueabihf_parity"
allow_failure: true
linux-armv6:
stage: build
image: ethcore/rust-armv6:latest
only:
- beta
- tags
- stable
script:
- rm -rf .cargo
- mkdir -p .cargo
- echo "[target.arm-unknown-linux-gnueabi]" >> .cargo/config
- echo "linker= \"arm-linux-gnueabi-gcc\"" >> .cargo/config
- cat .cargo/config
- cargo build --target arm-unknown-linux-gnueabi --release --verbose
- arm-linux-gnueabi-strip target/arm-unknown-linux-gnueabi/release/parity
- md5sum target/arm-unknown-linux-gnueabi/release/parity >> parity.md5
- aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabi/parity --body target/arm-unknown-linux-gnueabi/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabi/parity.md5 --body parity.md5
tags:
- rust
- rust-arm
artifacts:
paths:
- target/arm-unknown-linux-gnueabi/release/parity
name: "arm-unknown-linux-gnueabi_parity"
allow_failure: true
linux-aarch64:
stage: build
image: ethcore/rust-aarch64:latest
only:
- beta
- tags
- stable
script:
- rm -rf .cargo
- mkdir -p .cargo
- echo "[target.aarch64-unknown-linux-gnu]" >> .cargo/config
- echo "linker= \"aarch64-linux-gnu-gcc\"" >> .cargo/config
- cat .cargo/config
- cargo build --target aarch64-unknown-linux-gnu --release --verbose
- aarch64-linux-gnu-strip target/aarch64-unknown-linux-gnu/release/parity
- md5sum target/aarch64-unknown-linux-gnu/release/parity >> parity.md5
- sh scripts/deb-build.sh arm64
- cp target/aarch64-unknown-linux-gnu/release/parity deb/usr/bin/parity
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
- dpkg-deb -b deb "parity_"$VER"_arm64.deb"
- md5sum "parity_"$VER"_arm64.deb" >> "parity_"$VER"_arm64.deb.md5"
- aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/aarch64-unknown-linux-gnu/parity --body target/aarch64-unknown-linux-gnu/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/aarch64-unknown-linux-gnu/parity.md5 --body parity.md5
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/aarch64-unknown-linux-gnu/"parity_"$VER"_arm64.deb" --body "parity_"$VER"_arm64.deb"
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/aarch64-unknown-linux-gnu/"parity_"$VER"_arm64.deb.md5" --body "parity_"$VER"_arm64.deb.md5"
tags:
- rust
- rust-arm
artifacts:
paths:
- target/aarch64-unknown-linux-gnu/release/parity
name: "aarch64-unknown-linux-gnu_parity"
allow_failure: true
darwin:
stage: build
only:
- master
- beta
- tags
- stable
script:
- cargo build --release --verbose
- rm -rf parity.md5
- md5sum target/release/parity >> parity.md5
- aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-apple-darwin/parity --body target/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-apple-darwin/parity.md5 --body parity.md5
tags:
- osx
artifacts:
paths:
- target/release/parity
name: "x86_64-apple-darwin_parity"
windows:
stage: build
only:
- master
- beta
- tags
- stable
script:
- set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include;C:\vs2015\VC\include;C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt
- set LIB=C:\vs2015\VC\lib;C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10240.0\ucrt\x64
- set RUST_BACKTRACE=1
- set RUSTFLAGS=%RUSTFLAGS% -D warnings
- rustup default stable-x86_64-pc-windows-msvc
- cargo build --release --verbose
- curl -sL --url "https://github.com/ethcore/win-build/raw/master/SimpleFC.dll" -o nsis\SimpleFC.dll
- curl -sL --url "https://github.com/ethcore/win-build/raw/master/vc_redist.x64.exe" -o nsis\vc_redist.x64.exe
- signtool sign /f %keyfile% /p %certpass% target\release\parity.exe
- cd nsis
- makensis.exe installer.nsi
- copy installer.exe InstallParity.exe
- signtool sign /f %keyfile% /p %certpass% InstallParity.exe
- md5sums InstallParity.exe > InstallParity.exe.md5
- zip win-installer.zip InstallParity.exe InstallParity.exe.md5
- md5sums win-installer.zip > win-installer.zip.md5
- cd ..\target\release\
- md5sums parity.exe parity.pdb > parity.md5
- md5sums parity.exe > parity.exe.md5
- zip parity.zip parity.exe parity.pdb parity.md5
- md5sums parity.zip > parity.zip.md5
- cd ..\..
- aws configure set aws_access_key_id %s3_key%
- aws configure set aws_secret_access_key %s3_secret%
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.exe --body target\release\parity.exe
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.exe.md5 --body target\release\parity.exe.md5
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.zip --body target\release\parity.zip
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.zip.md5 --body target\release\parity.zip.md5
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/InstallParity.exe --body nsis\InstallParity.exe
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/InstallParity.exe.md5 --body nsis\InstallParity.exe.md5
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/win-installer.zip --body nsis\win-installer.zip
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/win-installer.zip.md5 --body nsis\win-installer.zip.md5
tags:
- rust-windows
artifacts:
paths:
- target/release/parity.exe
- target/release/parity.pdb
- nsis/InstallParity.exe
name: "x86_64-pc-windows-msvc_parity"
test-linux:
stage: test
before_script:
- git submodule update --init --recursive
script:
- export RUST_BACKTRACE=1
- ./test.sh --verbose
tags:
- rust-test
dependencies:
- linux-stable

View File

@@ -1,7 +1,6 @@
sudo: required sudo: required
dist: trusty dist: trusty
language: rust language: rust
branches: branches:
only: only:
- master - master
@@ -9,69 +8,96 @@ branches:
- /^stable-.*$/ - /^stable-.*$/
- /^beta$/ - /^beta$/
- /^stable$/ - /^stable$/
git: git:
depth: 3 depth: 3
matrix: matrix:
fast_finish: true
allow_failures:
- rust: nightly
include: include:
- rust: stable - rust: stable
env: RUN_TESTS="true" env: FEATURES="--features travis-beta" RUN_TESTS="true"
- rust: beta # - rust: beta
env: RUN_COVERAGE="true" # env: FEATURES="--features travis-beta" RUN_TESTS="true"
- rust: stable - rust: stable
env: RUN_DOCS="true" env: FEATURES="--features travis-beta" RUN_BUILD="true"
- rust: beta
env: FEATURES="--features travis-beta" RUN_BUILD="true"
- rust: stable
env: FEATURES="--features travis-beta" RUN_COVERAGE="true"
# - rust: nightly
# env: FEATURES="--features travis-nightly" RUN_BENCHES="true"
- rust: nightly
env: FEATURES="--features travis-nightly" RUN_TESTS="true"
env: env:
global: global:
- CXX="g++-4.8" # GH_TOKEN
- CC="gcc-4.8" - secure: bumJASbZSU8bxJ0EyPUJmu16AiV9EXOpyOj86Jlq/Ty9CfwGqsSXt96uDyE+OUJf34RUFQMsw0nk37/zC4lcn6kqk2wpuH3N/o85Zo/cVZY/NusBWLQqtT5VbYWsV+u2Ua4Tmmsw8yVYQhYwU2ZOejNpflL+Cs9XGgORp1L+/gMRMC2y5Se6ZhwnKPQlRJ8LGsG1dzjQULxzADIt3/zuspNBS8a2urJwlHfGMkvHDoUWCviP/GXoSqw3TZR7FmKyxE19I8n9+iSvm9+oZZquvcgfUxMHn8Gq/b44UbPvjtFOg2yam4xdWXF/RyWCHdc/R9EHorSABeCbefIsm+zcUF3/YQxwpSxM4IZEeH2rTiC7dcrsKw3XsO16xFQz5YI5Bay+CT/wTdMmJd7DdYz7Dyf+pOvcM9WOf/zorxYWSBOMYy0uzbusU2iyIghQ82s7E/Ahg+WARtPgkuTLSB5aL1oCTBKHqQscMr7lo5Ti6RpWLxEdTQMBznc+bMr+6dEtkEcG9zqc6cE9XX+ox3wTU6+HVMfQ1ltCntJ4UKcw3A6INEbw9wgocQa812CIASQ2fE+SCAbz6JxBjIAlFUnD1lUB7S8PdMPwn9plfQgKQ2A5YZqg6FnBdf0rQXIJYxQWKHXj/rBHSUCT0tHACDlzTA+EwWggvkP5AGIxRxm8jhw=
- RUST_BACKTRACE="1" - CVER=5
- NUM_JOBS=1
# - TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer"
- TARGETS="-p ethcore-util"
- ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}"
- KCOV_FEATURES=""
- KCOV_CMD="./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov"
- RUN_TESTS="false" - RUN_TESTS="false"
- RUN_COVERAGE="false" - RUN_COVERAGE="false"
- RUN_DOCS="false" - RUN_BUILD="false"
# GH_TOKEN for documentation - RUN_BENCHES="false"
- secure: bumJASbZSU8bxJ0EyPUJmu16AiV9EXOpyOj86Jlq/Ty9CfwGqsSXt96uDyE+OUJf34RUFQMsw0nk37/zC4lcn6kqk2wpuH3N/o85Zo/cVZY/NusBWLQqtT5VbYWsV+u2Ua4Tmmsw8yVYQhYwU2ZOejNpflL+Cs9XGgORp1L+/gMRMC2y5Se6ZhwnKPQlRJ8LGsG1dzjQULxzADIt3/zuspNBS8a2urJwlHfGMkvHDoUWCviP/GXoSqw3TZR7FmKyxE19I8n9+iSvm9+oZZquvcgfUxMHn8Gq/b44UbPvjtFOg2yam4xdWXF/RyWCHdc/R9EHorSABeCbefIsm+zcUF3/YQxwpSxM4IZEeH2rTiC7dcrsKw3XsO16xFQz5YI5Bay+CT/wTdMmJd7DdYz7Dyf+pOvcM9WOf/zorxYWSBOMYy0uzbusU2iyIghQ82s7E/Ahg+WARtPgkuTLSB5aL1oCTBKHqQscMr7lo5Ti6RpWLxEdTQMBznc+bMr+6dEtkEcG9zqc6cE9XX+ox3wTU6+HVMfQ1ltCntJ4UKcw3A6INEbw9wgocQa812CIASQ2fE+SCAbz6JxBjIAlFUnD1lUB7S8PdMPwn9plfQgKQ2A5YZqg6FnBdf0rQXIJYxQWKHXj/rBHSUCT0tHACDlzTA+EwWggvkP5AGIxRxm8jhw=
- KCOV_CMD="./kcov-master/tmp/usr/local/bin/kcov"
cache: cache:
apt: true apt: true
directories: directories:
- $TRAVIS_BUILD_DIR/target - $TRAVIS_BUILD_DIR/target
- $TRAVIS_BUILD_DIR/kcov-master
- $HOME/.cargo - $HOME/.cargo
addons: addons:
apt: apt:
sources:
- ubuntu-toolchain-r-test
packages: packages:
- libcurl4-openssl-dev - libcurl4-openssl-dev
- libelf-dev - libelf-dev
- libdw-dev - libdw-dev
- gcc-4.8
- g++-4.8
install:
- ([ "$RUN_COVERAGE" = "false" ]) || (test -x $KCOV_CMD) || (
wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz &&
tar xzf master.tar.gz &&
mkdir -p kcov-master/build &&
cd kcov-master/build &&
cmake .. &&
make && make install DESTDIR=../tmp &&
cd
)
script: script:
- if [ "$RUN_TESTS" = "true" ]; then ./test.sh --verbose; fi - echo "$TRAVIS_BUILD_DIR/target"
- if [ "$RUN_COVERAGE" = "true" ]; then ./scripts/cov.sh "$KCOV_CMD"; fi - ls "$TRAVIS_BUILD_DIR/target"
- if [ "$RUN_TESTS" = "true" ]; then cargo test --release --verbose ${FEATURES} ${TARGETS}; fi
- if [ "$RUN_BENCHES" = "true" ]; then cargo bench --no-run ${FEATURES} ${TARGETS}; fi
- if [ "$RUN_BUILD" = "true" ]; then cargo build --release --verbose ${FEATURES}; fi
- if [ "$RUN_BUILD" = "true" ]; then tar cvzf parity${ARCHIVE_SUFFIX}.tar.gz -C target/release parity; fi
after_success: | after_success: |
[ "$RUN_COVERAGE" = "true" ] &&
wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz &&
tar xzf master.tar.gz && mkdir kcov-master/build && cd kcov-master/build && cmake .. && make && make install DESTDIR=../tmp && cd ../.. &&
cargo test --no-run ${KCOV_FEATURES} ${TARGETS} &&
$KCOV_CMD target/debug/deps/ethcore_util-* &&
$KCOV_CMD target/debug/deps/ethash-* &&
$KCOV_CMD target/debug/deps/ethcore-* &&
$KCOV_CMD target/debug/deps/ethsync-* &&
$KCOV_CMD target/debug/deps/ethcore_rpc-* &&
$KCOV_CMD target/debug/deps/ethminer-* &&
$KCOV_CMD target/debug/parity-* &&
[ $TRAVIS_BRANCH = master ] && [ $TRAVIS_BRANCH = master ] &&
[ $TRAVIS_PULL_REQUEST = false ] && [ $TRAVIS_PULL_REQUEST = false ] &&
[ "$RUN_DOCS" = "true" ] && [ $TRAVIS_RUST_VERSION = stable ] &&
./scripts/doc.sh && cargo doc --no-deps --verbose ${KCOV_FEATURES} ${TARGETS} &&
echo '<meta http-equiv=refresh content=0;url=ethcore/index.html>' > target/doc/index.html &&
pip install --user ghp-import && pip install --user ghp-import &&
/home/travis/.local/bin/ghp-import -n target/doc && /home/travis/.local/bin/ghp-import -n target/doc &&
git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages
deploy:
provider: releases
api_key:
secure: "t+oGT/4lsy7IScw5s86Dpntl5Nyck4qG6nhHwMScc6FYzwLldgwgJaafL8Ej+HG+b7nFLriN+Snoa4YQ5o74X5ZlSWubVREOYQlL/fq7vcPB0DwAZ0Jufq1QW2R1M+3SwwF1eAwTv2W3G7A2K7dxjCVvENcy/gdxnZ36NeUPsqaCC9UcI2Yc7+4jyQwvx6ZfBvQeu+HbKENA0eUNs2ZQOID/1IPy0LJBvSyxAQYsysXdjTzGdNu4+Iba20E8uWYe4fAbgz+gwGarXg1L6D6gKyMlWkViqWjvXWBuDJJqMQZ3rw41AwZOoh3mKd2Lc0l6l4oZcEqPuob0yKTNjz1tuJy9xKTC2F2bDzsvUgk1IRfMK5ukXXXS09ZCZWuA9/GtnsqJ1xGTiwX+DhQzpVBHaBiseSNlYE1YN/3jNyGY+iSts1qut+1BwE7swmcTLsAPoAy8Ue+f7ErNoCg1lm71vq7VO2DLn7x2NqHyHUEuJ+7olDHSdE84G7d9otDRu/+TfMOw7GXwTaha6yJRInuNsnj4CFMLNVvYACzCC2idB7f7nUZoSFi9jf18S9fCMPVmazMrFj4g95HWrVHkjpV5zRTeUdTWw6DJl6pC9HFqORHdCvLv4Rc4dm5r3CmOcAQ0ZuiccV2oKzw4/Wic96daae8M5f5KSQ/WTr+h0wXZKp0="
skip_cleanup: true
file: parity${ARCHIVE_SUFFIX}.tar.gz
on:
tags: true
notifications:
webhooks:
urls:
- https://hooks.slack.com/services/${SLACK_WEBHOOK}
on_success: always
on_failure: always
on_start: never

1366
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,13 @@
[package] [package]
description = "Ethcore client." description = "Ethcore client."
name = "parity" name = "parity"
version = "1.3.14" version = "1.0.2"
license = "GPL-3.0" license = "GPL-3.0"
authors = ["Ethcore <admin@ethcore.io>"] authors = ["Ethcore <admin@ethcore.io>"]
build = "build.rs" build = "build.rs"
[build-dependencies] [build-dependencies]
rustc_version = "0.1" rustc_version = "0.1"
syntex = "*"
ethcore-ipc-codegen = { path = "ipc/codegen" }
ethcore-ipc-tests = { path = "ipc/tests" }
[dependencies] [dependencies]
log = "0.3" log = "0.3"
@@ -18,50 +15,26 @@ env_logger = "0.3"
rustc-serialize = "0.3" rustc-serialize = "0.3"
docopt = "0.6" docopt = "0.6"
time = "0.1" time = "0.1"
ctrlc = { git = "https://github.com/tomusdrw/rust-ctrlc.git" }
fdlimit = { path = "util/fdlimit" }
daemonize = "0.2"
num_cpus = "0.2" num_cpus = "0.2"
number_prefix = "0.2" number_prefix = "0.2"
rpassword = "0.2.1" rpassword = "0.1"
semver = "0.2" clippy = { version = "0.0.54", optional = true }
ansi_term = "0.7"
lazy_static = "0.2"
regex = "0.1"
isatty = "0.1"
ctrlc = { git = "https://github.com/ethcore/rust-ctrlc.git" }
fdlimit = { path = "util/fdlimit" }
ethcore = { path = "ethcore" } ethcore = { path = "ethcore" }
ethcore-util = { path = "util" } ethcore-util = { path = "util" }
ethsync = { path = "sync" } ethsync = { path = "sync" }
ethcore-io = { path = "util/io" } ethminer = { path = "miner" }
ethcore-devtools = { path = "devtools" } ethcore-devtools = { path = "devtools" }
ethcore-rpc = { path = "rpc" } ethcore-rpc = { path = "rpc", optional = true }
ethcore-signer = { path = "signer" }
ethcore-ipc-nano = { path = "ipc/nano" }
ethcore-ipc = { path = "ipc/rpc" }
ethcore-ipc-hypervisor = { path = "ipc/hypervisor" }
ethcore-logger = { path = "logger" }
json-ipc-server = { git = "https://github.com/ethcore/json-ipc-server.git", branch = "beta" }
ethcore-dapps = { path = "dapps", optional = true }
clippy = { version = "0.0.80", optional = true}
[target.'cfg(windows)'.dependencies]
winapi = "0.2"
[target.'cfg(not(windows))'.dependencies]
daemonize = "0.2"
[dependencies.hyper]
version = "0.8"
default-features = false
[features] [features]
default = ["ui", "use-precompiled-js"] default = ["rpc"]
ui = ["dapps", "ethcore-signer/ui"] rpc = ["ethcore-rpc"]
use-precompiled-js = ["ethcore-dapps/use-precompiled-js", "ethcore-signer/use-precompiled-js"] dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethminer/dev"]
dapps = ["ethcore-dapps"] travis-beta = ["ethcore/json-tests"]
ipc = ["ethcore/ipc"] travis-nightly = ["ethcore/json-tests", "dev"]
jit = ["ethcore/jit"]
dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethcore-dapps/dev", "ethcore-signer/dev"]
json-tests = ["ethcore/json-tests"]
[[bin]] [[bin]]
path = "parity/main.rs" path = "parity/main.rs"
@@ -70,4 +43,3 @@ name = "parity"
[profile.release] [profile.release]
debug = false debug = false
lto = false lto = false

View File

@@ -1,11 +1,6 @@
# [Parity](https://ethcore.io/parity.html) # ethcore
### Fast, light, and robust Ethereum implementation
[![Build Status][travis-image]][travis-url] [![Coverage Status][coveralls-image]][coveralls-url] [![Join the chat at https://gitter.im/ethcore/parity][gitter-image]][gitter-url] [![GPLv3][license-image]][license-url] [![Build Status][travis-image]][travis-url] [![Coverage Status][coveralls-image]][coveralls-url] [![Join the chat at https://gitter.im/trogdoro/xiki][gitter-image]][gitter-url] [![GPLv3][license-image]][license-url]
[Internal Documentation][doc-url]
Be sure to check out [our wiki][wiki-url] for more information.
[travis-image]: https://travis-ci.org/ethcore/parity.svg?branch=master [travis-image]: https://travis-ci.org/ethcore/parity.svg?branch=master
[travis-url]: https://travis-ci.org/ethcore/parity [travis-url]: https://travis-ci.org/ethcore/parity
@@ -15,78 +10,31 @@ Be sure to check out [our wiki][wiki-url] for more information.
[gitter-url]: https://gitter.im/ethcore/parity?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge [gitter-url]: https://gitter.im/ethcore/parity?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
[license-image]: https://img.shields.io/badge/license-GPL%20v3-green.svg [license-image]: https://img.shields.io/badge/license-GPL%20v3-green.svg
[license-url]: http://www.gnu.org/licenses/gpl-3.0.en.html [license-url]: http://www.gnu.org/licenses/gpl-3.0.en.html
[doc-url]: http://ethcore.github.io/parity/ethcore/index.html
[wiki-url]: https://github.com/ethcore/parity/wiki
---- [Documentation](http://ethcore.github.io/parity/ethcore/index.html)
## About Parity ### Building from source
Parity's goal is to be the fastest, lightest, and most secure Ethereum client. We are developing Parity using the sophisticated and First (if you don't already have it) get multirust:
cutting-edge Rust programming language. Parity is licensed under the GPLv3, and can be used for all your Ethereum needs.
By default, Parity will run a JSONRPC server on `127.0.0.1:8545`. This is fully configurable and supports a number
of RPC APIs.
Parity also runs a server for running decentralized apps, or "Dapps", on `http://127.0.0.1:8080`.
This includes a few useful Dapps, including Ethereum Wallet, Maker OTC, and a node status page.
In a near-future release, it will be easy to install Dapps and use them through this web interface.
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.2. You can download it at https://ethcore.io/parity.html or follow the instructions
below to build from source.
----
## Build dependencies
Parity is fully compatible with Stable Rust.
We recommend installing Rust through [rustup](https://www.rustup.rs/). If you don't already have rustup, you can install it like this:
- Linux and OSX:
```bash
$ curl https://sh.rustup.rs -sSf | sh
```
- Windows
Make sure you have Visual Studio 2015 with C++ support installed. Next, download and run the rustup installer from
https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe, start "VS2015 x64 Native Tools Command Prompt", and use the following command to install and set up the msvc toolchain:
```
$ rustup default stable-x86_64-pc-windows-msvc
```
Once you have rustup, install parity or download and build from source
----
## Quick install
- Linux:
```bash ```bash
cargo install --git https://github.com/ethcore/parity.git parity curl -sf https://raw.githubusercontent.com/brson/multirust/master/quick-install.sh | sudo sh -s -- --yes
``` ```
---- - OSX with Homebrew:
```bash
brew update && brew install multirust
multirust default stable
```
## Build from source Then, download and build Parity:
```bash ```bash
# download Parity code # download Parity code
$ git clone https://github.com/ethcore/parity git clone https://github.com/ethcore/parity
$ cd parity cd parity
# build in release mode # build in release mode
$ cargo build --release cargo build --release
``` ```
This will produce an executable in the `./target/release` subdirectory.
To get started, just run
```bash
$ ./target/release/parity
```
and parity will begin syncing the Ethereum blockchain.

View File

@@ -1,50 +0,0 @@
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
RUSTFLAGS: -Zorbit=off
branches:
only:
- master
- /^beta-.*$/
- /^stable-.*$/
- /^beta$/
- /^stable$/
install:
- git submodule update --init --recursive
- ps: Install-Product node 6
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.12.0-x86_64-pc-windows-msvc.exe"
- ps: Start-FileDownload "https://github.com/ethcore/win-build/raw/master/SimpleFC.dll" -FileName nsis\SimpleFC.dll
- ps: Start-FileDownload "https://github.com/ethcore/win-build/raw/master/vc_redist.x64.exe" -FileName nsis\vc_redist.x64.exe
- rust-1.12.0-x86_64-pc-windows-msvc.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
- SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin;C:\Program Files (x86)\NSIS;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Bin
- rustc -V
- cargo -V
- node -v
- npm -v
build: off
test_script:
- cargo test --verbose --release
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)
cache:
- target
- C:\users\appveyor\.cargo -> appveyor.yml

37
cov.sh Executable file
View File

@@ -0,0 +1,37 @@
#!/bin/sh
# Installing KCOV under ubuntu
# https://users.rust-lang.org/t/tutorial-how-to-collect-test-coverages-for-rust-project/650#
### Install deps
# $ sudo apt-get install libcurl4-openssl-dev libelf-dev libdw-dev cmake gcc binutils-dev libiberty-dev
#
### Compile kcov
# $ wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz && tar xf master.tar.gz
# $ cd kcov-master && mkdir build && cd build
# $ cmake .. && make && sudo make install
### Running coverage
if ! type kcov > /dev/null; then
echo "Install kcov first (details inside this file). Aborting."
exit 1
fi
cargo test \
-p ethash \
-p ethcore-util \
-p ethcore \
-p ethsync \
-p ethcore-rpc \
-p parity \
-p ethminer \
--no-run || exit $?
rm -rf target/coverage
mkdir -p target/coverage
EXCLUDE="~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests"
kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethcore-*
kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethash-*
kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethcore_util-*
kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethsync-*
kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethcore_rpc-*
kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethminer-*
xdg-open target/coverage/index.html

View File

@@ -1,46 +0,0 @@
[package]
description = "Parity Dapps crate"
name = "ethcore-dapps"
version = "1.3.0"
license = "GPL-3.0"
authors = ["Ethcore <admin@ethcore.io"]
build = "build.rs"
[lib]
[dependencies]
log = "0.3"
jsonrpc-core = "2.1"
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc-http-server.git", branch = "beta" }
hyper = { default-features = false, git = "https://github.com/ethcore/hyper" }
unicase = "1.3"
url = "1.0"
rustc-serialize = "0.3"
serde = "0.7.0"
serde_json = "0.7.0"
serde_macros = { version = "0.7.0", optional = true }
ethcore-rpc = { path = "../rpc" }
ethcore-util = { path = "../util" }
parity-dapps = { git = "https://github.com/ethcore/parity-ui.git", version = "1.4" }
# List of apps
parity-dapps-status = { git = "https://github.com/ethcore/parity-ui.git", version = "1.4" }
parity-dapps-home = { git = "https://github.com/ethcore/parity-ui.git", version = "1.4" }
parity-dapps-wallet = { git = "https://github.com/ethcore/parity-ui.git", version = "1.4", optional = true }
mime_guess = { version = "1.6.1" }
clippy = { version = "0.0.80", optional = true}
[build-dependencies]
serde_codegen = { version = "0.7.0", optional = true }
syntex = "*"
[features]
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

@@ -1,45 +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/>.
#[cfg(not(feature = "serde_macros"))]
mod inner {
extern crate syntex;
extern crate serde_codegen;
use std::env;
use std::path::Path;
pub fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
let src = Path::new("./src/api/types.rs.in");
let dst = Path::new(&out_dir).join("types.rs");
let mut registry = syntex::Registry::new();
serde_codegen::register(&mut registry);
registry.expand("", &src, &dst).unwrap();
}
}
#[cfg(feature = "serde_macros")]
mod inner {
pub fn main() {}
}
fn main() {
inner::main();
}

View File

@@ -1,101 +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 std::sync::Arc;
use hyper::{server, net, Decoder, Encoder, Next};
use api::types::{App, ApiError};
use api::response::{as_json, as_json_error, ping_response};
use handlers::extract_url;
use endpoint::{Endpoint, Endpoints, Handler, EndpointPath};
#[derive(Clone)]
pub struct RestApi {
local_domain: String,
endpoints: Arc<Endpoints>,
}
impl RestApi {
pub fn new(local_domain: String, endpoints: Arc<Endpoints>) -> Box<Endpoint> {
Box::new(RestApi {
local_domain: local_domain,
endpoints: endpoints,
})
}
fn list_apps(&self) -> Vec<App> {
self.endpoints.iter().filter_map(|(ref k, ref e)| {
e.info().map(|ref info| App::from_info(k, info))
}).collect()
}
}
impl Endpoint for RestApi {
fn to_handler(&self, _path: EndpointPath) -> Box<Handler> {
Box::new(RestApiRouter {
api: self.clone(),
handler: as_json_error(&ApiError {
code: "404".into(),
title: "Not Found".into(),
detail: "Resource you requested has not been found.".into(),
}),
})
}
}
struct RestApiRouter {
api: RestApi,
handler: Box<Handler>,
}
impl server::Handler<net::HttpStream> for RestApiRouter {
fn on_request(&mut self, request: server::Request<net::HttpStream>) -> Next {
let url = extract_url(&request);
if url.is_none() {
// Just return 404 if we can't parse URL
return Next::write();
}
let url = url.expect("Check for None is above; qed");
let endpoint = url.path.get(1).map(|v| v.as_str());
let handler = endpoint.and_then(|v| match v {
"apps" => Some(as_json(&self.api.list_apps())),
"ping" => Some(ping_response(&self.api.local_domain)),
_ => None,
});
// Overwrite default
if let Some(h) = handler {
self.handler = h;
}
self.handler.on_request(request)
}
fn on_request_readable(&mut self, decoder: &mut Decoder<net::HttpStream>) -> Next {
self.handler.on_request_readable(decoder)
}
fn on_response(&mut self, res: &mut server::Response) -> Next {
self.handler.on_response(res)
}
fn on_response_writable(&mut self, encoder: &mut Encoder<net::HttpStream>) -> Next {
self.handler.on_response_writable(encoder)
}
}

View File

@@ -1,27 +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/>.
//! REST API
#![cfg_attr(feature="nightly", feature(custom_derive, custom_attribute, plugin))]
#![cfg_attr(feature="nightly", plugin(serde_macros, clippy))]
mod api;
mod response;
mod types;
pub use self::api::RestApi;
pub use self::types::App;

View File

@@ -1,36 +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 serde::Serialize;
use serde_json;
use endpoint::Handler;
use handlers::{ContentHandler, EchoHandler};
pub fn as_json<T : Serialize>(val: &T) -> Box<Handler> {
Box::new(ContentHandler::ok(serde_json::to_string(val).unwrap(), "application/json".to_owned()))
}
pub fn as_json_error<T : Serialize>(val: &T) -> Box<Handler> {
Box::new(ContentHandler::not_found(serde_json::to_string(val).unwrap(), "application/json".to_owned()))
}
pub fn ping_response(local_domain: &str) -> Box<Handler> {
Box::new(EchoHandler::cors(vec![
format!("http://{}", local_domain),
// Allow CORS calls also for localhost
format!("http://{}", local_domain.replace("127.0.0.1", "localhost")),
]))
}

View File

@@ -1,21 +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/>.
#[cfg(feature = "serde_macros")]
include!("types.rs.in");
#[cfg(not(feature = "serde_macros"))]
include!(concat!(env!("OUT_DIR"), "/types.rs"));

View File

@@ -1,50 +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 endpoint::EndpointInfo;
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct App {
pub id: String,
pub name: String,
pub description: String,
pub version: String,
pub author: String,
#[serde(rename="iconUrl")]
pub icon_url: String,
}
impl App {
/// Creates `App` instance from `EndpointInfo` and `id`.
pub fn from_info(id: &str, info: &EndpointInfo) -> Self {
App {
id: id.to_owned(),
name: info.name.to_owned(),
description: info.description.to_owned(),
version: info.version.to_owned(),
author: info.author.to_owned(),
icon_url: info.icon_url.to_owned(),
}
}
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct ApiError {
pub code: String,
pub title: String,
pub detail: String,
}

View File

@@ -1,116 +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 serde_json;
use std::io;
use std::io::Read;
use std::fs;
use std::path::PathBuf;
use page::LocalPageEndpoint;
use endpoint::{Endpoints, EndpointInfo};
use api::App;
struct LocalDapp {
id: String,
path: PathBuf,
info: EndpointInfo,
}
fn local_dapps(dapps_path: String) -> Vec<LocalDapp> {
let files = fs::read_dir(dapps_path.as_str());
if let Err(e) = files {
warn!(target: "dapps", "Unable to load local dapps from: {}. Reason: {:?}", dapps_path, e);
return vec![];
}
let files = files.expect("Check is done earlier");
files.map(|dir| {
let entry = try!(dir);
let file_type = try!(entry.file_type());
// skip files
if file_type.is_file() {
return Err(io::Error::new(io::ErrorKind::NotFound, "Not a file"));
}
// take directory name and path
entry.file_name().into_string()
.map(|name| (name, entry.path()))
.map_err(|e| {
info!(target: "dapps", "Unable to load dapp: {:?}. Reason: {:?}", entry.path(), e);
io::Error::new(io::ErrorKind::NotFound, "Invalid name")
})
})
.filter_map(|m| {
if let Err(ref e) = m {
debug!(target: "dapps", "Ignoring local dapp: {:?}", e);
}
m.ok()
})
.map(|(name, path)| {
// try to get manifest file
let info = read_manifest(&name, path.clone());
LocalDapp {
id: name,
path: path,
info: info,
}
})
.collect()
}
fn read_manifest(name: &str, mut path: PathBuf) -> EndpointInfo {
path.push("manifest.json");
fs::File::open(path.clone())
.map_err(|e| format!("{:?}", e))
.and_then(|mut f| {
// Reat file
let mut s = String::new();
try!(f.read_to_string(&mut s).map_err(|e| format!("{:?}", e)));
// Try to deserialize manifest
serde_json::from_str::<App>(&s).map_err(|e| format!("{:?}", e))
})
.map(|app| EndpointInfo {
name: app.name,
description: app.description,
version: app.version,
author: app.author,
icon_url: app.icon_url,
})
.unwrap_or_else(|e| {
warn!(target: "dapps", "Cannot read manifest file at: {:?}. Error: {:?}", path, e);
EndpointInfo {
name: name.into(),
description: name.into(),
version: "0.0.0".into(),
author: "?".into(),
icon_url: "icon.png".into(),
}
})
}
pub fn local_endpoints(dapps_path: String) -> Endpoints {
let mut pages = Endpoints::new();
for dapp in local_dapps(dapps_path) {
pages.insert(
dapp.id,
Box::new(LocalPageEndpoint::new(dapp.path, dapp.info))
);
}
pages
}

View File

@@ -1,69 +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 endpoint::{Endpoints, Endpoint};
use page::PageEndpoint;
use proxypac::ProxyPac;
use parity_dapps::WebApp;
mod fs;
extern crate parity_dapps_status;
extern crate parity_dapps_home;
pub const DAPPS_DOMAIN : &'static str = ".parity";
pub const RPC_PATH : &'static str = "rpc";
pub const API_PATH : &'static str = "api";
pub const UTILS_PATH : &'static str = "parity-utils";
pub fn main_page() -> &'static str {
"/home/"
}
pub fn utils() -> Box<Endpoint> {
Box::new(PageEndpoint::with_prefix(parity_dapps_home::App::default(), UTILS_PATH.to_owned()))
}
pub fn all_endpoints(dapps_path: String) -> Endpoints {
// fetch fs dapps at first to avoid overwriting builtins
let mut pages = fs::local_endpoints(dapps_path);
// Home page needs to be safe embed
// 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_home::App::default())
));
pages.insert("proxy".into(), ProxyPac::boxed());
insert::<parity_dapps_status::App>(&mut pages, "parity");
insert::<parity_dapps_status::App>(&mut pages, "status");
// Optional dapps
wallet_page(&mut pages);
pages
}
#[cfg(feature = "parity-dapps-wallet")]
fn wallet_page(pages: &mut Endpoints) {
extern crate parity_dapps_wallet;
insert::<parity_dapps_wallet::App>(pages, "wallet");
}
#[cfg(not(feature = "parity-dapps-wallet"))]
fn wallet_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

@@ -1,45 +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/>.
//! URL Endpoint traits
use hyper::{server, net};
use std::collections::BTreeMap;
#[derive(Debug, PartialEq, Default, Clone)]
pub struct EndpointPath {
pub app_id: String,
pub host: String,
pub port: u16,
}
#[derive(Debug, PartialEq, Clone)]
pub struct EndpointInfo {
pub name: String,
pub description: String,
pub version: String,
pub author: String,
pub icon_url: String,
}
pub trait Endpoint : Send + Sync {
fn info(&self) -> Option<&EndpointInfo> { None }
fn to_handler(&self, path: EndpointPath) -> Box<server::Handler<net::HttpStream> + Send>;
}
pub type Endpoints = BTreeMap<String, Box<Endpoint>>;
pub type Handler = server::Handler<net::HttpStream> + Send;

View File

@@ -1,44 +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/>.
//! Authorization Handlers
use hyper::{server, Decoder, Encoder, Next};
use hyper::net::HttpStream;
use hyper::status::StatusCode;
pub struct AuthRequiredHandler;
impl server::Handler<HttpStream> for AuthRequiredHandler {
fn on_request(&mut self, _request: server::Request<HttpStream>) -> Next {
Next::write()
}
fn on_request_readable(&mut self, _decoder: &mut Decoder<HttpStream>) -> Next {
Next::write()
}
fn on_response(&mut self, res: &mut server::Response) -> Next {
res.set_status(StatusCode::Unauthorized);
res.headers_mut().set_raw("WWW-Authenticate", vec![b"Basic realm=\"Parity\"".to_vec()]);
Next::write()
}
fn on_response_writable(&mut self, _encoder: &mut Encoder<HttpStream>) -> Next {
Next::end()
}
}

View File

@@ -1,101 +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/>.
//! Simple Content Handler
use std::io::Write;
use hyper::{header, server, Decoder, Encoder, Next};
use hyper::net::HttpStream;
use hyper::status::StatusCode;
pub struct ContentHandler {
code: StatusCode,
content: String,
mimetype: String,
write_pos: usize,
}
impl ContentHandler {
pub fn ok(content: String, mimetype: String) -> Self {
ContentHandler {
code: StatusCode::Ok,
content: content,
mimetype: mimetype,
write_pos: 0
}
}
pub fn forbidden(content: String, mimetype: String) -> Self {
ContentHandler {
code: StatusCode::Forbidden,
content: content,
mimetype: mimetype,
write_pos: 0
}
}
pub fn not_found(content: String, mimetype: String) -> Self {
ContentHandler {
code: StatusCode::NotFound,
content: content,
mimetype: mimetype,
write_pos: 0
}
}
pub fn new(code: StatusCode, content: String, mimetype: String) -> Self {
ContentHandler {
code: code,
content: content,
mimetype: mimetype,
write_pos: 0,
}
}
}
impl server::Handler<HttpStream> for ContentHandler {
fn on_request(&mut self, _request: server::Request<HttpStream>) -> Next {
Next::write()
}
fn on_request_readable(&mut self, _decoder: &mut Decoder<HttpStream>) -> Next {
Next::write()
}
fn on_response(&mut self, res: &mut server::Response) -> Next {
res.set_status(self.code);
res.headers_mut().set(header::ContentType(self.mimetype.parse().unwrap()));
Next::write()
}
fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next {
let bytes = self.content.as_bytes();
if self.write_pos == bytes.len() {
return Next::end();
}
match encoder.write(&bytes[self.write_pos..]) {
Ok(bytes) => {
self.write_pos += bytes;
Next::write()
},
Err(e) => match e.kind() {
::std::io::ErrorKind::WouldBlock => Next::write(),
_ => Next::end()
},
}
}
}

View File

@@ -1,148 +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/>.
//! Echo Handler
use std::io::Read;
use hyper::{header, server, Decoder, Encoder, Next};
use hyper::method::Method;
use hyper::net::HttpStream;
use unicase::UniCase;
use super::ContentHandler;
#[derive(Debug, PartialEq)]
/// Type of Cross-Origin request
enum Cors {
/// Not a Cross-Origin request - no headers needed
No,
/// Cross-Origin request with valid Origin
Allowed(String),
/// Cross-Origin request with invalid Origin
Forbidden,
}
pub struct EchoHandler {
safe_origins: Vec<String>,
content: String,
cors: Cors,
handler: Option<ContentHandler>,
}
impl EchoHandler {
pub fn cors(safe_origins: Vec<String>) -> Self {
EchoHandler {
safe_origins: safe_origins,
content: String::new(),
cors: Cors::Forbidden,
handler: None,
}
}
fn cors_header(&self, origin: Option<String>) -> Cors {
fn origin_is_allowed(origin: &str, safe_origins: &[String]) -> bool {
for safe in safe_origins {
if origin.starts_with(safe) {
return true;
}
}
false
}
match origin {
Some(ref origin) if origin_is_allowed(origin, &self.safe_origins) => {
Cors::Allowed(origin.clone())
},
None => Cors::No,
_ => Cors::Forbidden,
}
}
}
impl server::Handler<HttpStream> for EchoHandler {
fn on_request(&mut self, request: server::Request<HttpStream>) -> Next {
let origin = request.headers().get_raw("origin")
.and_then(|list| list.get(0))
.and_then(|origin| String::from_utf8(origin.clone()).ok());
self.cors = self.cors_header(origin);
// Don't even read the payload if origin is forbidden!
if let Cors::Forbidden = self.cors {
self.handler = Some(ContentHandler::ok(String::new(), "text/plain".into()));
Next::write()
} else {
Next::read()
}
}
fn on_request_readable(&mut self, decoder: &mut Decoder<HttpStream>) -> Next {
match decoder.read_to_string(&mut self.content) {
Ok(0) => {
self.handler = Some(ContentHandler::ok(self.content.clone(), "application/json".into()));
Next::write()
},
Ok(_) => Next::read(),
Err(e) => match e.kind() {
::std::io::ErrorKind::WouldBlock => Next::read(),
_ => Next::end(),
}
}
}
fn on_response(&mut self, res: &mut server::Response) -> Next {
if let Cors::Allowed(ref domain) = self.cors {
let mut headers = res.headers_mut();
headers.set(header::Allow(vec![Method::Options, Method::Post, Method::Get]));
headers.set(header::AccessControlAllowHeaders(vec![
UniCase("origin".to_owned()),
UniCase("content-type".to_owned()),
UniCase("accept".to_owned()),
]));
headers.set(header::AccessControlAllowOrigin::Value(domain.clone()));
}
self.handler.as_mut().unwrap().on_response(res)
}
fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next {
self.handler.as_mut().unwrap().on_response_writable(encoder)
}
}
#[test]
fn should_return_correct_cors_value() {
// given
let safe_origins = vec!["chrome-extension://".to_owned(), "http://localhost:8080".to_owned()];
let cut = EchoHandler {
safe_origins: safe_origins,
content: String::new(),
cors: Cors::No,
handler: None,
};
// when
let res1 = cut.cors_header(Some("http://ethcore.io".into()));
let res2 = cut.cors_header(Some("http://localhost:8080".into()));
let res3 = cut.cors_header(Some("chrome-extension://deadbeefcafe".into()));
let res4 = cut.cors_header(None);
// then
assert_eq!(res1, Cors::Forbidden);
assert_eq!(res2, Cors::Allowed("http://localhost:8080".into()));
assert_eq!(res3, Cors::Allowed("chrome-extension://deadbeefcafe".into()));
assert_eq!(res4, Cors::No);
}

View File

@@ -1,57 +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/>.
//! Hyper handlers implementations.
mod auth;
mod echo;
mod content;
mod redirect;
pub use self::auth::AuthRequiredHandler;
pub use self::echo::EchoHandler;
pub use self::content::ContentHandler;
pub use self::redirect::Redirection;
use url::Url;
use hyper::{server, header, net, uri};
pub fn extract_url(req: &server::Request<net::HttpStream>) -> Option<Url> {
match *req.uri() {
uri::RequestUri::AbsoluteUri(ref url) => {
match Url::from_generic_url(url.clone()) {
Ok(url) => Some(url),
_ => None,
}
},
uri::RequestUri::AbsolutePath(ref path) => {
// Attempt to prepend the Host header (mandatory in HTTP/1.1)
let url_string = match req.headers().get::<header::Host>() {
Some(ref host) => {
format!("http://{}:{}{}", host.hostname, host.port.unwrap_or(80), path)
},
None => return None,
};
match Url::parse(&url_string) {
Ok(url) => Some(url),
_ => None,
}
},
_ => None,
}
}

View File

@@ -1,55 +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/>.
//! HTTP Redirection hyper handler
use hyper::{header, server, Decoder, Encoder, Next};
use hyper::net::HttpStream;
use hyper::status::StatusCode;
pub struct Redirection {
to_url: &'static str
}
impl Redirection {
pub fn new(url: &'static str) -> Box<Self> {
Box::new(Redirection {
to_url: url
})
}
}
impl server::Handler<HttpStream> for Redirection {
fn on_request(&mut self, _request: server::Request<HttpStream>) -> Next {
Next::write()
}
fn on_request_readable(&mut self, _decoder: &mut Decoder<HttpStream>) -> Next {
Next::write()
}
fn on_response(&mut self, res: &mut server::Response) -> Next {
res.set_status(StatusCode::MovedPermanently);
res.headers_mut().set(header::Location(self.to_url.to_owned()));
Next::write()
}
fn on_response_writable(&mut self, _encoder: &mut Encoder<HttpStream>) -> Next {
Next::end()
}
}

View File

@@ -1,238 +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/>.
//! Ethcore Webapplications for Parity
//! ```
//! extern crate jsonrpc_core;
//! extern crate ethcore_dapps;
//!
//! use std::sync::Arc;
//! use jsonrpc_core::IoHandler;
//! use ethcore_dapps::*;
//!
//! struct SayHello;
//! impl MethodCommand for SayHello {
//! fn execute(&self, _params: Params) -> Result<Value, Error> {
//! Ok(Value::String("hello".to_string()))
//! }
//! }
//!
//! fn main() {
//! let io = IoHandler::new();
//! io.add_method("say_hello", SayHello);
//! let _server = Server::start_unsecure_http(
//! &"127.0.0.1:3030".parse().unwrap(),
//! Arc::new(io)
//! );
//! }
//! ```
//!
#![warn(missing_docs)]
#![cfg_attr(feature="nightly", plugin(clippy))]
#[macro_use]
extern crate log;
extern crate url as url_lib;
extern crate hyper;
extern crate unicase;
extern crate serde;
extern crate serde_json;
extern crate jsonrpc_core;
extern crate jsonrpc_http_server;
extern crate parity_dapps;
extern crate ethcore_rpc;
extern crate ethcore_util;
extern crate mime_guess;
mod endpoint;
mod apps;
mod page;
mod router;
mod handlers;
mod rpc;
mod api;
mod proxypac;
mod url;
use std::sync::{Arc, Mutex};
use std::net::SocketAddr;
use std::collections::HashMap;
use jsonrpc_core::{IoHandler, IoDelegate};
use router::auth::{Authorization, NoAuth, HttpBasicAuth};
use ethcore_rpc::Extendable;
static DAPPS_DOMAIN : &'static str = ".parity";
/// Webapps HTTP+RPC server build.
pub struct ServerBuilder {
dapps_path: String,
handler: Arc<IoHandler>,
}
impl Extendable for ServerBuilder {
fn add_delegate<D: Send + Sync + 'static>(&self, delegate: IoDelegate<D>) {
self.handler.add_delegate(delegate);
}
}
impl ServerBuilder {
/// Construct new dapps server
pub fn new(dapps_path: String) -> Self {
ServerBuilder {
dapps_path: dapps_path,
handler: Arc::new(IoHandler::new())
}
}
/// Asynchronously start server with no authentication,
/// returns result with `Server` handle on success or an error.
pub fn start_unsecured_http(&self, addr: &SocketAddr, hosts: Option<Vec<String>>) -> Result<Server, ServerError> {
Server::start_http(
addr,
hosts,
NoAuth,
self.handler.clone(),
self.dapps_path.clone(),
)
}
/// Asynchronously start server with `HTTP Basic Authentication`,
/// return result with `Server` handle on success or an error.
pub fn start_basic_auth_http(&self, addr: &SocketAddr, hosts: Option<Vec<String>>, username: &str, password: &str) -> Result<Server, ServerError> {
Server::start_http(
addr,
hosts,
HttpBasicAuth::single_user(username, password),
self.handler.clone(),
self.dapps_path.clone(),
)
}
}
/// Webapps HTTP server.
pub struct Server {
server: Option<hyper::server::Listening>,
panic_handler: Arc<Mutex<Option<Box<Fn() -> () + Send>>>>,
}
impl Server {
/// Returns a list of allowed hosts or `None` if all hosts are allowed.
fn allowed_hosts(hosts: Option<Vec<String>>, bind_address: String) -> Option<Vec<String>> {
let mut allowed = Vec::new();
match hosts {
Some(hosts) => allowed.extend_from_slice(&hosts),
None => return None,
}
// Add localhost domain as valid too if listening on loopback interface.
allowed.push(bind_address.replace("127.0.0.1", "localhost").into());
allowed.push(bind_address.into());
Some(allowed)
}
fn start_http<A: Authorization + 'static>(
addr: &SocketAddr,
hosts: Option<Vec<String>>,
authorization: A,
handler: Arc<IoHandler>,
dapps_path: String,
) -> Result<Server, ServerError> {
let panic_handler = Arc::new(Mutex::new(None));
let authorization = Arc::new(authorization);
let endpoints = Arc::new(apps::all_endpoints(dapps_path));
let special = Arc::new({
let mut special = HashMap::new();
special.insert(router::SpecialEndpoint::Rpc, rpc::rpc(handler, panic_handler.clone()));
special.insert(router::SpecialEndpoint::Api, api::RestApi::new(format!("{}", addr), endpoints.clone()));
special.insert(router::SpecialEndpoint::Utils, apps::utils());
special
});
let hosts = Self::allowed_hosts(hosts, format!("{}", addr));
try!(hyper::Server::http(addr))
.handle(move |_| router::Router::new(
apps::main_page(),
endpoints.clone(),
special.clone(),
authorization.clone(),
hosts.clone(),
))
.map(|(l, srv)| {
::std::thread::spawn(move || {
srv.run();
});
Server {
server: Some(l),
panic_handler: panic_handler,
}
})
.map_err(ServerError::from)
}
/// Set callback for panics.
pub fn set_panic_handler<F>(&self, handler: F) where F : Fn() -> () + Send + 'static {
*self.panic_handler.lock().unwrap() = Some(Box::new(handler));
}
}
impl Drop for Server {
fn drop(&mut self) {
self.server.take().unwrap().close()
}
}
/// Webapp Server startup error
#[derive(Debug)]
pub enum ServerError {
/// Wrapped `std::io::Error`
IoError(std::io::Error),
/// Other `hyper` error
Other(hyper::error::Error),
}
impl From<hyper::error::Error> for ServerError {
fn from(err: hyper::error::Error) -> Self {
match err {
hyper::error::Error::Io(e) => ServerError::IoError(e),
e => ServerError::Other(e),
}
}
}
#[cfg(test)]
mod tests {
use super::Server;
#[test]
fn should_return_allowed_hosts() {
// given
let bind_address = "127.0.0.1".to_owned();
// when
let all = Server::allowed_hosts(None, bind_address.clone());
let address = Server::allowed_hosts(Some(Vec::new()), bind_address.clone());
let some = Server::allowed_hosts(Some(vec!["ethcore.io".into()]), bind_address.clone());
// then
assert_eq!(all, None);
assert_eq!(address, Some(vec!["localhost".into(), "127.0.0.1".into()]));
assert_eq!(some, Some(vec!["ethcore.io".into(), "localhost".into(), "127.0.0.1".into()]));
}
}

View File

@@ -1,154 +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 page::handler;
use std::sync::Arc;
use endpoint::{Endpoint, EndpointInfo, EndpointPath, Handler};
use parity_dapps::{WebApp, File, Info};
pub struct PageEndpoint<T : WebApp + 'static> {
/// Content of the files
pub app: Arc<T>,
/// Prefix to strip from the path (when `None` deducted from `app_id`)
pub prefix: Option<String>,
/// Safe to be loaded in frame by other origin. (use wisely!)
safe_to_embed: bool,
info: EndpointInfo,
}
impl<T: WebApp + 'static> PageEndpoint<T> {
/// Creates new `PageEndpoint` for builtin (compile time) Dapp.
pub fn new(app: T) -> Self {
let info = app.info();
PageEndpoint {
app: Arc::new(app),
prefix: None,
safe_to_embed: false,
info: EndpointInfo::from(info),
}
}
/// Create new `PageEndpoint` and specify prefix that should be removed before looking for a file.
/// It's used only for special endpoints (i.e. `/parity-utils/`)
/// So `/parity-utils/inject.js` will be resolved to `/inject.js` is prefix is set.
pub fn with_prefix(app: T, prefix: String) -> Self {
let info = app.info();
PageEndpoint {
app: Arc::new(app),
prefix: Some(prefix),
safe_to_embed: false,
info: EndpointInfo::from(info),
}
}
/// Creates new `PageEndpoint` which can be safely used in iframe
/// even from different origin. It might be dangerous (clickjacking).
/// Use wisely!
pub fn new_safe_to_embed(app: T) -> Self {
let info = app.info();
PageEndpoint {
app: Arc::new(app),
prefix: None,
safe_to_embed: true,
info: EndpointInfo::from(info),
}
}
}
impl<T: WebApp> Endpoint for PageEndpoint<T> {
fn info(&self) -> Option<&EndpointInfo> {
Some(&self.info)
}
fn to_handler(&self, path: EndpointPath) -> Box<Handler> {
Box::new(handler::PageHandler {
app: BuiltinDapp::new(self.app.clone()),
prefix: self.prefix.clone(),
path: path,
file: None,
safe_to_embed: self.safe_to_embed,
})
}
}
impl From<Info> for EndpointInfo {
fn from(info: Info) -> Self {
EndpointInfo {
name: info.name.into(),
description: info.description.into(),
author: info.author.into(),
icon_url: info.icon_url.into(),
version: info.version.into(),
}
}
}
struct BuiltinDapp<T: WebApp + 'static> {
app: Arc<T>,
}
impl<T: WebApp + 'static> BuiltinDapp<T> {
fn new(app: Arc<T>) -> Self {
BuiltinDapp {
app: app,
}
}
}
impl<T: WebApp + 'static> handler::Dapp for BuiltinDapp<T> {
type DappFile = BuiltinDappFile<T>;
fn file(&self, path: &str) -> Option<Self::DappFile> {
self.app.file(path).map(|_| {
BuiltinDappFile {
app: self.app.clone(),
path: path.into(),
write_pos: 0,
}
})
}
}
struct BuiltinDappFile<T: WebApp + 'static> {
app: Arc<T>,
path: String,
write_pos: usize,
}
impl<T: WebApp + 'static> BuiltinDappFile<T> {
fn file(&self) -> &File {
self.app.file(&self.path).expect("Check is done when structure is created.")
}
}
impl<T: WebApp + 'static> handler::DappFile for BuiltinDappFile<T> {
fn content_type(&self) -> &str {
self.file().content_type
}
fn is_drained(&self) -> bool {
self.write_pos == self.file().content.len()
}
fn next_chunk(&mut self) -> &[u8] {
&self.file().content[self.write_pos..]
}
fn bytes_written(&mut self, bytes: usize) {
self.write_pos += bytes;
}
}

View File

@@ -1,207 +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 std::io::Write;
use hyper::header;
use hyper::server;
use hyper::uri::RequestUri;
use hyper::net::HttpStream;
use hyper::status::StatusCode;
use hyper::{Decoder, Encoder, Next};
use endpoint::EndpointPath;
/// Represents a file that can be sent to client.
/// Implementation should keep track of bytes already sent internally.
pub trait DappFile: Send {
/// Returns a content-type of this file.
fn content_type(&self) -> &str;
/// Checks if all bytes from that file were written.
fn is_drained(&self) -> bool;
/// Fetch next chunk to write to the client.
fn next_chunk(&mut self) -> &[u8];
/// How many files have been written to the client.
fn bytes_written(&mut self, bytes: usize);
}
/// Dapp as a (dynamic) set of files.
pub trait Dapp: Send + 'static {
/// File type
type DappFile: DappFile;
/// Returns file under given path.
fn file(&self, path: &str) -> Option<Self::DappFile>;
}
/// A handler for a single webapp.
/// Resolves correct paths and serves as a plumbing code between
/// hyper server and dapp.
pub struct PageHandler<T: Dapp> {
/// A Dapp.
pub app: T,
/// File currently being served (or `None` if file does not exist).
pub file: Option<T::DappFile>,
/// Optional prefix to strip from path.
pub prefix: Option<String>,
/// Requested path.
pub path: EndpointPath,
/// Flag indicating if the file can be safely embeded (put in iframe).
pub safe_to_embed: bool,
}
impl<T: Dapp> PageHandler<T> {
fn extract_path(&self, path: &str) -> String {
let app_id = &self.path.app_id;
let prefix = "/".to_owned() + self.prefix.as_ref().unwrap_or(app_id);
let prefix_with_slash = prefix.clone() + "/";
let query_pos = path.find('?').unwrap_or_else(|| path.len());
// Index file support
match path == "/" || path == &prefix || path == &prefix_with_slash {
true => "index.html".to_owned(),
false => if path.starts_with(&prefix_with_slash) {
path[prefix_with_slash.len()..query_pos].to_owned()
} else if path.starts_with("/") {
path[1..query_pos].to_owned()
} else {
path[0..query_pos].to_owned()
}
}
}
}
impl<T: Dapp> server::Handler<HttpStream> for PageHandler<T> {
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))
},
RequestUri::AbsoluteUri(ref url) => {
self.app.file(&self.extract_path(url.path()))
},
_ => None,
};
Next::write()
}
fn on_request_readable(&mut self, _decoder: &mut Decoder<HttpStream>) -> Next {
Next::write()
}
fn on_response(&mut self, res: &mut server::Response) -> Next {
if let Some(ref f) = self.file {
res.set_status(StatusCode::Ok);
res.headers_mut().set(header::ContentType(f.content_type().parse().unwrap()));
if !self.safe_to_embed {
res.headers_mut().set_raw("X-Frame-Options", vec![b"SAMEORIGIN".to_vec()]);
}
Next::write()
} else {
res.set_status(StatusCode::NotFound);
Next::write()
}
}
fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next {
match self.file {
None => Next::end(),
Some(ref f) if f.is_drained() => Next::end(),
Some(ref mut f) => match encoder.write(f.next_chunk()) {
Ok(bytes) => {
f.bytes_written(bytes);
Next::write()
},
Err(e) => match e.kind() {
::std::io::ErrorKind::WouldBlock => Next::write(),
_ => Next::end(),
},
}
}
}
}
#[cfg(test)]
mod test {
use super::*;
pub struct TestWebAppFile;
impl DappFile for TestWebAppFile {
fn content_type(&self) -> &str {
unimplemented!()
}
fn is_drained(&self) -> bool {
unimplemented!()
}
fn next_chunk(&mut self) -> &[u8] {
unimplemented!()
}
fn bytes_written(&mut self, _bytes: usize) {
unimplemented!()
}
}
#[derive(Default)]
pub struct TestWebapp;
impl Dapp for TestWebapp {
type DappFile = TestWebAppFile;
fn file(&self, _path: &str) -> Option<Self::DappFile> {
None
}
}
}
#[test]
fn should_extract_path_with_appid() {
// given
let path1 = "/";
let path2= "/test.css";
let path3 = "/app/myfile.txt";
let path4 = "/app/myfile.txt?query=123";
let page_handler = PageHandler {
app: test::TestWebapp,
prefix: None,
path: EndpointPath {
app_id: "app".to_owned(),
host: "".to_owned(),
port: 8080
},
file: None,
safe_to_embed: true,
};
// when
let res1 = page_handler.extract_path(path1);
let res2 = page_handler.extract_path(path2);
let res3 = page_handler.extract_path(path3);
let res4 = page_handler.extract_path(path4);
// then
assert_eq!(&res1, "index.html");
assert_eq!(&res2, "test.css");
assert_eq!(&res3, "myfile.txt");
assert_eq!(&res4, "myfile.txt");
}

View File

@@ -1,118 +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 mime_guess;
use std::io::{Seek, Read, SeekFrom};
use std::fs;
use std::path::PathBuf;
use page::handler;
use endpoint::{Endpoint, EndpointInfo, EndpointPath, Handler};
pub struct LocalPageEndpoint {
path: PathBuf,
info: EndpointInfo,
}
impl LocalPageEndpoint {
pub fn new(path: PathBuf, info: EndpointInfo) -> Self {
LocalPageEndpoint {
path: path,
info: info,
}
}
}
impl Endpoint for LocalPageEndpoint {
fn info(&self) -> Option<&EndpointInfo> {
Some(&self.info)
}
fn to_handler(&self, path: EndpointPath) -> Box<Handler> {
Box::new(handler::PageHandler {
app: LocalDapp::new(self.path.clone()),
prefix: None,
path: path,
file: None,
safe_to_embed: false,
})
}
}
struct LocalDapp {
path: PathBuf,
}
impl LocalDapp {
fn new(path: PathBuf) -> Self {
LocalDapp {
path: path
}
}
}
impl handler::Dapp for LocalDapp {
type DappFile = LocalFile;
fn file(&self, file_path: &str) -> Option<Self::DappFile> {
let mut path = self.path.clone();
for part in file_path.split('/') {
path.push(part);
}
// Check if file exists
fs::File::open(path.clone()).ok().map(|file| {
let content_type = mime_guess::guess_mime_type(path);
let len = file.metadata().ok().map_or(0, |meta| meta.len());
LocalFile {
content_type: content_type.to_string(),
buffer: [0; 4096],
file: file,
pos: 0,
len: len,
}
})
}
}
struct LocalFile {
content_type: String,
buffer: [u8; 4096],
file: fs::File,
len: u64,
pos: u64,
}
impl handler::DappFile for LocalFile {
fn content_type(&self) -> &str {
&self.content_type
}
fn is_drained(&self) -> bool {
self.pos == self.len
}
fn next_chunk(&mut self) -> &[u8] {
let _ = self.file.seek(SeekFrom::Start(self.pos));
if let Ok(n) = self.file.read(&mut self.buffer) {
&self.buffer[0..n]
} else {
&self.buffer[0..0]
}
}
fn bytes_written(&mut self, bytes: usize) {
self.pos += bytes as u64;
}
}

View File

@@ -1,24 +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/>.
mod builtin;
mod local;
mod handler;
pub use self::local::LocalPageEndpoint;
pub use self::builtin::PageEndpoint;

View File

@@ -1,49 +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/>.
//! Serving ProxyPac file
use endpoint::{Endpoint, Handler, EndpointPath};
use handlers::ContentHandler;
use apps::DAPPS_DOMAIN;
pub struct ProxyPac;
impl ProxyPac {
pub fn boxed() -> Box<Endpoint> {
Box::new(ProxyPac)
}
}
impl Endpoint for ProxyPac {
fn to_handler(&self, path: EndpointPath) -> Box<Handler> {
let content = format!(
r#"
function FindProxyForURL(url, host) {{
if (shExpMatch(host, "*{0}"))
{{
return "PROXY {1}:{2}";
}}
return "DIRECT";
}}
"#,
DAPPS_DOMAIN, path.host, path.port);
Box::new(ContentHandler::ok(content, "application/javascript".to_owned()))
}
}

View File

@@ -1,104 +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/>.
//! HTTP Authorization implementations
use std::collections::HashMap;
use hyper::{server, net, header, status};
use endpoint::Handler;
use handlers::{AuthRequiredHandler, ContentHandler};
/// Authorization result
pub enum Authorized {
/// Authorization was successful.
Yes,
/// Unsuccessful authorization. Handler for further work is returned.
No(Box<Handler>),
}
/// Authorization interface
pub trait Authorization : Send + Sync {
/// Checks if authorization is valid.
fn is_authorized(&self, req: &server::Request<net::HttpStream>)-> Authorized;
}
/// HTTP Basic Authorization handler
pub struct HttpBasicAuth {
users: HashMap<String, String>,
}
/// No-authorization implementation (authorization disabled)
pub struct NoAuth;
impl Authorization for NoAuth {
fn is_authorized(&self, _req: &server::Request<net::HttpStream>)-> Authorized {
Authorized::Yes
}
}
impl Authorization for HttpBasicAuth {
fn is_authorized(&self, req: &server::Request<net::HttpStream>) -> Authorized {
let auth = self.check_auth(&req);
match auth {
Access::Denied => {
Authorized::No(Box::new(ContentHandler::new(
status::StatusCode::Unauthorized,
"<h1>Unauthorized</h1>".into(),
"text/html".into(),
)))
},
Access::AuthRequired => {
Authorized::No(Box::new(AuthRequiredHandler))
},
Access::Granted => {
Authorized::Yes
},
}
}
}
#[derive(Debug)]
enum Access {
Granted,
Denied,
AuthRequired,
}
impl HttpBasicAuth {
/// Creates `HttpBasicAuth` instance with only one user.
pub fn single_user(username: &str, password: &str) -> Self {
let mut users = HashMap::new();
users.insert(username.to_owned(), password.to_owned());
HttpBasicAuth {
users: users
}
}
fn is_authorized(&self, username: &str, password: &str) -> bool {
self.users.get(&username.to_owned()).map_or(false, |pass| pass == password)
}
fn check_auth(&self, req: &server::Request<net::HttpStream>) -> Access {
match req.headers().get::<header::Authorization<header::Basic>>() {
Some(&header::Authorization(
header::Basic { ref username, password: Some(ref password) }
)) if self.is_authorized(username, password) => Access::Granted,
Some(_) => Access::Denied,
None => Access::AuthRequired,
}
}
}

View File

@@ -1,42 +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 DAPPS_DOMAIN;
use hyper::server;
use hyper::net::HttpStream;
use jsonrpc_http_server::{is_host_header_valid};
use handlers::ContentHandler;
pub fn is_valid(request: &server::Request<HttpStream>, allowed_hosts: &[String], endpoints: Vec<String>) -> bool {
let mut endpoints = endpoints.iter()
.map(|endpoint| format!("{}{}", endpoint, DAPPS_DOMAIN))
.collect::<Vec<String>>();
endpoints.extend_from_slice(allowed_hosts);
is_host_header_valid(request, &endpoints)
}
pub fn host_invalid_response() -> Box<server::Handler<HttpStream> + Send> {
Box::new(ContentHandler::forbidden(
r#"
<h1>Request with disallowed <code>Host</code> header has been blocked.</h1>
<p>Check the URL in your browser address bar.</p>
"#.into(),
"text/html".into()
))
}

View File

@@ -1,236 +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/>.
//! Router implementation
//! Processes request handling authorization and dispatching it to proper application.
pub mod auth;
mod host_validation;
use DAPPS_DOMAIN;
use std::sync::Arc;
use std::collections::HashMap;
use url::{Url, Host};
use hyper::{self, server, Next, Encoder, Decoder};
use hyper::net::HttpStream;
use apps;
use endpoint::{Endpoint, Endpoints, EndpointPath};
use handlers::{Redirection, extract_url};
use self::auth::{Authorization, Authorized};
/// Special endpoints are accessible on every domain (every dapp)
#[derive(Debug, PartialEq, Hash, Eq)]
pub enum SpecialEndpoint {
Rpc,
Api,
Utils,
None,
}
pub struct Router<A: Authorization + 'static> {
main_page: &'static str,
endpoints: Arc<Endpoints>,
special: Arc<HashMap<SpecialEndpoint, Box<Endpoint>>>,
authorization: Arc<A>,
allowed_hosts: Option<Vec<String>>,
handler: Box<server::Handler<HttpStream> + Send>,
}
impl<A: Authorization + 'static> server::Handler<HttpStream> for Router<A> {
fn on_request(&mut self, req: server::Request<HttpStream>) -> Next {
// Validate Host header
if let Some(ref hosts) = self.allowed_hosts {
if !host_validation::is_valid(&req, hosts, self.endpoints.keys().cloned().collect()) {
self.handler = host_validation::host_invalid_response();
return self.handler.on_request(req);
}
}
// Check authorization
let auth = self.authorization.is_authorized(&req);
if let Authorized::No(handler) = auth {
self.handler = handler;
return self.handler.on_request(req);
}
// Choose proper handler depending on path / domain
let url = extract_url(&req);
let endpoint = extract_endpoint(&url);
self.handler = match endpoint {
// First check special endpoints
(ref path, ref endpoint) if self.special.contains_key(endpoint) => {
self.special.get(endpoint).unwrap().to_handler(path.clone().unwrap_or_default())
},
// Then delegate to dapp
(Some(ref path), _) if self.endpoints.contains_key(&path.app_id) => {
self.endpoints.get(&path.app_id).unwrap().to_handler(path.clone())
},
// Redirection to main page
_ if *req.method() == hyper::method::Method::Get => {
Redirection::new(self.main_page)
},
// RPC by default
_ => {
self.special.get(&SpecialEndpoint::Rpc).unwrap().to_handler(EndpointPath::default())
}
};
// Delegate on_request to proper handler
self.handler.on_request(req)
}
/// This event occurs each time the `Request` is ready to be read from.
fn on_request_readable(&mut self, decoder: &mut Decoder<HttpStream>) -> Next {
self.handler.on_request_readable(decoder)
}
/// This event occurs after the first time this handled signals `Next::write()`.
fn on_response(&mut self, response: &mut server::Response) -> Next {
self.handler.on_response(response)
}
/// This event occurs each time the `Response` is ready to be written to.
fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next {
self.handler.on_response_writable(encoder)
}
}
impl<A: Authorization> Router<A> {
pub fn new(
main_page: &'static str,
endpoints: Arc<Endpoints>,
special: Arc<HashMap<SpecialEndpoint, Box<Endpoint>>>,
authorization: Arc<A>,
allowed_hosts: Option<Vec<String>>,
) -> Self {
let handler = special.get(&SpecialEndpoint::Rpc).unwrap().to_handler(EndpointPath::default());
Router {
main_page: main_page,
endpoints: endpoints,
special: special,
authorization: authorization,
allowed_hosts: allowed_hosts,
handler: handler,
}
}
}
fn extract_endpoint(url: &Option<Url>) -> (Option<EndpointPath>, SpecialEndpoint) {
fn special_endpoint(url: &Url) -> SpecialEndpoint {
if url.path.len() <= 1 {
return SpecialEndpoint::None;
}
match url.path[0].as_ref() {
apps::RPC_PATH => SpecialEndpoint::Rpc,
apps::API_PATH => SpecialEndpoint::Api,
apps::UTILS_PATH => SpecialEndpoint::Utils,
_ => SpecialEndpoint::None,
}
}
match *url {
Some(ref url) => match url.host {
Host::Domain(ref domain) if domain.ends_with(DAPPS_DOMAIN) => {
let len = domain.len() - DAPPS_DOMAIN.len();
let id = domain[0..len].to_owned();
(Some(EndpointPath {
app_id: id,
host: domain.clone(),
port: url.port,
}), special_endpoint(url))
},
_ if url.path.len() > 1 => {
let id = url.path[0].clone();
(Some(EndpointPath {
app_id: id.clone(),
host: format!("{}", url.host),
port: url.port,
}), special_endpoint(url))
},
_ => (None, special_endpoint(url)),
},
_ => (None, SpecialEndpoint::None)
}
}
#[test]
fn should_extract_endpoint() {
assert_eq!(extract_endpoint(&None), (None, SpecialEndpoint::None));
// With path prefix
assert_eq!(
extract_endpoint(&Url::parse("http://localhost:8080/status/index.html").ok()),
(Some(EndpointPath {
app_id: "status".to_owned(),
host: "localhost".to_owned(),
port: 8080,
}), SpecialEndpoint::None)
);
// With path prefix
assert_eq!(
extract_endpoint(&Url::parse("http://localhost:8080/rpc/").ok()),
(Some(EndpointPath {
app_id: "rpc".to_owned(),
host: "localhost".to_owned(),
port: 8080,
}), SpecialEndpoint::Rpc)
);
assert_eq!(
extract_endpoint(&Url::parse("http://my.status.parity/parity-utils/inject.js").ok()),
(Some(EndpointPath {
app_id: "my.status".to_owned(),
host: "my.status.parity".to_owned(),
port: 80,
}), SpecialEndpoint::Utils)
);
// By Subdomain
assert_eq!(
extract_endpoint(&Url::parse("http://my.status.parity/test.html").ok()),
(Some(EndpointPath {
app_id: "my.status".to_owned(),
host: "my.status.parity".to_owned(),
port: 80,
}), SpecialEndpoint::None)
);
// RPC by subdomain
assert_eq!(
extract_endpoint(&Url::parse("http://my.status.parity/rpc/").ok()),
(Some(EndpointPath {
app_id: "my.status".to_owned(),
host: "my.status.parity".to_owned(),
port: 80,
}), SpecialEndpoint::Rpc)
);
// API by subdomain
assert_eq!(
extract_endpoint(&Url::parse("http://my.status.parity/api/").ok()),
(Some(EndpointPath {
app_id: "my.status".to_owned(),
host: "my.status.parity".to_owned(),
port: 80,
}), SpecialEndpoint::Api)
);
}

View File

@@ -1,44 +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 std::sync::{Arc, Mutex};
use jsonrpc_core::IoHandler;
use jsonrpc_http_server::{ServerHandler, PanicHandler, AccessControlAllowOrigin};
use endpoint::{Endpoint, EndpointPath, Handler};
pub fn rpc(handler: Arc<IoHandler>, panic_handler: Arc<Mutex<Option<Box<Fn() -> () + Send>>>>) -> Box<Endpoint> {
Box::new(RpcEndpoint {
handler: handler,
panic_handler: panic_handler,
cors_domain: Some(vec![AccessControlAllowOrigin::Null]),
// NOTE [ToDr] We don't need to do any hosts validation here. It's already done in router.
allowed_hosts: None,
})
}
struct RpcEndpoint {
handler: Arc<IoHandler>,
panic_handler: Arc<Mutex<Option<Box<Fn() -> () + Send>>>>,
cors_domain: Option<Vec<AccessControlAllowOrigin>>,
allowed_hosts: Option<Vec<String>>,
}
impl Endpoint for RpcEndpoint {
fn to_handler(&self, _path: EndpointPath) -> Box<Handler> {
let panic_handler = PanicHandler { handler: self.panic_handler.clone() };
Box::new(ServerHandler::new(self.handler.clone(), self.cors_domain.clone(), self.allowed_hosts.clone(), panic_handler))
}
}

View File

@@ -1,145 +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/>.
//! HTTP/HTTPS URL type. Based on URL type from Iron library.
use url_lib::{self};
pub use url_lib::Host;
/// HTTP/HTTPS URL type for Iron.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Url {
/// Raw url of url
pub raw: url_lib::Url,
/// The host field of the URL, probably a domain.
pub host: Host,
/// The connection port.
pub port: u16,
/// The URL path, the resource to be accessed.
///
/// A *non-empty* vector encoding the parts of the URL path.
/// Empty entries of `""` correspond to trailing slashes.
pub path: Vec<String>,
/// The URL username field, from the userinfo section of the URL.
///
/// `None` if the `@` character was not part of the input OR
/// if a blank username was provided.
/// Otherwise, a non-empty string.
pub username: Option<String>,
/// The URL password field, from the userinfo section of the URL.
///
/// `None` if the `@` character was not part of the input OR
/// if a blank password was provided.
/// Otherwise, a non-empty string.
pub password: Option<String>,
}
impl Url {
/// Create a URL from a string.
///
/// The input must be a valid URL with a special scheme for this to succeed.
///
/// HTTP and HTTPS are special schemes.
///
/// See: http://url.spec.whatwg.org/#special-scheme
pub fn parse(input: &str) -> Result<Url, String> {
// Parse the string using rust-url, then convert.
match url_lib::Url::parse(input) {
Ok(raw_url) => Url::from_generic_url(raw_url),
Err(e) => Err(format!("{}", e))
}
}
/// Create a `Url` from a `rust-url` `Url`.
pub fn from_generic_url(raw_url: url_lib::Url) -> Result<Url, String> {
// Map empty usernames to None.
let username = match raw_url.username() {
"" => None,
username => Some(username.to_owned())
};
// Map empty passwords to None.
let password = match raw_url.password() {
Some(password) if !password.is_empty() => Some(password.to_owned()),
_ => None,
};
let port = try!(raw_url.port_or_known_default().ok_or_else(|| format!("Unknown port for scheme: `{}`", raw_url.scheme())));
let host = try!(raw_url.host().ok_or_else(|| "Valid host, because only data:, mailto: protocols does not have host.".to_owned())).to_owned();
let path = try!(raw_url.path_segments().ok_or_else(|| "Valid path segments. In HTTP we won't get cannot-be-a-base URLs".to_owned()))
.map(|part| part.to_owned()).collect();
Ok(Url {
port: port,
host: host,
path: path,
raw: raw_url,
username: username,
password: password,
})
}
}
#[cfg(test)]
mod test {
use super::Url;
#[test]
fn test_default_port() {
assert_eq!(Url::parse("http://example.com/wow").unwrap().port, 80u16);
assert_eq!(Url::parse("https://example.com/wow").unwrap().port, 443u16);
}
#[test]
fn test_explicit_port() {
assert_eq!(Url::parse("http://localhost:3097").unwrap().port, 3097u16);
}
#[test]
fn test_empty_username() {
assert!(Url::parse("http://@example.com").unwrap().username.is_none());
assert!(Url::parse("http://:password@example.com").unwrap().username.is_none());
}
#[test]
fn test_not_empty_username() {
let user = Url::parse("http://john:pass@example.com").unwrap().username;
assert_eq!(user.unwrap(), "john");
let user = Url::parse("http://john:@example.com").unwrap().username;
assert_eq!(user.unwrap(), "john");
}
#[test]
fn test_empty_password() {
assert!(Url::parse("http://michael@example.com").unwrap().password.is_none());
assert!(Url::parse("http://:@example.com").unwrap().password.is_none());
}
#[test]
fn test_not_empty_password() {
let pass = Url::parse("http://michael:pass@example.com").unwrap().password;
assert_eq!(pass.unwrap(), "pass");
let pass = Url::parse("http://:pass@example.com").unwrap().password;
assert_eq!(pass.unwrap(), "pass");
}
}

View File

@@ -1,26 +0,0 @@
[package]
description = "Ethcore Database"
homepage = "http://ethcore.io"
license = "GPL-3.0"
name = "ethcore-db"
version = "1.3.0"
authors = ["Ethcore <admin@ethcore.io>"]
build = "build.rs"
[build-dependencies]
syntex = "*"
ethcore-ipc-codegen = { path = "../ipc/codegen" }
[dependencies]
clippy = { version = "0.0.80", optional = true}
ethcore-devtools = { path = "../devtools" }
ethcore-ipc = { path = "../ipc/rpc" }
rocksdb = { git = "https://github.com/ethcore/rust-rocksdb" }
semver = "0.2"
ethcore-ipc-nano = { path = "../ipc/nano" }
nanomsg = { git = "https://github.com/ethcore/nanomsg.rs.git" }
crossbeam = "0.2"
ethcore-util = { path = "../util" }
[features]
dev = ["clippy"]

View File

@@ -1,43 +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/>.
extern crate syntex;
extern crate ethcore_ipc_codegen as codegen;
use std::env;
use std::path::Path;
pub fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
// ipc pass
{
let src = Path::new("src/lib.rs.in");
let dst = Path::new(&out_dir).join("lib.intermediate.rs.in");
let mut registry = syntex::Registry::new();
codegen::register(&mut registry);
registry.expand("", &src, &dst).unwrap();
}
// binary serialization pass
{
let src = Path::new(&out_dir).join("lib.intermediate.rs.in");
let dst = Path::new(&out_dir).join("lib.rs");
let mut registry = syntex::Registry::new();
codegen::register(&mut registry);
registry.expand("", &src, &dst).unwrap();
}
}

View File

@@ -1,566 +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/>.
//! Ethcore rocksdb ipc service
use traits::*;
use rocksdb::{DB, Writable, WriteBatch, IteratorMode, DBIterator, IndexType, Options, DBCompactionStyle, BlockBasedOptions, Direction};
use std::sync::{RwLock, Arc};
use std::convert::From;
use ipc::IpcConfig;
use std::mem;
use ipc::binary::BinaryConvertError;
use std::collections::{VecDeque, HashMap, BTreeMap};
enum WriteCacheEntry {
Remove,
Write(Vec<u8>),
}
pub struct WriteCache {
entries: HashMap<Vec<u8>, WriteCacheEntry>,
preferred_len: usize,
}
const FLUSH_BATCH_SIZE: usize = 4096;
impl WriteCache {
fn new(cache_len: usize) -> WriteCache {
WriteCache {
entries: HashMap::new(),
preferred_len: cache_len,
}
}
fn write(&mut self, key: Vec<u8>, val: Vec<u8>) {
self.entries.insert(key, WriteCacheEntry::Write(val));
}
fn remove(&mut self, key: Vec<u8>) {
self.entries.insert(key, WriteCacheEntry::Remove);
}
fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
self.entries.get(key).and_then(
|vec_ref| match vec_ref {
&WriteCacheEntry::Write(ref val) => Some(val.clone()),
&WriteCacheEntry::Remove => None
})
}
/// WriteCache should be locked for this
fn flush(&mut self, db: &DB, amount: usize) -> Result<(), Error> {
let batch = WriteBatch::new();
let mut removed_so_far = 0;
while removed_so_far < amount {
if self.entries.len() == 0 { break; }
let removed_key = {
let (key, cache_entry) = self.entries.iter().nth(0)
.expect("if entries.len == 0, we should have break in the loop, still we got here somehow");
match *cache_entry {
WriteCacheEntry::Write(ref val) => {
try!(batch.put(&key, val));
},
WriteCacheEntry::Remove => {
try!(batch.delete(&key));
},
}
key.clone()
};
self.entries.remove(&removed_key);
removed_so_far = removed_so_far + 1;
}
if removed_so_far > 0 {
try!(db.write(batch));
}
Ok(())
}
/// flushes until cache is empty
fn flush_all(&mut self, db: &DB) -> Result<(), Error> {
while !self.is_empty() { try!(self.flush(db, FLUSH_BATCH_SIZE)); }
Ok(())
}
fn is_empty(&self) -> bool {
self.entries.is_empty()
}
fn try_shrink(&mut self, db: &DB) -> Result<(), Error> {
if self.entries.len() > self.preferred_len {
try!(self.flush(db, FLUSH_BATCH_SIZE));
}
Ok(())
}
}
pub struct Database {
db: RwLock<Option<DB>>,
/// Iterators - dont't use between threads!
iterators: RwLock<BTreeMap<IteratorHandle, DBIterator>>,
write_cache: RwLock<WriteCache>,
}
unsafe impl Send for Database {}
unsafe impl Sync for Database {}
impl Database {
pub fn new() -> Database {
Database {
db: RwLock::new(None),
iterators: RwLock::new(BTreeMap::new()),
write_cache: RwLock::new(WriteCache::new(DEFAULT_CACHE_LEN)),
}
}
pub fn flush(&self) -> Result<(), Error> {
let mut cache_lock = self.write_cache.write();
let db_lock = self.db.read();
if db_lock.is_none() { return Ok(()); }
let db = db_lock.as_ref().unwrap();
try!(cache_lock.try_shrink(&db));
Ok(())
}
pub fn flush_all(&self) -> Result<(), Error> {
let mut cache_lock = self.write_cache.write();
let db_lock = self.db.read();
if db_lock.is_none() { return Ok(()); }
let db = db_lock.as_ref().expect("we should have exited with Ok(()) on the previous step");
try!(cache_lock.flush_all(&db));
Ok(())
}
}
impl Drop for Database {
fn drop(&mut self) {
self.flush().unwrap();
}
}
#[derive(Ipc)]
impl DatabaseService for Database {
fn open(&self, config: DatabaseConfig, path: String) -> Result<(), Error> {
let mut db = self.db.write();
if db.is_some() { return Err(Error::AlreadyOpen); }
let mut opts = Options::new();
opts.set_max_open_files(256);
opts.create_if_missing(true);
opts.set_use_fsync(false);
opts.set_compaction_style(DBCompactionStyle::DBUniversalCompaction);
if let Some(size) = config.prefix_size {
let mut block_opts = BlockBasedOptions::new();
block_opts.set_index_type(IndexType::HashSearch);
opts.set_block_based_table_factory(&block_opts);
opts.set_prefix_extractor_fixed_size(size);
}
*db = Some(try!(DB::open(&opts, &path)));
Ok(())
}
/// Opens database in the specified path with the default config
fn open_default(&self, path: String) -> Result<(), Error> {
self.open(DatabaseConfig::default(), path)
}
fn close(&self) -> Result<(), Error> {
try!(self.flush_all());
let mut db = self.db.write();
if db.is_none() { return Err(Error::IsClosed); }
*db = None;
Ok(())
}
fn put(&self, key: &[u8], value: &[u8]) -> Result<(), Error> {
let mut cache_lock = self.write_cache.write();
cache_lock.write(key.to_vec(), value.to_vec());
Ok(())
}
fn delete(&self, key: &[u8]) -> Result<(), Error> {
let mut cache_lock = self.write_cache.write();
cache_lock.remove(key.to_vec());
Ok(())
}
fn write(&self, transaction: DBTransaction) -> Result<(), Error> {
let mut cache_lock = self.write_cache.write();
let mut writes = transaction.writes.borrow_mut();
for kv in writes.drain(..) {
cache_lock.write(kv.key, kv.value);
}
let mut removes = transaction.removes.borrow_mut();
for k in removes.drain(..) {
cache_lock.remove(k);
}
Ok(())
}
fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Error> {
{
let key_vec = key.to_vec();
let cache_hit = self.write_cache.read().get(&key_vec);
if cache_hit.is_some() {
return Ok(Some(cache_hit.expect("cache_hit.is_some() = true, still there is none somehow here")))
}
}
let db_lock = self.db.read();
let db = try!(db_lock.as_ref().ok_or(Error::IsClosed));
match try!(db.get(key)) {
Some(db_vec) => {
Ok(Some(db_vec.to_vec()))
},
None => Ok(None),
}
}
fn get_by_prefix(&self, prefix: &[u8]) -> Result<Option<Vec<u8>>, Error> {
let db_lock = self.db.read();
let db = try!(db_lock.as_ref().ok_or(Error::IsClosed));
let mut iter = db.iterator(IteratorMode::From(prefix, Direction::Forward));
match iter.next() {
// TODO: use prefix_same_as_start read option (not availabele in C API currently)
Some((k, v)) => if k[0 .. prefix.len()] == prefix[..] { Ok(Some(v.to_vec())) } else { Ok(None) },
_ => Ok(None)
}
}
fn is_empty(&self) -> Result<bool, Error> {
let db_lock = self.db.read();
let db = try!(db_lock.as_ref().ok_or(Error::IsClosed));
Ok(db.iterator(IteratorMode::Start).next().is_none())
}
fn iter(&self) -> Result<IteratorHandle, Error> {
let db_lock = self.db.read();
let db = try!(db_lock.as_ref().ok_or(Error::IsClosed));
let mut iterators = self.iterators.write();
let next_iterator = iterators.keys().last().unwrap_or(&0) + 1;
iterators.insert(next_iterator, db.iterator(IteratorMode::Start));
Ok(next_iterator)
}
fn iter_next(&self, handle: IteratorHandle) -> Option<KeyValue>
{
let mut iterators = self.iterators.write();
let mut iterator = match iterators.get_mut(&handle) {
Some(some_iterator) => some_iterator,
None => { return None; },
};
iterator.next().and_then(|(some_key, some_val)| {
Some(KeyValue {
key: some_key.to_vec(),
value: some_val.to_vec(),
})
})
}
fn dispose_iter(&self, handle: IteratorHandle) -> Result<(), Error> {
let mut iterators = self.iterators.write();
iterators.remove(&handle);
Ok(())
}
}
// TODO : put proper at compile-time
impl IpcConfig for Database {}
/// Database iterator
pub struct DatabaseIterator {
client: Arc<DatabaseClient<::nanomsg::Socket>>,
handle: IteratorHandle,
}
impl Iterator for DatabaseIterator {
type Item = (Vec<u8>, Vec<u8>);
fn next(&mut self) -> Option<Self::Item> {
self.client.iter_next(self.handle).and_then(|kv| Some((kv.key, kv.value)))
}
}
impl Drop for DatabaseIterator {
fn drop(&mut self) {
self.client.dispose_iter(self.handle).unwrap();
}
}
#[cfg(test)]
mod test {
use super::Database;
use traits::*;
use devtools::*;
#[test]
fn can_be_created() {
let db = Database::new();
assert!(db.is_empty().is_err());
}
#[test]
fn can_be_open_empty() {
let db = Database::new();
let path = RandomTempPath::create_dir();
db.open_default(path.as_str().to_owned()).unwrap();
assert!(db.is_empty().is_ok());
}
#[test]
fn can_store_key() {
let db = Database::new();
let path = RandomTempPath::create_dir();
db.open_default(path.as_str().to_owned()).unwrap();
db.put("xxx".as_bytes(), "1".as_bytes()).unwrap();
db.flush_all().unwrap();
assert!(!db.is_empty().unwrap());
}
#[test]
fn can_retrieve() {
let db = Database::new();
let path = RandomTempPath::create_dir();
db.open_default(path.as_str().to_owned()).unwrap();
db.put("xxx".as_bytes(), "1".as_bytes()).unwrap();
db.close().unwrap();
db.open_default(path.as_str().to_owned()).unwrap();
assert_eq!(db.get("xxx".as_bytes()).unwrap().unwrap(), "1".as_bytes().to_vec());
}
}
#[cfg(test)]
mod write_cache_tests {
use super::Database;
use traits::*;
use devtools::*;
#[test]
fn cache_write_flush() {
let db = Database::new();
let path = RandomTempPath::create_dir();
db.open_default(path.as_str().to_owned()).unwrap();
db.put("100500".as_bytes(), "1".as_bytes()).unwrap();
db.delete("100500".as_bytes()).unwrap();
db.flush_all().unwrap();
let val = db.get("100500".as_bytes()).unwrap();
assert!(val.is_none());
}
}
#[cfg(test)]
mod client_tests {
use super::{DatabaseClient, Database};
use traits::*;
use devtools::*;
use nanoipc;
use std::sync::Arc;
use std::sync::atomic::{Ordering, AtomicBool};
use crossbeam;
use run_worker;
fn init_worker(addr: &str) -> nanoipc::Worker<Database> {
let mut worker = nanoipc::Worker::<Database>::new(&Arc::new(Database::new()));
worker.add_duplex(addr).unwrap();
worker
}
#[test]
fn can_call_handshake() {
let url = "ipc:///tmp/parity-db-ipc-test-10.ipc";
let worker_should_exit = Arc::new(AtomicBool::new(false));
let worker_is_ready = Arc::new(AtomicBool::new(false));
let c_worker_should_exit = worker_should_exit.clone();
let c_worker_is_ready = worker_is_ready.clone();
::std::thread::spawn(move || {
let mut worker = init_worker(url);
while !c_worker_should_exit.load(Ordering::Relaxed) {
worker.poll();
c_worker_is_ready.store(true, Ordering::Relaxed);
}
});
while !worker_is_ready.load(Ordering::Relaxed) { }
let client = nanoipc::init_duplex_client::<DatabaseClient<_>>(url).unwrap();
let hs = client.handshake();
worker_should_exit.store(true, Ordering::Relaxed);
assert!(hs.is_ok());
}
#[test]
fn can_open_db() {
let url = "ipc:///tmp/parity-db-ipc-test-20.ipc";
let path = RandomTempPath::create_dir();
let worker_should_exit = Arc::new(AtomicBool::new(false));
let worker_is_ready = Arc::new(AtomicBool::new(false));
let c_worker_should_exit = worker_should_exit.clone();
let c_worker_is_ready = worker_is_ready.clone();
::std::thread::spawn(move || {
let mut worker = init_worker(url);
while !c_worker_should_exit.load(Ordering::Relaxed) {
worker.poll();
c_worker_is_ready.store(true, Ordering::Relaxed);
}
});
while !worker_is_ready.load(Ordering::Relaxed) { }
let client = nanoipc::init_duplex_client::<DatabaseClient<_>>(url).unwrap();
client.open_default(path.as_str().to_owned()).unwrap();
assert!(client.is_empty().unwrap());
worker_should_exit.store(true, Ordering::Relaxed);
}
#[test]
fn can_put() {
let url = "ipc:///tmp/parity-db-ipc-test-30.ipc";
let path = RandomTempPath::create_dir();
crossbeam::scope(move |scope| {
let stop = Arc::new(AtomicBool::new(false));
run_worker(scope, stop.clone(), url);
let client = nanoipc::init_client::<DatabaseClient<_>>(url).unwrap();
client.open_default(path.as_str().to_owned()).unwrap();
client.put("xxx".as_bytes(), "1".as_bytes()).unwrap();
client.close().unwrap();
stop.store(true, Ordering::Relaxed);
});
}
#[test]
fn can_put_and_read() {
let url = "ipc:///tmp/parity-db-ipc-test-40.ipc";
let path = RandomTempPath::create_dir();
crossbeam::scope(move |scope| {
let stop = Arc::new(AtomicBool::new(false));
run_worker(scope, stop.clone(), url);
let client = nanoipc::init_client::<DatabaseClient<_>>(url).unwrap();
client.open_default(path.as_str().to_owned()).unwrap();
client.put("xxx".as_bytes(), "1".as_bytes()).unwrap();
client.close().unwrap();
client.open_default(path.as_str().to_owned()).unwrap();
assert_eq!(client.get("xxx".as_bytes()).unwrap().unwrap(), "1".as_bytes().to_vec());
stop.store(true, Ordering::Relaxed);
});
}
#[test]
fn can_read_empty() {
let url = "ipc:///tmp/parity-db-ipc-test-45.ipc";
let path = RandomTempPath::create_dir();
crossbeam::scope(move |scope| {
let stop = Arc::new(AtomicBool::new(false));
run_worker(scope, stop.clone(), url);
let client = nanoipc::init_client::<DatabaseClient<_>>(url).unwrap();
client.open_default(path.as_str().to_owned()).unwrap();
assert!(client.get("xxx".as_bytes()).unwrap().is_none());
stop.store(true, Ordering::Relaxed);
});
}
#[test]
fn can_commit_client_transaction() {
let url = "ipc:///tmp/parity-db-ipc-test-60.ipc";
let path = RandomTempPath::create_dir();
crossbeam::scope(move |scope| {
let stop = Arc::new(AtomicBool::new(false));
run_worker(scope, stop.clone(), url);
let client = nanoipc::init_client::<DatabaseClient<_>>(url).unwrap();
client.open_default(path.as_str().to_owned()).unwrap();
let transaction = DBTransaction::new();
transaction.put("xxx".as_bytes(), "1".as_bytes());
client.write(transaction).unwrap();
client.close().unwrap();
client.open_default(path.as_str().to_owned()).unwrap();
assert_eq!(client.get("xxx".as_bytes()).unwrap().unwrap(), "1".as_bytes().to_vec());
stop.store(true, Ordering::Relaxed);
});
}
#[test]
fn key_write_read_ipc() {
let url = "ipc:///tmp/parity-db-ipc-test-70.ipc";
let path = RandomTempPath::create_dir();
crossbeam::scope(|scope| {
let stop = StopGuard::new();
run_worker(&scope, stop.share(), url);
let client = nanoipc::init_client::<DatabaseClient<_>>(url).unwrap();
client.open_default(path.as_str().to_owned()).unwrap();
let mut batch = Vec::new();
for _ in 0..100 {
batch.push((random_str(256).as_bytes().to_vec(), random_str(256).as_bytes().to_vec()));
batch.push((random_str(256).as_bytes().to_vec(), random_str(2048).as_bytes().to_vec()));
batch.push((random_str(2048).as_bytes().to_vec(), random_str(2048).as_bytes().to_vec()));
batch.push((random_str(2048).as_bytes().to_vec(), random_str(256).as_bytes().to_vec()));
}
for &(ref k, ref v) in batch.iter() {
client.put(k, v).unwrap();
}
client.close().unwrap();
client.open_default(path.as_str().to_owned()).unwrap();
for &(ref k, ref v) in batch.iter() {
assert_eq!(v, &client.get(k).unwrap().unwrap());
}
});
}
}

View File

@@ -1,20 +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/>.
//! Database ipc service
#![allow(dead_code, unused_assignments, unused_variables)] // codegen issues
include!(concat!(env!("OUT_DIR"), "/lib.rs"));

View File

@@ -1,89 +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/>.
extern crate ethcore_ipc as ipc;
extern crate rocksdb;
extern crate ethcore_devtools as devtools;
extern crate semver;
extern crate ethcore_ipc_nano as nanoipc;
extern crate nanomsg;
extern crate crossbeam;
extern crate ethcore_util as util;
pub mod database;
pub mod traits;
pub use traits::{DatabaseService, DBTransaction, Error};
pub use database::{Database, DatabaseClient, DatabaseIterator};
use std::sync::Arc;
use std::sync::atomic::*;
use std::path::PathBuf;
pub type DatabaseNanoClient = DatabaseClient<::nanomsg::Socket>;
pub type DatabaseConnection = nanoipc::GuardedSocket<DatabaseNanoClient>;
#[derive(Debug)]
pub enum ServiceError {
Io(std::io::Error),
Socket(nanoipc::SocketError),
}
impl std::convert::From<std::io::Error> for ServiceError {
fn from(io_error: std::io::Error) -> ServiceError { ServiceError::Io(io_error) }
}
impl std::convert::From<nanoipc::SocketError> for ServiceError {
fn from(socket_error: nanoipc::SocketError) -> ServiceError { ServiceError::Socket(socket_error) }
}
pub fn blocks_service_url(db_path: &str) -> Result<String, std::io::Error> {
let mut path = PathBuf::from(db_path);
try!(::std::fs::create_dir_all(db_path));
path.push("blocks.ipc");
Ok(format!("ipc://{}", path.to_str().unwrap()))
}
pub fn extras_service_url(db_path: &str) -> Result<String, ::std::io::Error> {
let mut path = PathBuf::from(db_path);
try!(::std::fs::create_dir_all(db_path));
path.push("extras.ipc");
Ok(format!("ipc://{}", path.to_str().unwrap()))
}
pub fn blocks_client(db_path: &str) -> Result<DatabaseConnection, ServiceError> {
let url = try!(blocks_service_url(db_path));
let client = try!(nanoipc::init_client::<DatabaseClient<_>>(&url));
Ok(client)
}
pub fn extras_client(db_path: &str) -> Result<DatabaseConnection, ServiceError> {
let url = try!(extras_service_url(db_path));
let client = try!(nanoipc::init_client::<DatabaseClient<_>>(&url));
Ok(client)
}
// for tests
pub fn run_worker(scope: &crossbeam::Scope, stop: Arc<AtomicBool>, socket_path: &str) {
let socket_path = socket_path.to_owned();
scope.spawn(move || {
let mut worker = nanoipc::Worker::new(&Arc::new(Database::new()));
worker.add_reqrep(&socket_path).unwrap();
while !stop.load(Ordering::Relaxed) {
worker.poll();
}
});
}

View File

@@ -1,138 +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/>.
//! Ethcore database trait
use std::mem;
use ipc::binary::BinaryConvertError;
use std::collections::VecDeque;
use std::cell::RefCell;
pub type IteratorHandle = u32;
pub const DEFAULT_CACHE_LEN: usize = 12288;
#[derive(Binary)]
pub struct KeyValue {
pub key: Vec<u8>,
pub value: Vec<u8>,
}
#[derive(Debug, Binary)]
pub enum Error {
AlreadyOpen,
IsClosed,
RocksDb(String),
TransactionUnknown,
IteratorUnknown,
UncommitedTransactions,
}
impl From<String> for Error {
fn from(s: String) -> Error {
Error::RocksDb(s)
}
}
/// Database configuration
#[derive(Binary)]
pub struct DatabaseConfig {
/// Optional prefix size in bytes. Allows lookup by partial key.
pub prefix_size: Option<usize>,
/// write cache length
pub cache: usize,
}
impl Default for DatabaseConfig {
fn default() -> DatabaseConfig {
DatabaseConfig {
prefix_size: None,
cache: DEFAULT_CACHE_LEN,
}
}
}
impl DatabaseConfig {
fn with_prefix(prefix: usize) -> DatabaseConfig {
DatabaseConfig {
prefix_size: Some(prefix),
cache: DEFAULT_CACHE_LEN,
}
}
}
pub trait DatabaseService : Sized {
/// Opens database in the specified path
fn open(&self, config: DatabaseConfig, path: String) -> Result<(), Error>;
/// Opens database in the specified path with the default config
fn open_default(&self, path: String) -> Result<(), Error>;
/// Closes database
fn close(&self) -> Result<(), Error>;
/// Insert a key-value pair in the transaction. Any existing value value will be overwritten.
fn put(&self, key: &[u8], value: &[u8]) -> Result<(), Error>;
/// Delete value by key.
fn delete(&self, key: &[u8]) -> Result<(), Error>;
/// Get value by key.
fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Error>;
/// Get value by partial key. Prefix size should match configured prefix size.
fn get_by_prefix(&self, prefix: &[u8]) -> Result<Option<Vec<u8>>, Error>;
/// Check if there is anything in the database.
fn is_empty(&self) -> Result<bool, Error>;
/// Get handle to iterate through keys
fn iter(&self) -> Result<IteratorHandle, Error>;
/// Next key-value for the the given iterator
fn iter_next(&self, iterator: IteratorHandle) -> Option<KeyValue>;
/// Dispose iteration that is no longer needed
fn dispose_iter(&self, handle: IteratorHandle) -> Result<(), Error>;
/// Write client transaction
fn write(&self, transaction: DBTransaction) -> Result<(), Error>;
}
#[derive(Binary)]
pub struct DBTransaction {
pub writes: RefCell<Vec<KeyValue>>,
pub removes: RefCell<Vec<Vec<u8>>>,
}
impl DBTransaction {
pub fn new() -> DBTransaction {
DBTransaction {
writes: RefCell::new(Vec::new()),
removes: RefCell::new(Vec::new()),
}
}
pub fn put(&self, key: &[u8], value: &[u8]) {
let mut brw = self.writes.borrow_mut();
brw.push(KeyValue { key: key.to_vec(), value: value.to_vec() });
}
pub fn delete(&self, key: &[u8]) {
let mut brw = self.removes.borrow_mut();
brw.push(key.to_vec());
}
}

View File

@@ -3,7 +3,7 @@ description = "Ethcore development/test/build tools"
homepage = "http://ethcore.io" homepage = "http://ethcore.io"
license = "GPL-3.0" license = "GPL-3.0"
name = "ethcore-devtools" name = "ethcore-devtools"
version = "1.3.0" version = "1.0.0"
authors = ["Ethcore <admin@ethcore.io>"] authors = ["Ethcore <admin@ethcore.io>"]
[dependencies] [dependencies]

1
devtools/README.md Normal file
View File

@@ -0,0 +1 @@
# ethcore dev tools

View File

@@ -19,10 +19,6 @@
extern crate rand; extern crate rand;
mod random_path; pub mod random_path;
mod test_socket;
mod stop_guard;
pub use random_path::*; pub use random_path::*;
pub use test_socket::*;
pub use stop_guard::*;

View File

@@ -19,7 +19,6 @@
use std::path::*; use std::path::*;
use std::fs; use std::fs;
use std::env; use std::env;
use std::ops::{Deref, DerefMut};
use rand::random; use rand::random;
pub struct RandomTempPath { pub struct RandomTempPath {
@@ -27,11 +26,7 @@ pub struct RandomTempPath {
} }
pub fn random_filename() -> String { pub fn random_filename() -> String {
random_str(8) (0..8).map(|_| ((random::<f32>() * 26.0) as u8 + 97) as char).collect()
}
pub fn random_str(len: usize) -> String {
(0..len).map(|_| ((random::<f32>() * 26.0) as u8 + 97) as char).collect()
} }
impl RandomTempPath { impl RandomTempPath {
@@ -59,51 +54,16 @@ impl RandomTempPath {
pub fn as_str(&self) -> &str { pub fn as_str(&self) -> &str {
self.path.to_str().unwrap() self.path.to_str().unwrap()
} }
pub fn new_in(&self, name: &str) -> String {
let mut path = self.path.clone();
path.push(name);
path.to_str().unwrap().to_owned()
}
} }
impl Drop for RandomTempPath { impl Drop for RandomTempPath {
fn drop(&mut self) { fn drop(&mut self) {
if let Err(e) = fs::remove_dir_all(self.as_path()) { if let Err(e) = fs::remove_dir_all(self.as_path()) {
panic!("Failed to remove temp directory. Here's what prevented this from happening: ({})", e); panic!("failed to remove temp directory, probably something failed to destroyed ({})", e);
} }
} }
} }
pub struct GuardedTempResult<T> {
pub result: Option<T>,
pub _temp: RandomTempPath
}
impl<T> GuardedTempResult<T> {
pub fn reference(&self) -> &T {
self.result.as_ref().unwrap()
}
pub fn reference_mut(&mut self) -> &mut T {
self.result.as_mut().unwrap()
}
pub fn take(&mut self) -> T {
self.result.take().unwrap()
}
}
impl<T> Deref for GuardedTempResult<T> {
type Target = T;
fn deref(&self) -> &T { self.result.as_ref().unwrap() }
}
impl<T> DerefMut for GuardedTempResult<T> {
fn deref_mut(&mut self) -> &mut T { self.result.as_mut().unwrap() }
}
#[test] #[test]
fn creates_dir() { fn creates_dir() {
let temp = RandomTempPath::create_dir(); let temp = RandomTempPath::create_dir();

View File

@@ -1,45 +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/>.
//! Stop guard mod
use std::sync::Arc;
use std::sync::atomic::*;
/// Stop guard that will set a stop flag on drop
pub struct StopGuard {
flag: Arc<AtomicBool>,
}
impl StopGuard {
/// Create a stop guard
pub fn new() -> StopGuard {
StopGuard {
flag: Arc::new(AtomicBool::new(false))
}
}
/// Share stop guard between the threads
pub fn share(&self) -> Arc<AtomicBool> {
self.flag.clone()
}
}
impl Drop for StopGuard {
fn drop(&mut self) {
self.flag.store(true, Ordering::Relaxed)
}
}

View File

@@ -1,95 +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 std::io::*;
use std::cmp;
pub struct TestSocket {
pub read_buffer: Vec<u8>,
pub write_buffer: Vec<u8>,
pub cursor: usize,
pub buf_size: usize,
}
impl Default for TestSocket {
fn default() -> Self {
TestSocket::new()
}
}
impl TestSocket {
pub fn new() -> Self {
TestSocket {
read_buffer: vec![],
write_buffer: vec![],
cursor: 0,
buf_size: 0,
}
}
pub fn new_buf(buf_size: usize) -> TestSocket {
TestSocket {
read_buffer: vec![],
write_buffer: vec![],
cursor: 0,
buf_size: buf_size,
}
}
pub fn new_ready(data: Vec<u8>) -> TestSocket {
TestSocket {
read_buffer: data,
write_buffer: vec![],
cursor: 0,
buf_size: 0,
}
}
}
impl Read for TestSocket {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
let end_position = cmp::min(self.read_buffer.len(), self.cursor+buf.len());
if self.cursor > end_position { return Ok(0) }
let len = cmp::max(end_position - self.cursor, 0);
match len {
0 => Ok(0),
_ => {
for i in self.cursor..end_position {
buf[i-self.cursor] = self.read_buffer[i];
}
self.cursor = end_position;
Ok(len)
}
}
}
}
impl Write for TestSocket {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
if self.buf_size == 0 || buf.len() < self.buf_size {
self.write_buffer.extend(buf.iter().cloned());
Ok(buf.len())
}
else {
self.write_buffer.extend(buf.iter().take(self.buf_size).cloned());
Ok(self.buf_size)
}
}
fn flush(&mut self) -> Result<()> {
unimplemented!();
}
}

11
doc.sh Executable file
View File

@@ -0,0 +1,11 @@
#!/bin/sh
# generate documentation only for partiy and ethcore libraries
cargo doc --no-deps --verbose \
-p ethash \
-p ethcore-util \
-p ethcore \
-p ethsync \
-p ethcore-rpc \
-p parity \
-p ethminer

View File

@@ -1,29 +0,0 @@
FROM centos:latest
WORKDIR /build
# install tools and dependencies
RUN yum -y update&& \
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
# 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 && \
strip /build/parity/target/release/parity
RUN file /build/parity/target/release/parity

View File

@@ -1,43 +0,0 @@
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
# show tools
RUN rustc -vV && \
cargo -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

@@ -1,43 +0,0 @@
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 clean
# install rustup
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
# rustup directory
ENV PATH /root/.cargo/bin:$PATH
ENV RUST_TARGETS="arm-unknown-linux-gnueabihf"
# multirust add arm--linux-gnuabhf toolchain
RUN rustup target add armv7-unknown-linux-gnueabihf
# show backtraces
ENV RUST_BACKTRACE 1
# show tools
RUN rustc -vV && \
cargo -V
# build parity
RUN git clone https://github.com/ethcore/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

@@ -27,11 +27,11 @@ RUN git clone https://github.com/debris/evmjit && \
mkdir build && cd build && \ mkdir build && cd build && \
cmake .. && make && make install && cd cmake .. && make && make install && cd
# install rustup # install multirust
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y RUN curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes
# rustup directory # export rust LIBRARY_PATH
ENV PATH /root/.cargo/bin:$PATH ENV LIBRARY_PATH /usr/local/lib
# show backtraces # show backtraces
ENV RUST_BACKTRACE 1 ENV RUST_BACKTRACE 1

View File

@@ -1,55 +1,42 @@
FROM ubuntu:14.04 FROM ubuntu:14.04
WORKDIR /build
# install tools and dependencies # install tools and dependencies
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y \ apt-get install -y \
# make # make
build-essential \ build-essential \
# add-apt-repository # add-apt-repository
software-properties-common \ software-properties-common \
curl \ curl \
wget \ wget \
git \ git \
g++ \ g++ \
binutils \ # evmjit dependencies
file \ zlib1g-dev \
# evmjit dependencies libedit-dev
zlib1g-dev \
libedit-dev
# cmake and llvm ppas. then update ppas # cmake, llvm and rocksdb ppas. then update ppas
RUN add-apt-repository -y "ppa:george-edison55/cmake-3.x" && \ 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" && \ add-apt-repository "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main" && \
apt-get update && \ apt-get update && \
apt-get install -y --force-yes cmake llvm-3.7-dev apt-get install -y --force-yes cmake llvm-3.7-dev
# install evmjit # install evmjit
RUN git clone https://github.com/debris/evmjit && \ RUN git clone https://github.com/debris/evmjit && \
cd evmjit && \ cd evmjit && \
mkdir build && cd build && \ mkdir build && cd build && \
cmake .. && make && make install && cd cmake .. && make && make install && cd
# install rustup # install multirust
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y RUN curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes
# rustup directory # export rust LIBRARY_PATH
ENV PATH /root/.cargo/bin:$PATH ENV LIBRARY_PATH /usr/local/lib
# show backtraces # show backtraces
ENV RUST_BACKTRACE 1 ENV RUST_BACKTRACE 1
# show tools
RUN rustc -vV && \
cargo -V && \
gcc -v &&\
g++ -v
# build parity # build parity
RUN git clone https://github.com/ethcore/parity && \ RUN git clone https://github.com/ethcore/parity && \
cd parity && \ cd parity && \
git checkout beta && \ cargo build --release --features ethcore/jit
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,40 +0,0 @@
FROM ubuntu:14.04
WORKDIR /build
# install tools and dependencies
RUN apt-get update && \
apt-get install -y \
g++ \
curl \
git \
file \
binutils \
make
# install rustup
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
# rustup directory
ENV PATH /root/.cargo/bin:$PATH
# show backtraces
ENV RUST_BACKTRACE 1
# show tools
RUN rustc -vV && \
cargo -V && \
gcc -v &&\
g++ -v
# build parity
RUN git clone https://github.com/ethcore/parity && \
cd parity && \
git checkout stable && \
git pull && \
cargo build --release --verbose && \
ls /build/parity/target/release/parity && \
strip /build/parity/target/release/parity
RUN file /build/parity/target/release/parity
EXPOSE 8080 8545 8180
ENTRYPOINT ["/build/parity/target/release/parity"]

View File

@@ -1,36 +1,23 @@
FROM ubuntu:14.04 FROM ubuntu:14.04
WORKDIR /build
# install tools and dependencies # install tools and dependencies
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y \ apt-get install -y \
g++ \ g++ \
curl \ curl \
git \ git \
file \ make
binutils
# install rustup # install multirust
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y RUN curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes
# rustup directory # export rust LIBRARY_PATH
ENV PATH /root/.cargo/bin:$PATH ENV LIBRARY_PATH /usr/local/lib
# show backtraces # show backtraces
ENV RUST_BACKTRACE 1 ENV RUST_BACKTRACE 1
# show tools
RUN rustc -vV && \
cargo -V && \
gcc -v &&\
g++ -v
# build parity # build parity
RUN git clone https://github.com/ethcore/parity && \ RUN git clone https://github.com/ethcore/parity && \
cd parity && \ cd parity && \
git checkout beta && \ cargo build --release
git pull && \
cargo build --release --verbose && \
ls /build/parity/target/release/parity && \
strip /build/parity/target/release/parity
ENTRYPOINT ["/build/parity/target/release/parity"]

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "ethash" name = "ethash"
version = "1.3.0" version = "1.0.0"
authors = ["arkpar <arkadiy@ethcore.io"] authors = ["arkpar <arkadiy@ethcore.io"]
[lib] [lib]
@@ -9,4 +9,3 @@ authors = ["arkpar <arkadiy@ethcore.io"]
log = "0.3" log = "0.3"
sha3 = { path = "../util/sha3" } sha3 = { path = "../util/sha3" }
primal = "0.2.3" primal = "0.2.3"
parking_lot = "0.2.6"

View File

@@ -20,17 +20,14 @@
// TODO: fix endianess for big endian // TODO: fix endianess for big endian
use primal::is_prime; use primal::is_prime;
use std::cell::Cell;
use std::mem; use std::mem;
use std::ptr; use std::ptr;
use sha3; use sha3;
use std::slice; use std::slice;
use std::path::PathBuf; use std::path::PathBuf;
use std::io::{self, Read, Write}; use std::io::{Read, Write, self};
use std::fs::{self, File}; use std::fs::{self, File};
use parking_lot::Mutex;
pub const ETHASH_EPOCH_LENGTH: u64 = 30000; pub const ETHASH_EPOCH_LENGTH: u64 = 30000;
pub const ETHASH_CACHE_ROUNDS: usize = 3; pub const ETHASH_CACHE_ROUNDS: usize = 3;
pub const ETHASH_MIX_BYTES: usize = 128; pub const ETHASH_MIX_BYTES: usize = 128;
@@ -45,14 +42,14 @@ const NODE_WORDS: usize = 64 / 4;
const NODE_BYTES: usize = 64; const NODE_BYTES: usize = 64;
const MIX_WORDS: usize = ETHASH_MIX_BYTES / 4; const MIX_WORDS: usize = ETHASH_MIX_BYTES / 4;
const MIX_NODES: usize = MIX_WORDS / NODE_WORDS; const MIX_NODES: usize = MIX_WORDS / NODE_WORDS;
const FNV_PRIME: u32 = 0x01000193; const FNV_PRIME: u32 = 0x01000193;
/// Computation result /// Computation result
pub struct ProofOfWork { pub struct ProofOfWork {
/// Difficulty boundary /// Difficulty boundary
pub value: H256, pub value: H256,
/// Mix /// Mix
pub mix_hash: H256, pub mix_hash: H256
} }
struct Node { struct Node {
@@ -88,7 +85,6 @@ pub type H256 = [u8; 32];
pub struct Light { pub struct Light {
block_number: u64, block_number: u64,
cache: Vec<Node>, cache: Vec<Node>,
seed_compute: Mutex<SeedHashCompute>,
} }
/// Light cache structur /// Light cache structur
@@ -105,17 +101,17 @@ impl Light {
light_compute(self, header_hash, nonce) light_compute(self, header_hash, nonce)
} }
pub fn file_path(seed_hash: H256) -> PathBuf { pub fn file_path(block_number: u64) -> PathBuf {
let mut home = ::std::env::home_dir().unwrap(); let mut home = ::std::env::home_dir().unwrap();
home.push(".ethash"); home.push(".ethash");
home.push("light"); home.push("light");
let seed_hash = get_seedhash(block_number);
home.push(to_hex(&seed_hash)); home.push(to_hex(&seed_hash));
home home
} }
pub fn from_file(block_number: u64) -> io::Result<Light> { pub fn from_file(block_number: u64) -> io::Result<Light> {
let seed_compute = SeedHashCompute::new(); let path = Light::file_path(block_number);
let path = Light::file_path(seed_compute.get_seedhash(block_number));
let mut file = try!(File::open(path)); let mut file = try!(File::open(path));
let cache_size = get_cache_size(block_number); let cache_size = get_cache_size(block_number);
@@ -130,13 +126,11 @@ impl Light {
Ok(Light { Ok(Light {
cache: nodes, cache: nodes,
block_number: block_number, block_number: block_number,
seed_compute: Mutex::new(seed_compute),
}) })
} }
pub fn to_file(&self) -> io::Result<()> { pub fn to_file(&self) -> io::Result<()> {
let seed_compute = self.seed_compute.lock(); let path = Light::file_path(self.block_number);
let path = Light::file_path(seed_compute.get_seedhash(self.block_number));
try!(fs::create_dir_all(path.parent().unwrap())); try!(fs::create_dir_all(path.parent().unwrap()));
let mut file = try!(File::create(path)); let mut file = try!(File::create(path));
@@ -147,51 +141,6 @@ impl Light {
} }
} }
pub struct SeedHashCompute {
prev_epoch: Cell<u64>,
prev_seedhash: Cell<H256>,
}
impl SeedHashCompute {
#[inline]
pub fn new() -> SeedHashCompute {
SeedHashCompute {
prev_epoch: Cell::new(0),
prev_seedhash: Cell::new([0u8; 32]),
}
}
#[inline]
fn reset_cache(&self) {
self.prev_epoch.set(0);
self.prev_seedhash.set([0u8; 32]);
}
#[inline]
pub fn get_seedhash(&self, block_number: u64) -> H256 {
let epoch = block_number / ETHASH_EPOCH_LENGTH;
if epoch < self.prev_epoch.get() {
// can't build on previous hash if requesting an older block
self.reset_cache();
}
if epoch > self.prev_epoch.get() {
let seed_hash = SeedHashCompute::resume_compute_seedhash(self.prev_seedhash.get(), self.prev_epoch.get(), epoch);
self.prev_seedhash.set(seed_hash);
self.prev_epoch.set(epoch);
}
self.prev_seedhash.get()
}
#[inline]
pub fn resume_compute_seedhash(mut hash: H256, start_epoch: u64, end_epoch: u64) -> H256 {
for _ in start_epoch..end_epoch {
unsafe { sha3::sha3_256(hash[..].as_mut_ptr(), 32, hash[..].as_ptr(), 32) };
}
hash
}
}
#[inline] #[inline]
fn fnv_hash(x: u32, y: u32) -> u32 { fn fnv_hash(x: u32, y: u32) -> u32 {
return x.wrapping_mul(FNV_PRIME) ^ y; return x.wrapping_mul(FNV_PRIME) ^ y;
@@ -204,24 +153,34 @@ fn sha3_512(input: &[u8], output: &mut [u8]) {
#[inline] #[inline]
fn get_cache_size(block_number: u64) -> usize { fn get_cache_size(block_number: u64) -> usize {
let mut sz: u64 = CACHE_BYTES_INIT + CACHE_BYTES_GROWTH * (block_number / ETHASH_EPOCH_LENGTH); let mut sz: u64 = CACHE_BYTES_INIT + CACHE_BYTES_GROWTH * (block_number / ETHASH_EPOCH_LENGTH);
sz = sz - NODE_BYTES as u64; sz = sz - NODE_BYTES as u64;
while !is_prime(sz / NODE_BYTES as u64) { while !is_prime(sz / NODE_BYTES as u64) {
sz = sz - 2 * NODE_BYTES as u64; sz = sz - 2 * NODE_BYTES as u64;
} }
sz as usize sz as usize
} }
#[inline] #[inline]
fn get_data_size(block_number: u64) -> usize { fn get_data_size(block_number: u64) -> usize {
let mut sz: u64 = DATASET_BYTES_INIT + DATASET_BYTES_GROWTH * (block_number / ETHASH_EPOCH_LENGTH); let mut sz: u64 = DATASET_BYTES_INIT + DATASET_BYTES_GROWTH * (block_number / ETHASH_EPOCH_LENGTH);
sz = sz - ETHASH_MIX_BYTES as u64; sz = sz - ETHASH_MIX_BYTES as u64;
while !is_prime(sz / ETHASH_MIX_BYTES as u64) { while !is_prime(sz / ETHASH_MIX_BYTES as u64) {
sz = sz - 2 * ETHASH_MIX_BYTES as u64; sz = sz - 2 * ETHASH_MIX_BYTES as u64;
} }
sz as usize sz as usize
} }
#[inline]
/// Given the `block_number`, determine the seed hash for Ethash.
pub fn get_seedhash(block_number: u64) -> H256 {
let epochs = block_number / ETHASH_EPOCH_LENGTH;
let mut ret: H256 = [0u8; 32];
for _ in 0..epochs {
unsafe { sha3::sha3_256(ret[..].as_mut_ptr(), 32, ret[..].as_ptr(), 32) };
}
ret
}
/// Difficulty quick check for POW preverification /// Difficulty quick check for POW preverification
/// ///
@@ -252,12 +211,12 @@ pub fn light_compute(light: &Light, header_hash: &H256, nonce: u64) -> ProofOfWo
hash_compute(light, full_size, header_hash, nonce) hash_compute(light, full_size, header_hash, nonce)
} }
fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64) -> ProofOfWork { fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64) -> ProofOfWork {
if full_size % MIX_WORDS != 0 { if full_size % MIX_WORDS != 0 {
panic!("Unaligned full size"); panic!("Unaligned full size");
} }
// pack hash and nonce together into first 40 bytes of s_mix // pack hash and nonce together into first 40 bytes of s_mix
let mut s_mix: [Node; MIX_NODES + 1] = [Node::default(), Node::default(), Node::default()]; let mut s_mix: [Node; MIX_NODES + 1] = [ Node::default(), Node::default(), Node::default() ];
unsafe { ptr::copy_nonoverlapping(header_hash.as_ptr(), s_mix.get_unchecked_mut(0).bytes.as_mut_ptr(), 32) }; unsafe { ptr::copy_nonoverlapping(header_hash.as_ptr(), s_mix.get_unchecked_mut(0).bytes.as_mut_ptr(), 32) };
unsafe { ptr::copy_nonoverlapping(mem::transmute(&nonce), s_mix.get_unchecked_mut(0).bytes[32..].as_mut_ptr(), 8) }; unsafe { ptr::copy_nonoverlapping(mem::transmute(&nonce), s_mix.get_unchecked_mut(0).bytes[32..].as_mut_ptr(), 8) };
@@ -271,12 +230,11 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64)
let page_size = 4 * MIX_WORDS; let page_size = 4 * MIX_WORDS;
let num_full_pages = (full_size / page_size) as u32; let num_full_pages = (full_size / page_size) as u32;
let cache: &[Node] = &light.cache; // deref once for better performance
for i in 0..(ETHASH_ACCESSES as u32) { for i in 0..(ETHASH_ACCESSES as u32) {
let index = fnv_hash(f_mix.get_unchecked(0).as_words().get_unchecked(0) ^ i, *mix.get_unchecked(0).as_words().get_unchecked((i as usize) % MIX_WORDS)) % num_full_pages; let index = fnv_hash(f_mix.get_unchecked(0).as_words().get_unchecked(0) ^ i, *mix.get_unchecked(0).as_words().get_unchecked((i as usize) % MIX_WORDS)) % num_full_pages;
for n in 0..MIX_NODES { for n in 0..MIX_NODES {
let tmp_node = calculate_dag_item(index * MIX_NODES as u32 + n as u32, cache); let tmp_node = calculate_dag_item(index * MIX_NODES as u32 + n as u32, light);
for w in 0..NODE_WORDS { for w in 0..NODE_WORDS {
*mix.get_unchecked_mut(n).as_words_mut().get_unchecked_mut(w) = fnv_hash(*mix.get_unchecked(n).as_words().get_unchecked(w), *tmp_node.as_words().get_unchecked(w)); *mix.get_unchecked_mut(n).as_words_mut().get_unchecked_mut(w) = fnv_hash(*mix.get_unchecked(n).as_words().get_unchecked(w), *tmp_node.as_words().get_unchecked(w));
} }
@@ -299,7 +257,7 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64)
ptr::copy_nonoverlapping(mix.get_unchecked_mut(0).bytes.as_ptr(), buf[64..].as_mut_ptr(), 32); ptr::copy_nonoverlapping(mix.get_unchecked_mut(0).bytes.as_ptr(), buf[64..].as_mut_ptr(), 32);
ptr::copy_nonoverlapping(mix.get_unchecked_mut(0).bytes.as_ptr(), mix_hash.as_mut_ptr(), 32); ptr::copy_nonoverlapping(mix.get_unchecked_mut(0).bytes.as_ptr(), mix_hash.as_mut_ptr(), 32);
let mut value: H256 = [0u8; 32]; let mut value: H256 = [0u8; 32];
sha3::sha3_256(value.as_mut_ptr(), value.len(), buf.as_ptr(), buf.len()); sha3::sha3_256(value.as_mut_ptr(), value.len(), buf.as_ptr(), buf.len());
ProofOfWork { ProofOfWork {
mix_hash: mix_hash, mix_hash: mix_hash,
value: value, value: value,
@@ -307,17 +265,18 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64)
} }
} }
fn calculate_dag_item(node_index: u32, cache: &[Node]) -> Node { fn calculate_dag_item(node_index: u32, light: &Light) -> Node {
unsafe { unsafe {
let num_parent_nodes = cache.len(); let num_parent_nodes = light.cache.len();
let init = cache.get_unchecked(node_index as usize % num_parent_nodes); let cache_nodes = &light.cache;
let init = cache_nodes.get_unchecked(node_index as usize % num_parent_nodes);
let mut ret = init.clone(); let mut ret = init.clone();
*ret.as_words_mut().get_unchecked_mut(0) ^= node_index; *ret.as_words_mut().get_unchecked_mut(0) ^= node_index;
sha3::sha3_512(ret.bytes.as_mut_ptr(), ret.bytes.len(), ret.bytes.as_ptr(), ret.bytes.len()); sha3::sha3_512(ret.bytes.as_mut_ptr(), ret.bytes.len(), ret.bytes.as_ptr(), ret.bytes.len());
for i in 0..ETHASH_DATASET_PARENTS { for i in 0..ETHASH_DATASET_PARENTS {
let parent_index = fnv_hash(node_index ^ i, *ret.as_words().get_unchecked(i as usize % NODE_WORDS)) % num_parent_nodes as u32; let parent_index = fnv_hash(node_index ^ i, *ret.as_words().get_unchecked(i as usize % NODE_WORDS)) % num_parent_nodes as u32;
let parent = cache.get_unchecked(parent_index as usize); let parent = cache_nodes.get_unchecked(parent_index as usize);
for w in 0..NODE_WORDS { for w in 0..NODE_WORDS {
*ret.as_words_mut().get_unchecked_mut(w) = fnv_hash(*ret.as_words().get_unchecked(w), *parent.as_words().get_unchecked(w)); *ret.as_words_mut().get_unchecked_mut(w) = fnv_hash(*ret.as_words().get_unchecked(w), *parent.as_words().get_unchecked(w));
} }
@@ -328,9 +287,7 @@ fn calculate_dag_item(node_index: u32, cache: &[Node]) -> Node {
} }
fn light_new(block_number: u64) -> Light { fn light_new(block_number: u64) -> Light {
let seedhash = get_seedhash(block_number);
let seed_compute = SeedHashCompute::new();
let seedhash = seed_compute.get_seedhash(block_number);
let cache_size = get_cache_size(block_number); let cache_size = get_cache_size(block_number);
if cache_size % NODE_BYTES != 0 { if cache_size % NODE_BYTES != 0 {
@@ -351,7 +308,7 @@ fn light_new(block_number: u64) -> Light {
let idx = *nodes.get_unchecked_mut(i).as_words().get_unchecked(0) as usize % num_nodes; let idx = *nodes.get_unchecked_mut(i).as_words().get_unchecked(0) as usize % num_nodes;
let mut data = nodes.get_unchecked((num_nodes - 1 + i) % num_nodes).clone(); let mut data = nodes.get_unchecked((num_nodes - 1 + i) % num_nodes).clone();
for w in 0..NODE_WORDS { for w in 0..NODE_WORDS {
*data.as_words_mut().get_unchecked_mut(w) ^= *nodes.get_unchecked(idx).as_words().get_unchecked(w); *data.as_words_mut().get_unchecked_mut(w) ^= *nodes.get_unchecked(idx).as_words().get_unchecked(w) ;
} }
sha3_512(&data.bytes, &mut nodes.get_unchecked_mut(i).bytes); sha3_512(&data.bytes, &mut nodes.get_unchecked_mut(i).bytes);
} }
@@ -361,11 +318,10 @@ fn light_new(block_number: u64) -> Light {
Light { Light {
cache: nodes, cache: nodes,
block_number: block_number, block_number: block_number,
seed_compute: Mutex::new(seed_compute),
} }
} }
static CHARS: &'static [u8] = b"0123456789abcdef"; static CHARS: &'static[u8] = b"0123456789abcdef";
fn to_hex(bytes: &[u8]) -> String { fn to_hex(bytes: &[u8]) -> String {
let mut v = Vec::with_capacity(bytes.len() * 2); let mut v = Vec::with_capacity(bytes.len() * 2);
for &byte in bytes.iter() { for &byte in bytes.iter() {
@@ -373,7 +329,9 @@ fn to_hex(bytes: &[u8]) -> String {
v.push(CHARS[(byte & 0xf) as usize]); v.push(CHARS[(byte & 0xf) as usize]);
} }
unsafe { String::from_utf8_unchecked(v) } unsafe {
String::from_utf8_unchecked(v)
}
} }
#[test] #[test]
@@ -403,8 +361,8 @@ fn test_get_data_size() {
#[test] #[test]
fn test_difficulty_test() { fn test_difficulty_test() {
let hash = [0xf5, 0x7e, 0x6f, 0x3a, 0xcf, 0xc0, 0xdd, 0x4b, 0x5b, 0xf2, 0xbe, 0xe4, 0x0a, 0xb3, 0x35, 0x8a, 0xa6, 0x87, 0x73, 0xa8, 0xd0, 0x9f, 0x5e, 0x59, 0x5e, 0xab, 0x55, 0x94, 0x05, 0x52, 0x7d, 0x72]; let hash = [0xf5, 0x7e, 0x6f, 0x3a, 0xcf, 0xc0, 0xdd, 0x4b, 0x5b, 0xf2, 0xbe, 0xe4, 0x0a, 0xb3, 0x35, 0x8a, 0xa6, 0x87, 0x73, 0xa8, 0xd0, 0x9f, 0x5e, 0x59, 0x5e, 0xab, 0x55, 0x94, 0x05, 0x52, 0x7d, 0x72];
let mix_hash = [0x1f, 0xff, 0x04, 0xce, 0xc9, 0x41, 0x73, 0xfd, 0x59, 0x1e, 0x3d, 0x89, 0x60, 0xce, 0x6b, 0xdf, 0x8b, 0x19, 0x71, 0x04, 0x8c, 0x71, 0xff, 0x93, 0x7b, 0xb2, 0xd3, 0x2a, 0x64, 0x31, 0xab, 0x6d]; let mix_hash = [0x1f, 0xff, 0x04, 0xce, 0xc9, 0x41, 0x73, 0xfd, 0x59, 0x1e, 0x3d, 0x89, 0x60, 0xce, 0x6b, 0xdf, 0x8b, 0x19, 0x71, 0x04, 0x8c, 0x71, 0xff, 0x93, 0x7b, 0xb2, 0xd3, 0x2a, 0x64, 0x31, 0xab, 0x6d ];
let nonce = 0xd7b3ac70a301a249; let nonce = 0xd7b3ac70a301a249;
let boundary_good = [0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3e, 0x9b, 0x6c, 0x69, 0xbc, 0x2c, 0xe2, 0xa2, 0x4a, 0x8e, 0x95, 0x69, 0xef, 0xc7, 0xd7, 0x1b, 0x33, 0x35, 0xdf, 0x36, 0x8c, 0x9a, 0xe9, 0x7e, 0x53, 0x84]; let boundary_good = [0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3e, 0x9b, 0x6c, 0x69, 0xbc, 0x2c, 0xe2, 0xa2, 0x4a, 0x8e, 0x95, 0x69, 0xef, 0xc7, 0xd7, 0x1b, 0x33, 0x35, 0xdf, 0x36, 0x8c, 0x9a, 0xe9, 0x7e, 0x53, 0x84];
assert_eq!(quick_get_difficulty(&hash, nonce, &mix_hash)[..], boundary_good[..]); assert_eq!(quick_get_difficulty(&hash, nonce, &mix_hash)[..], boundary_good[..]);
@@ -414,8 +372,8 @@ fn test_difficulty_test() {
#[test] #[test]
fn test_light_compute() { fn test_light_compute() {
let hash = [0xf5, 0x7e, 0x6f, 0x3a, 0xcf, 0xc0, 0xdd, 0x4b, 0x5b, 0xf2, 0xbe, 0xe4, 0x0a, 0xb3, 0x35, 0x8a, 0xa6, 0x87, 0x73, 0xa8, 0xd0, 0x9f, 0x5e, 0x59, 0x5e, 0xab, 0x55, 0x94, 0x05, 0x52, 0x7d, 0x72]; let hash = [0xf5, 0x7e, 0x6f, 0x3a, 0xcf, 0xc0, 0xdd, 0x4b, 0x5b, 0xf2, 0xbe, 0xe4, 0x0a, 0xb3, 0x35, 0x8a, 0xa6, 0x87, 0x73, 0xa8, 0xd0, 0x9f, 0x5e, 0x59, 0x5e, 0xab, 0x55, 0x94, 0x05, 0x52, 0x7d, 0x72];
let mix_hash = [0x1f, 0xff, 0x04, 0xce, 0xc9, 0x41, 0x73, 0xfd, 0x59, 0x1e, 0x3d, 0x89, 0x60, 0xce, 0x6b, 0xdf, 0x8b, 0x19, 0x71, 0x04, 0x8c, 0x71, 0xff, 0x93, 0x7b, 0xb2, 0xd3, 0x2a, 0x64, 0x31, 0xab, 0x6d]; let mix_hash = [0x1f, 0xff, 0x04, 0xce, 0xc9, 0x41, 0x73, 0xfd, 0x59, 0x1e, 0x3d, 0x89, 0x60, 0xce, 0x6b, 0xdf, 0x8b, 0x19, 0x71, 0x04, 0x8c, 0x71, 0xff, 0x93, 0x7b, 0xb2, 0xd3, 0x2a, 0x64, 0x31, 0xab, 0x6d ];
let boundary = [0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3e, 0x9b, 0x6c, 0x69, 0xbc, 0x2c, 0xe2, 0xa2, 0x4a, 0x8e, 0x95, 0x69, 0xef, 0xc7, 0xd7, 0x1b, 0x33, 0x35, 0xdf, 0x36, 0x8c, 0x9a, 0xe9, 0x7e, 0x53, 0x84]; let boundary = [0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3e, 0x9b, 0x6c, 0x69, 0xbc, 0x2c, 0xe2, 0xa2, 0x4a, 0x8e, 0x95, 0x69, 0xef, 0xc7, 0xd7, 0x1b, 0x33, 0x35, 0xdf, 0x36, 0x8c, 0x9a, 0xe9, 0x7e, 0x53, 0x84];
let nonce = 0xd7b3ac70a301a249; let nonce = 0xd7b3ac70a301a249;
// difficulty = 0x085657254bd9u64; // difficulty = 0x085657254bd9u64;
@@ -424,34 +382,3 @@ fn test_light_compute() {
assert_eq!(result.mix_hash[..], mix_hash[..]); assert_eq!(result.mix_hash[..], mix_hash[..]);
assert_eq!(result.value[..], boundary[..]); assert_eq!(result.value[..], boundary[..]);
} }
#[test]
fn test_seed_compute_once() {
let seed_compute = SeedHashCompute::new();
let hash = [241, 175, 44, 134, 39, 121, 245, 239, 228, 236, 43, 160, 195, 152, 46, 7, 199, 5, 253, 147, 241, 206, 98, 43, 3, 104, 17, 40, 192, 79, 106, 162];
assert_eq!(seed_compute.get_seedhash(486382), hash);
}
#[test]
fn test_seed_compute_zero() {
let seed_compute = SeedHashCompute::new();
assert_eq!(seed_compute.get_seedhash(0), [0u8; 32]);
}
#[test]
fn test_seed_compute_after_older() {
let seed_compute = SeedHashCompute::new();
// calculating an older value first shouldn't affect the result
let _ = seed_compute.get_seedhash(50000);
let hash = [241, 175, 44, 134, 39, 121, 245, 239, 228, 236, 43, 160, 195, 152, 46, 7, 199, 5, 253, 147, 241, 206, 98, 43, 3, 104, 17, 40, 192, 79, 106, 162];
assert_eq!(seed_compute.get_seedhash(486382), hash);
}
#[test]
fn test_seed_compute_after_newer() {
let seed_compute = SeedHashCompute::new();
// calculating an newer value first shouldn't affect the result
let _ = seed_compute.get_seedhash(972764);
let hash = [241, 175, 44, 134, 39, 121, 245, 239, 228, 236, 43, 160, 195, 152, 46, 7, 199, 5, 253, 147, 241, 206, 98, 43, 3, 104, 17, 40, 192, 79, 106, 162];
assert_eq!(seed_compute.get_seedhash(486382), hash);
}

View File

@@ -18,18 +18,15 @@
//! See https://github.com/ethereum/wiki/wiki/Ethash //! See https://github.com/ethereum/wiki/wiki/Ethash
extern crate primal; extern crate primal;
extern crate sha3; extern crate sha3;
extern crate parking_lot;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
mod compute; mod compute;
use std::mem; use std::mem;
use compute::Light; use compute::Light;
pub use compute::{ETHASH_EPOCH_LENGTH, H256, ProofOfWork, SeedHashCompute, quick_get_difficulty}; pub use compute::{get_seedhash, quick_get_difficulty, H256, ProofOfWork, ETHASH_EPOCH_LENGTH};
use std::sync::Arc; use std::sync::{Arc, Mutex};
use parking_lot::Mutex;
struct LightCache { struct LightCache {
recent_epoch: Option<u64>, recent_epoch: Option<u64>,
@@ -64,7 +61,7 @@ impl EthashManager {
pub fn compute_light(&self, block_number: u64, header_hash: &H256, nonce: u64) -> ProofOfWork { pub fn compute_light(&self, block_number: u64, header_hash: &H256, nonce: u64) -> ProofOfWork {
let epoch = block_number / ETHASH_EPOCH_LENGTH; let epoch = block_number / ETHASH_EPOCH_LENGTH;
let light = { let light = {
let mut lights = self.cache.lock(); let mut lights = self.cache.lock().unwrap();
let light = match lights.recent_epoch.clone() { let light = match lights.recent_epoch.clone() {
Some(ref e) if *e == epoch => lights.recent.clone(), Some(ref e) if *e == epoch => lights.recent.clone(),
_ => match lights.prev_epoch.clone() { _ => match lights.prev_epoch.clone() {
@@ -79,7 +76,7 @@ impl EthashManager {
lights.recent.clone() lights.recent.clone()
} }
_ => None, _ => None,
}, }
}; };
match light { match light {
None => { None => {
@@ -98,7 +95,7 @@ impl EthashManager {
lights.prev = mem::replace(&mut lights.recent, Some(light.clone())); lights.prev = mem::replace(&mut lights.recent, Some(light.clone()));
light light
} }
Some(light) => light, Some(light) => light
} }
}; };
light.compute(header_hash, nonce) light.compute(header_hash, nonce)
@@ -111,12 +108,12 @@ fn test_lru() {
let hash = [0u8; 32]; let hash = [0u8; 32];
ethash.compute_light(1, &hash, 1); ethash.compute_light(1, &hash, 1);
ethash.compute_light(50000, &hash, 1); ethash.compute_light(50000, &hash, 1);
assert_eq!(ethash.cache.lock().recent_epoch.unwrap(), 1); assert_eq!(ethash.cache.lock().unwrap().recent_epoch.unwrap(), 1);
assert_eq!(ethash.cache.lock().prev_epoch.unwrap(), 0); assert_eq!(ethash.cache.lock().unwrap().prev_epoch.unwrap(), 0);
ethash.compute_light(1, &hash, 1); ethash.compute_light(1, &hash, 1);
assert_eq!(ethash.cache.lock().recent_epoch.unwrap(), 0); assert_eq!(ethash.cache.lock().unwrap().recent_epoch.unwrap(), 0);
assert_eq!(ethash.cache.lock().prev_epoch.unwrap(), 1); assert_eq!(ethash.cache.lock().unwrap().prev_epoch.unwrap(), 1);
ethash.compute_light(70000, &hash, 1); ethash.compute_light(70000, &hash, 1);
assert_eq!(ethash.cache.lock().recent_epoch.unwrap(), 2); assert_eq!(ethash.cache.lock().unwrap().recent_epoch.unwrap(), 2);
assert_eq!(ethash.cache.lock().prev_epoch.unwrap(), 0); assert_eq!(ethash.cache.lock().unwrap().prev_epoch.unwrap(), 0);
} }

View File

@@ -3,12 +3,8 @@ description = "Ethcore library"
homepage = "http://ethcore.io" homepage = "http://ethcore.io"
license = "GPL-3.0" license = "GPL-3.0"
name = "ethcore" name = "ethcore"
version = "1.3.0" version = "1.0.2"
authors = ["Ethcore <admin@ethcore.io>"] authors = ["Ethcore <admin@ethcore.io>"]
build = "build.rs"
[build-dependencies]
"ethcore-ipc-codegen" = { path = "../ipc/codegen" }
[dependencies] [dependencies]
log = "0.3" log = "0.3"
@@ -16,32 +12,16 @@ env_logger = "0.3"
rustc-serialize = "0.3" rustc-serialize = "0.3"
heapsize = "0.3" heapsize = "0.3"
rust-crypto = "0.2.34" rust-crypto = "0.2.34"
num_cpus = "0.2"
crossbeam = "0.2.9"
lazy_static = "0.2"
bloomchain = "0.1"
rayon = "0.4"
semver = "0.2"
bit-set = "0.4"
time = "0.1" time = "0.1"
evmjit = { path = "../evmjit", optional = true }
clippy = { version = "0.0.80", optional = true}
ethash = { path = "../ethash" }
ethcore-util = { path = "../util" } ethcore-util = { path = "../util" }
ethcore-io = { path = "../util/io" } evmjit = { path = "../evmjit", optional = true }
ethash = { path = "../ethash" }
num_cpus = "0.2"
clippy = { version = "0.0.54", optional = true }
crossbeam = "0.1.5"
lazy_static = "0.1"
ethcore-devtools = { path = "../devtools" } ethcore-devtools = { path = "../devtools" }
ethjson = { path = "../json" } ethjson = { path = "../json" }
ethcore-ipc = { path = "../ipc/rpc" }
ethstore = { path = "../ethstore" }
ethcore-ipc-nano = { path = "../ipc/nano" }
rand = "0.3"
lru-cache = "0.0.7"
bloomfilter = { git = "https://github.com/ethcore/rust-bloom-filter" }
byteorder = "0.5"
[dependencies.hyper]
git = "https://github.com/ethcore/hyper"
default-features = false
[features] [features]
jit = ["evmjit"] jit = ["evmjit"]
@@ -50,5 +30,3 @@ json-tests = []
test-heavy = [] test-heavy = []
dev = ["clippy"] dev = ["clippy"]
default = [] default = []
benches = []
ipc = []

View File

@@ -1,23 +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/>.
extern crate ethcore_ipc_codegen;
fn main() {
ethcore_ipc_codegen::derive_binary("src/types/mod.rs.in").unwrap();
ethcore_ipc_codegen::derive_ipc_cond("src/client/traits.rs", cfg!(feature="ipc")).unwrap();
ethcore_ipc_codegen::derive_ipc_cond("src/client/chain_notify.rs", cfg!(feature="ipc")).unwrap();
}

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@@ -1,160 +1,24 @@
{ {
"name": "Frontier/Homestead", "name": "Frontier/Homestead",
"engine": { "engineName": "Ethash",
"Ethash": {
"params": {
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"homesteadTransition": "0x118c30",
"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"
],
"eip150Transition": "0x259518",
"eip155Transition": "0x28d138",
"eip160Transition": "0x28d138",
"eip161abcTransition": "0x28d138",
"eip161dTransition": "0x28d138",
"maxCodeSize": 24576
}
}
},
"params": { "params": {
"accountStartNonce": "0x00", "accountStartNonce": "0x00",
"frontierCompatibilityModeLimit": "0x118c30",
"maximumExtraDataSize": "0x20", "maximumExtraDataSize": "0x20",
"tieBreakingGas": false,
"minGasLimit": "0x1388", "minGasLimit": "0x1388",
"networkID" : "0x1", "gasLimitBoundDivisor": "0x0400",
"forkBlock": "0x1d4c00", "minimumDifficulty": "0x020000",
"forkCanonHash": "0x4985f5ca3d2afbec36529aa96f74de3cc10a2a4a6c44f2157a57d2c6059a11bb" "difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"networkID" : "0x1"
}, },
"genesis": { "genesis": {
"seal": { "nonce": "0x0000000000000042",
"ethereum": {
"nonce": "0x0000000000000042",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x400000000", "difficulty": "0x400000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"author": "0x0000000000000000000000000000000000000000", "author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00", "timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
@@ -166,7 +30,7 @@
"enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303", "enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303",
"enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303", "enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303",
"enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303", "enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303",
"enode://4cd540b2c3292e17cff39922e864094bf8b0741fcc8c5dcea14957e389d7944c70278d872902e3d0345927f621547efa659013c400865485ab4bfa0c6596936f@138.201.144.135:30303" "enode://248f12bc8b18d5289358085520ac78cd8076485211e6d96ab0bc93d6cd25442db0ce3a937dc404f64f207b0b9aed50e25e98ce32af5ac7cb321ff285b97de485@zero.parity.io:30303"
], ],
"accounts": { "accounts": {
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },

View File

@@ -1,157 +1,24 @@
{ {
"name": "Frontier (Test)", "name": "Frontier (Test)",
"engine": { "engineName": "Ethash",
"Ethash": {
"params": {
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"homesteadTransition": "0x118c30",
"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"
],
"eip150Transition": "0x7fffffffffffffff",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
}
}
},
"params": { "params": {
"accountStartNonce": "0x00", "accountStartNonce": "0x00",
"frontierCompatibilityModeLimit": "0x118c30",
"maximumExtraDataSize": "0x20", "maximumExtraDataSize": "0x20",
"tieBreakingGas": false,
"minGasLimit": "0x1388", "minGasLimit": "0x1388",
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"networkID" : "0x1" "networkID" : "0x1"
}, },
"genesis": { "genesis": {
"seal": { "nonce": "0x0000000000000042",
"ethereum": {
"nonce": "0x0000000000000042",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x400000000", "difficulty": "0x400000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"author": "0x0000000000000000000000000000000000000000", "author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00", "timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",

View File

@@ -1,37 +1,24 @@
{ {
"name": "Frontier (Test)", "name": "Frontier (Test)",
"engine": { "engineName": "Ethash",
"Ethash": {
"params": {
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"homesteadTransition": "0x7fffffffffffffff",
"eip150Transition": "0x7fffffffffffffff",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
}
}
},
"params": { "params": {
"accountStartNonce": "0x00", "accountStartNonce": "0x00",
"frontierCompatibilityModeLimit": "0xffffffffffffffff",
"maximumExtraDataSize": "0x20", "maximumExtraDataSize": "0x20",
"tieBreakingGas": false,
"minGasLimit": "0x1388", "minGasLimit": "0x1388",
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"networkID" : "0x1" "networkID" : "0x1"
}, },
"genesis": { "genesis": {
"seal": { "nonce": "0x0000000000000042",
"ethereum": {
"nonce": "0x0000000000000042",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x400000000", "difficulty": "0x400000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"author": "0x0000000000000000000000000000000000000000", "author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00", "timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",

View File

@@ -1,37 +1,24 @@
{ {
"name": "Homestead (Test)", "name": "Homestead (Test)",
"engine": { "engineName": "Ethash",
"Ethash": {
"params": {
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"homesteadTransition": "0x0",
"eip150Transition": "0x7fffffffffffffff",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
}
}
},
"params": { "params": {
"accountStartNonce": "0x00", "accountStartNonce": "0x00",
"frontierCompatibilityModeLimit": 0,
"maximumExtraDataSize": "0x20", "maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388", "minGasLimit": "0x1388",
"tieBreakingGas": false,
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"networkID" : "0x1" "networkID" : "0x1"
}, },
"genesis": { "genesis": {
"seal": { "nonce": "0x0000000000000042",
"ethereum": {
"nonce": "0x0000000000000042",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x400000000", "difficulty": "0x400000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"author": "0x0000000000000000000000000000000000000000", "author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00", "timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",

View File

@@ -1,39 +1,24 @@
{ {
"name": "Morden", "name": "Morden",
"engine": { "engineName": "Ethash",
"Ethash": {
"params": {
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar": "0x8e4e9b13d4b45cb0befc93c3061b1408f67316b2",
"homesteadTransition": "0x789b0",
"eip150Transition": "0x1b34d8",
"eip155Transition": "0x1cc348",
"eip160Transition": "0x1cc348",
"eip161abcTransition": "0x1cc348",
"eip161dTransition": "0x1cc348"
}
}
},
"params": { "params": {
"accountStartNonce": "0x0100000", "accountStartNonce": "0x0100000",
"frontierCompatibilityModeLimit": "0x789b0",
"maximumExtraDataSize": "0x20", "maximumExtraDataSize": "0x20",
"tieBreakingGas": false,
"minGasLimit": "0x1388", "minGasLimit": "0x1388",
"networkID" : "0x2", "gasLimitBoundDivisor": "0x0400",
"forkBlock": "0x1b34d8", "minimumDifficulty": "0x020000",
"forkCanonHash": "0xf376243aeff1f256d970714c3de9fd78fa4e63cf63e32a51fe1169e375d98145" "difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar": "",
"networkID" : "0x2"
}, },
"genesis": { "genesis": {
"seal": { "nonce": "0x00006d6f7264656e",
"ethereum": {
"nonce": "0x00006d6f7264656e",
"mixHash": "0x00000000000000000000000000000000000000647572616c65787365646c6578"
}
},
"difficulty": "0x20000", "difficulty": "0x20000",
"mixHash": "0x00000000000000000000000000000000000000647572616c65787365646c6578",
"author": "0x0000000000000000000000000000000000000000", "author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00", "timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
@@ -41,8 +26,7 @@
"gasLimit": "0x2fefd8" "gasLimit": "0x2fefd8"
}, },
"nodes": [ "nodes": [
"enode://e731347db0521f3476e6bbbb83375dcd7133a1601425ebd15fd10f3835fd4c304fba6282087ca5a0deeafadf0aa0d4fd56c3323331901c1f38bd181c283e3e35@128.199.55.137:30303", "enode://b1217cbaa440e35ed471157123fe468e19e8b5ad5bedb4b1fdbcbdab6fb2f5ed3e95dd9c24a22a79fdb2352204cea207df27d92bfd21bfd41545e8b16f637499@104.44.138.37:30303"
"enode://ceb5c0f85eb994dbe9693bf46d99b03f6b838d17cc74e68d5eb003171ff39e5f120b17f965b267c319303f94d80b9d994b77062fb1486d76ce95d9f3d8fe1cb4@46.101.122.141:30303"
], ],
"accounts": { "accounts": {
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },

View File

@@ -1,37 +1,24 @@
{ {
"name": "Olympic", "name": "Olympic",
"engine": { "engineName": "Ethash",
"Ethash": {
"params": {
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x08",
"blockReward": "0x14D1120D7B160000",
"registrar": "5e70c0bbcd5636e0f9f9316e9f8633feb64d4050",
"homesteadTransition": "0x7fffffffffffffff",
"eip150Transition": "0x7fffffffffffffff",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
}
}
},
"params": { "params": {
"accountStartNonce": "0x00", "accountStartNonce": "0x00",
"frontierCompatibilityModeLimit": "0xffffffffffffffff",
"maximumExtraDataSize": "0x0400", "maximumExtraDataSize": "0x0400",
"tieBreakingGas": false,
"minGasLimit": "125000", "minGasLimit": "125000",
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x08",
"blockReward": "0x14D1120D7B160000",
"registrar": "5e70c0bbcd5636e0f9f9316e9f8633feb64d4050",
"networkID" : "0x0" "networkID" : "0x0"
}, },
"genesis": { "genesis": {
"seal": { "nonce": "0x000000000000002a",
"ethereum": {
"nonce": "0x000000000000002a",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x20000", "difficulty": "0x20000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"author": "0x0000000000000000000000000000000000000000", "author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00", "timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",

View File

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

View File

@@ -1,167 +0,0 @@
{
"name": "EIP150.1b hard-fork consensus test",
"engine": {
"Ethash": {
"params": {
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"homesteadTransition": "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"
],
"eip150Transition": "0xa",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
}
}
},
"params": {
"accountStartNonce": "0x00",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x1"
},
"genesis": {
"seal": {
"ethereum": {
"nonce": "0x0000000000000042",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x400000000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"gasLimit": "0x1388"
},
"accounts": {
"0000000000000000000000000000000000000001": { "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

@@ -1,33 +0,0 @@
{
"name": "TestInstantSeal",
"engine": {
"InstantSeal": null
},
"params": {
"accountStartNonce": "0x0100000",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x2"
},
"genesis": {
"seal": {
"ethereum": {
"nonce": "0x00006d6f7264656e",
"mixHash": "0x00000000000000000000000000000000000000647572616c65787365646c6578"
}
},
"difficulty": "0x20000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",
"gasLimit": "0x2fefd8"
},
"accounts": {
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
"102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" }
}
}

View File

@@ -1,33 +0,0 @@
{
"name": "Morden",
"engine": {
"Null": null
},
"params": {
"accountStartNonce": "0x0",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x2"
},
"genesis": {
"seal": {
"ethereum": {
"nonce": "0x00006d6f7264656e",
"mixHash": "0x00000000000000000000000000000000000000647572616c65787365646c6578"
}
},
"difficulty": "0x20000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",
"gasLimit": "0x2fefd8"
},
"accounts": {
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "0", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0000000000000000000000000000000000000002": { "balance": "1", "nonce": "0", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0000000000000000000000000000000000000003": { "balance": "1", "nonce": "0", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0000000000000000000000000000000000000004": { "balance": "1", "nonce": "0", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
"9cce34f7ab185c7aba1b7c8140d620b4bda941d6": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "0" }
}
}

View File

@@ -1,22 +1,24 @@
{ {
"name": "Morden", "name": "Morden",
"engine": { "engineName": "NullEngine",
"Null": null
},
"params": { "params": {
"accountStartNonce": "0x0", "accountStartNonce": "0x0100000",
"frontierCompatibilityModeLimit": "0xfffa2990",
"maximumExtraDataSize": "0x20", "maximumExtraDataSize": "0x20",
"tieBreakingGas": false,
"minGasLimit": "0x1388", "minGasLimit": "0x1388",
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar": "",
"networkID" : "0x2" "networkID" : "0x2"
}, },
"genesis": { "genesis": {
"seal": { "nonce": "0x00006d6f7264656e",
"ethereum": {
"nonce": "0x00006d6f7264656e",
"mixHash": "0x00000000000000000000000000000000000000647572616c65787365646c6578"
}
},
"difficulty": "0x20000", "difficulty": "0x20000",
"mixHash": "0x00000000000000000000000000000000000000647572616c65787365646c6578",
"author": "0x0000000000000000000000000000000000000000", "author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00", "timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",

View File

@@ -1,39 +0,0 @@
{
"name": "TestAuthority",
"engine": {
"BasicAuthority": {
"params": {
"gasLimitBoundDivisor": "0x0400",
"durationLimit": "0x0d",
"authorities" : ["0x9cce34f7ab185c7aba1b7c8140d620b4bda941d6"]
}
}
},
"params": {
"accountStartNonce": "0x0100000",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x69"
},
"genesis": {
"seal": {
"generic": {
"fields": 1,
"rlp": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"
}
},
"difficulty": "0x20000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",
"gasLimit": "0x2fefd8"
},
"accounts": {
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
"9cce34f7ab185c7aba1b7c8140d620b4bda941d6": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" }
}
}

View File

@@ -19,15 +19,9 @@
use util::*; use util::*;
use pod_account::*; use pod_account::*;
use account_db::*; use account_db::*;
use lru_cache::LruCache;
use std::cell::{RefCell, Cell};
const STORAGE_CACHE_ITEMS: usize = 8192;
/// Single account in the system. /// Single account in the system.
/// Keeps track of changes to the code and storage. #[derive(Clone)]
/// The changes are applied in `commit_storage` and `commit_code`
pub struct Account { pub struct Account {
// Balance of the account. // Balance of the account.
balance: U256, balance: U256,
@@ -35,22 +29,12 @@ pub struct Account {
nonce: U256, nonce: U256,
// Trie-backed storage. // Trie-backed storage.
storage_root: H256, storage_root: H256,
// LRU Cache of the trie-backed storage. // Overlay on trie-backed storage - tuple is (<clean>, <value>).
// This is limited to `STORAGE_CACHE_ITEMS` recent queries storage_overlay: RefCell<HashMap<H256, (Filth, H256)>>,
storage_cache: RefCell<LruCache<H256, H256>>, // Code hash of the account. If None, means that it's a contract whose code has not yet been set.
// Modified storage. Accumulates changes to storage made in `set_storage` code_hash: Option<H256>,
// Takes precedence over `storage_cache`.
storage_changes: HashMap<H256, H256>,
// Code hash of the account.
code_hash: H256,
// Size of the accoun code.
code_size: Option<u64>,
// Code cache of the account. // Code cache of the account.
code_cache: Arc<Bytes>, code_cache: Bytes,
// Account code new or has been modified.
code_filth: Filth,
// Cached address hash.
address_hash: Cell<Option<H256>>,
} }
impl Account { impl Account {
@@ -61,33 +45,23 @@ impl Account {
balance: balance, balance: balance,
nonce: nonce, nonce: nonce,
storage_root: SHA3_NULL_RLP, storage_root: SHA3_NULL_RLP,
storage_cache: Self::empty_storage_cache(), storage_overlay: RefCell::new(storage.into_iter().map(|(k, v)| (k, (Filth::Dirty, v))).collect()),
storage_changes: storage, code_hash: Some(code.sha3()),
code_hash: code.sha3(), code_cache: code
code_size: Some(code.len() as u64),
code_cache: Arc::new(code),
code_filth: Filth::Dirty,
address_hash: Cell::new(None),
} }
} }
fn empty_storage_cache() -> RefCell<LruCache<H256, H256>> { #[cfg(test)]
RefCell::new(LruCache::new(STORAGE_CACHE_ITEMS)) #[cfg(feature = "json-tests")]
}
/// General constructor. /// General constructor.
pub fn from_pod(pod: PodAccount) -> Account { pub fn from_pod(pod: PodAccount) -> Account {
Account { Account {
balance: pod.balance, balance: pod.balance,
nonce: pod.nonce, nonce: pod.nonce,
storage_root: SHA3_NULL_RLP, storage_root: SHA3_NULL_RLP,
storage_cache: Self::empty_storage_cache(), storage_overlay: RefCell::new(pod.storage.into_iter().map(|(k, v)| (k, (Filth::Dirty, v))).collect()),
storage_changes: pod.storage.into_iter().collect(), code_hash: Some(pod.code.sha3()),
code_hash: pod.code.as_ref().map_or(SHA3_EMPTY, |c| c.sha3()), code_cache: pod.code
code_filth: Filth::Dirty,
code_size: Some(pod.code.as_ref().map_or(0, |c| c.len() as u64)),
code_cache: Arc::new(pod.code.map_or_else(|| { warn!("POD account with unknown code is being created! Assuming no code."); vec![] }, |c| c)),
address_hash: Cell::new(None),
} }
} }
@@ -97,13 +71,9 @@ impl Account {
balance: balance, balance: balance,
nonce: nonce, nonce: nonce,
storage_root: SHA3_NULL_RLP, storage_root: SHA3_NULL_RLP,
storage_cache: Self::empty_storage_cache(), storage_overlay: RefCell::new(HashMap::new()),
storage_changes: HashMap::new(), code_hash: Some(SHA3_EMPTY),
code_hash: SHA3_EMPTY, code_cache: vec![],
code_cache: Arc::new(vec![]),
code_size: Some(0),
code_filth: Filth::Clean,
address_hash: Cell::new(None),
} }
} }
@@ -114,13 +84,9 @@ impl Account {
nonce: r.val_at(0), nonce: r.val_at(0),
balance: r.val_at(1), balance: r.val_at(1),
storage_root: r.val_at(2), storage_root: r.val_at(2),
storage_cache: Self::empty_storage_cache(), storage_overlay: RefCell::new(HashMap::new()),
storage_changes: HashMap::new(), code_hash: Some(r.val_at(3)),
code_hash: r.val_at(3), code_cache: vec![],
code_cache: Arc::new(vec![]),
code_size: None,
code_filth: Filth::Clean,
address_hash: Cell::new(None),
} }
} }
@@ -131,65 +97,29 @@ impl Account {
balance: balance, balance: balance,
nonce: nonce, nonce: nonce,
storage_root: SHA3_NULL_RLP, storage_root: SHA3_NULL_RLP,
storage_cache: Self::empty_storage_cache(), storage_overlay: RefCell::new(HashMap::new()),
storage_changes: HashMap::new(), code_hash: None,
code_hash: SHA3_EMPTY, code_cache: vec![],
code_cache: Arc::new(vec![]),
code_size: None,
code_filth: Filth::Clean,
address_hash: Cell::new(None),
} }
} }
/// Set this account's code to the given code. /// Set this account's code to the given code.
/// NOTE: Account should have been created with `new_contract()` /// NOTE: Account should have been created with `new_contract()`
pub fn init_code(&mut self, code: Bytes) { pub fn init_code(&mut self, code: Bytes) {
self.code_hash = code.sha3(); assert!(self.code_hash.is_none());
self.code_cache = Arc::new(code); self.code_cache = code;
self.code_size = Some(self.code_cache.len() as u64);
self.code_filth = Filth::Dirty;
}
/// Reset this account's code to the given code.
pub fn reset_code(&mut self, code: Bytes) {
self.init_code(code);
} }
/// Set (and cache) the contents of the trie's storage at `key` to `value`. /// Set (and cache) the contents of the trie's storage at `key` to `value`.
pub fn set_storage(&mut self, key: H256, value: H256) { pub fn set_storage(&mut self, key: H256, value: H256) {
self.storage_changes.insert(key, value); self.storage_overlay.borrow_mut().insert(key, (Filth::Dirty, value));
} }
/// Get (and cache) the contents of the trie's storage at `key`. /// Get (and cache) the contents of the trie's storage at `key`.
/// Takes modifed storage into account.
pub fn storage_at(&self, db: &AccountDB, key: &H256) -> H256 { pub fn storage_at(&self, db: &AccountDB, key: &H256) -> H256 {
if let Some(value) = self.cached_storage_at(key) { self.storage_overlay.borrow_mut().entry(key.clone()).or_insert_with(||{
return value; (Filth::Clean, H256::from(SecTrieDB::new(db, &self.storage_root).get(key.bytes()).map_or(U256::zero(), |v| -> U256 {decode(v)})))
} }).1.clone()
let db = SecTrieDB::new(db, &self.storage_root)
.expect("Account storage_root initially set to zero (valid) and only altered by SecTrieDBMut. \
SecTrieDBMut would not set it to an invalid state root. Therefore the root is valid and DB creation \
using it will not fail.");
let item: U256 = match db.get(key){
Ok(x) => x.map_or_else(U256::zero, decode),
Err(e) => panic!("Encountered potential DB corruption: {}", e),
};
let value: H256 = item.into();
self.storage_cache.borrow_mut().insert(key.clone(), value.clone());
value
}
/// Get cached storage value if any. Returns `None` if the
/// key is not in the cache.
pub fn cached_storage_at(&self, key: &H256) -> Option<H256> {
if let Some(value) = self.storage_changes.get(key) {
return Some(value.clone())
}
if let Some(value) = self.storage_cache.borrow_mut().get_mut(key) {
return Some(value.clone())
}
None
} }
/// return the balance associated with this account. /// return the balance associated with this account.
@@ -198,168 +128,105 @@ impl Account {
/// return the nonce associated with this account. /// return the nonce associated with this account.
pub fn nonce(&self) -> &U256 { &self.nonce } pub fn nonce(&self) -> &U256 { &self.nonce }
#[cfg(test)]
/// return the code hash associated with this account. /// return the code hash associated with this account.
pub fn code_hash(&self) -> H256 { pub fn code_hash(&self) -> H256 {
self.code_hash.clone() self.code_hash.clone().unwrap_or(SHA3_EMPTY)
}
/// return the code hash associated with this account.
pub fn address_hash(&self, address: &Address) -> H256 {
let hash = self.address_hash.get();
hash.unwrap_or_else(|| {
let hash = address.sha3();
self.address_hash.set(Some(hash.clone()));
hash
})
} }
/// returns the account's code. If `None` then the code cache isn't available - /// returns the account's code. If `None` then the code cache isn't available -
/// get someone who knows to call `note_code`. /// get someone who knows to call `note_code`.
pub fn code(&self) -> Option<Arc<Bytes>> { pub fn code(&self) -> Option<&[u8]> {
if self.code_hash != SHA3_EMPTY && self.code_cache.is_empty() { match self.code_hash {
return None; Some(c) if c == SHA3_EMPTY && self.code_cache.is_empty() => Some(&self.code_cache),
Some(_) if !self.code_cache.is_empty() => Some(&self.code_cache),
None => Some(&self.code_cache),
_ => None,
} }
Some(self.code_cache.clone())
}
/// returns the account's code size. If `None` then the code cache or code size cache isn't available -
/// get someone who knows to call `note_code`.
pub fn code_size(&self) -> Option<u64> {
self.code_size.clone()
} }
#[cfg(test)] #[cfg(test)]
/// Provide a byte array which hashes to the `code_hash`. returns the hash as a result. /// Provide a byte array which hashes to the `code_hash`. returns the hash as a result.
pub fn note_code(&mut self, code: Bytes) -> Result<(), H256> { pub fn note_code(&mut self, code: Bytes) -> Result<(), H256> {
let h = code.sha3(); let h = code.sha3();
if self.code_hash == h { match self.code_hash {
self.code_cache = Arc::new(code); Some(ref i) if h == *i => {
self.code_size = Some(self.code_cache.len() as u64); self.code_cache = code;
Ok(()) Ok(())
} else { },
Err(h) _ => Err(h)
} }
} }
/// Is `code_cache` valid; such that code is going to return Some? /// Is `code_cache` valid; such that code is going to return Some?
pub fn is_cached(&self) -> bool { pub fn is_cached(&self) -> bool {
!self.code_cache.is_empty() || (self.code_cache.is_empty() && self.code_hash == SHA3_EMPTY) !self.code_cache.is_empty() || (self.code_cache.is_empty() && self.code_hash == Some(SHA3_EMPTY))
} }
/// Provide a database to get `code_hash`. Should not be called if it is a contract without code. /// Provide a database to lookup `code_hash`. Should not be called if it is a contract without code.
pub fn cache_code(&mut self, db: &AccountDB) -> bool { pub fn cache_code(&mut self, db: &AccountDB) -> bool {
// TODO: fill out self.code_cache; // TODO: fill out self.code_cache;
trace!("Account::cache_code: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty()); trace!("Account::cache_code: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty());
self.is_cached() || self.is_cached() ||
match db.get(&self.code_hash) { match self.code_hash {
Some(x) => { Some(ref h) => match db.lookup(h) {
self.code_cache = Arc::new(x.to_vec()); Some(x) => { self.code_cache = x.to_vec(); true },
self.code_size = Some(x.len() as u64);
true
},
_ => {
warn!("Failed reverse get of {}", self.code_hash);
false
},
}
}
/// Provide a database to get `code_size`. Should not be called if it is a contract without code.
pub fn cache_code_size(&mut self, db: &AccountDB) -> bool {
// TODO: fill out self.code_cache;
trace!("Account::cache_code_size: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty());
self.code_size.is_some() ||
if self.code_hash != SHA3_EMPTY {
match db.get(&self.code_hash) {
Some(x) => {
self.code_size = Some(x.len() as u64);
true
},
_ => { _ => {
warn!("Failed reverse get of {}", self.code_hash); warn!("Failed reverse lookup of {}", h);
false false
}, },
} },
} else { _ => false,
false
} }
} }
#[cfg(test)]
/// Determine whether there are any un-`commit()`-ed storage-setting operations. /// Determine whether there are any un-`commit()`-ed storage-setting operations.
pub fn storage_is_clean(&self) -> bool { self.storage_changes.is_empty() } pub fn storage_is_clean(&self) -> bool { self.storage_overlay.borrow().iter().find(|&(_, &(f, _))| f == Filth::Dirty).is_none() }
/// Check if account has zero nonce, balance, no code and no storage.
///
/// NOTE: Will panic if `!self.storage_is_clean()`
pub fn is_empty(&self) -> bool {
assert!(self.storage_is_clean(), "Account::is_empty() may only legally be called when storage is clean.");
self.is_null() && self.storage_root == SHA3_NULL_RLP
}
/// Check if account has zero nonce, balance, no code.
pub fn is_null(&self) -> bool {
self.balance.is_zero() &&
self.nonce.is_zero() &&
self.code_hash == SHA3_EMPTY
}
#[cfg(test)] #[cfg(test)]
/// return the storage root associated with this account or None if it has been altered via the overlay. /// return the storage root associated with this account or None if it has been altered via the overlay.
pub fn storage_root(&self) -> Option<&H256> { if self.storage_is_clean() {Some(&self.storage_root)} else {None} } pub fn storage_root(&self) -> Option<&H256> { if self.storage_is_clean() {Some(&self.storage_root)} else {None} }
/// return the storage overlay. /// return the storage overlay.
pub fn storage_changes(&self) -> &HashMap<H256, H256> { &self.storage_changes } pub fn storage_overlay(&self) -> Ref<HashMap<H256, (Filth, H256)>> { self.storage_overlay.borrow() }
/// Increment the nonce of the account by one. /// Increment the nonce of the account by one.
pub fn inc_nonce(&mut self) { pub fn inc_nonce(&mut self) { self.nonce = self.nonce + U256::from(1u8); }
self.nonce = self.nonce + U256::from(1u8);
}
/// Increase account balance. /// Increment the nonce of the account by one.
pub fn add_balance(&mut self, x: &U256) { pub fn add_balance(&mut self, x: &U256) { self.balance = self.balance + *x; }
self.balance = self.balance + *x;
}
/// Decrease account balance. /// Increment the nonce of the account by one.
/// Panics if balance is less than `x` /// Panics if balance is less than `x`
pub fn sub_balance(&mut self, x: &U256) { pub fn sub_balance(&mut self, x: &U256) {
assert!(self.balance >= *x); assert!(self.balance >= *x);
self.balance = self.balance - *x; self.balance = self.balance - *x;
} }
/// Commit the `storage_changes` to the backing DB and update `storage_root`. /// Commit the `storage_overlay` to the backing DB and update `storage_root`.
pub fn commit_storage(&mut self, trie_factory: &TrieFactory, db: &mut AccountDBMut) { pub fn commit_storage(&mut self, db: &mut AccountDBMut) {
let mut t = trie_factory.from_existing(db, &mut self.storage_root) let mut t = SecTrieDBMut::from_existing(db, &mut self.storage_root);
.expect("Account storage_root initially set to zero (valid) and only altered by SecTrieDBMut. \ for (k, &mut (ref mut f, ref mut v)) in self.storage_overlay.borrow_mut().iter_mut() {
SecTrieDBMut would not set it to an invalid state root. Therefore the root is valid and DB creation \ if f == &Filth::Dirty {
using it will not fail."); // cast key and value to trait type,
for (k, v) in self.storage_changes.drain() { // so we can call overloaded `to_bytes` method
// cast key and value to trait type, match v.is_zero() {
// so we can call overloaded `to_bytes` method true => { t.remove(k); },
let res = match v.is_zero() { false => { t.insert(k, &encode(&U256::from(v.as_slice()))); },
true => t.remove(k.as_slice()), }
false => t.insert(k.as_slice(), &encode(&U256::from(v.as_slice()))), *f = Filth::Clean;
};
if let Err(e) = res {
warn!("Encountered potential DB corruption: {}", e);
} }
self.storage_cache.borrow_mut().insert(k, v);
} }
} }
/// Commit any unsaved code. `code_hash` will always return the hash of the `code_cache` after this. /// Commit any unsaved code. `code_hash` will always return the hash of the `code_cache` after this.
pub fn commit_code(&mut self, db: &mut AccountDBMut) { pub fn commit_code(&mut self, db: &mut AccountDBMut) {
trace!("Commiting code of {:?} - {:?}, {:?}", self, self.code_filth == Filth::Dirty, self.code_cache.is_empty()); trace!("Commiting code of {:?} - {:?}, {:?}", self, self.code_hash.is_none(), self.code_cache.is_empty());
match (self.code_filth == Filth::Dirty, self.code_cache.is_empty()) { match (self.code_hash.is_none(), self.code_cache.is_empty()) {
(true, true) => { (true, true) => self.code_hash = Some(SHA3_EMPTY),
self.code_size = Some(0);
self.code_filth = Filth::Clean;
},
(true, false) => { (true, false) => {
db.emplace(self.code_hash.clone(), (*self.code_cache).clone()); self.code_hash = Some(db.insert(&self.code_cache));
self.code_size = Some(self.code_cache.len() as u64);
self.code_filth = Filth::Clean;
}, },
(false, _) => {}, (false, _) => {},
} }
@@ -371,59 +238,9 @@ impl Account {
stream.append(&self.nonce); stream.append(&self.nonce);
stream.append(&self.balance); stream.append(&self.balance);
stream.append(&self.storage_root); stream.append(&self.storage_root);
stream.append(&self.code_hash); stream.append(self.code_hash.as_ref().expect("Cannot form RLP of contract account without code."));
stream.out() stream.out()
} }
/// Clone basic account data
pub fn clone_basic(&self) -> Account {
Account {
balance: self.balance.clone(),
nonce: self.nonce.clone(),
storage_root: self.storage_root.clone(),
storage_cache: Self::empty_storage_cache(),
storage_changes: HashMap::new(),
code_hash: self.code_hash.clone(),
code_size: self.code_size.clone(),
code_cache: self.code_cache.clone(),
code_filth: self.code_filth,
address_hash: self.address_hash.clone(),
}
}
/// Clone account data and dirty storage keys
pub fn clone_dirty(&self) -> Account {
let mut account = self.clone_basic();
account.storage_changes = self.storage_changes.clone();
account.code_cache = self.code_cache.clone();
account
}
/// Clone account data, dirty storage keys and cached storage keys.
pub fn clone_all(&self) -> Account {
let mut account = self.clone_dirty();
account.storage_cache = self.storage_cache.clone();
account
}
/// Replace self with the data from other account merging storage cache.
/// Basic account data and all modifications are overwritten
/// with new values.
pub fn overwrite_with(&mut self, other: Account) {
self.balance = other.balance;
self.nonce = other.nonce;
self.storage_root = other.storage_root;
self.code_hash = other.code_hash;
self.code_filth = other.code_filth;
self.code_cache = other.code_cache;
self.code_size = other.code_size;
self.address_hash = other.address_hash;
let mut cache = self.storage_cache.borrow_mut();
for (k, v) in other.storage_cache.into_inner().into_iter() {
cache.insert(k.clone() , v.clone()); //TODO: cloning should not be required here
}
self.storage_changes = other.storage_changes;
}
} }
impl fmt::Debug for Account { impl fmt::Debug for Account {
@@ -439,24 +256,14 @@ mod tests {
use super::*; use super::*;
use account_db::*; use account_db::*;
#[test]
fn account_compress() {
let raw = Account::new_basic(2.into(), 4.into()).rlp();
let rlp = UntrustedRlp::new(&raw);
let compact_vec = rlp.compress(RlpType::Snapshot).to_vec();
assert!(raw.len() > compact_vec.len());
let again_raw = UntrustedRlp::new(&compact_vec).decompress(RlpType::Snapshot);
assert_eq!(raw, again_raw.to_vec());
}
#[test] #[test]
fn storage_at() { fn storage_at() {
let mut db = MemoryDB::new(); let mut db = MemoryDB::new();
let mut db = AccountDBMut::new(&mut db, &Address::new()); let mut db = AccountDBMut::new(&mut db, &Address::new());
let rlp = { let rlp = {
let mut a = Account::new_contract(69.into(), 0.into()); let mut a = Account::new_contract(x!(69), x!(0));
a.set_storage(H256::from(&U256::from(0x00u64)), H256::from(&U256::from(0x1234u64))); a.set_storage(H256::from(&U256::from(0x00u64)), H256::from(&U256::from(0x1234u64)));
a.commit_storage(&Default::default(), &mut db); a.commit_storage(&mut db);
a.init_code(vec![]); a.init_code(vec![]);
a.commit_code(&mut db); a.commit_code(&mut db);
a.rlp() a.rlp()
@@ -474,7 +281,7 @@ mod tests {
let mut db = AccountDBMut::new(&mut db, &Address::new()); let mut db = AccountDBMut::new(&mut db, &Address::new());
let rlp = { let rlp = {
let mut a = Account::new_contract(69.into(), 0.into()); let mut a = Account::new_contract(x!(69), x!(0));
a.init_code(vec![0x55, 0x44, 0xffu8]); a.init_code(vec![0x55, 0x44, 0xffu8]);
a.commit_code(&mut db); a.commit_code(&mut db);
a.rlp() a.rlp()
@@ -489,57 +296,40 @@ mod tests {
#[test] #[test]
fn commit_storage() { fn commit_storage() {
let mut a = Account::new_contract(69.into(), 0.into()); let mut a = Account::new_contract(x!(69), x!(0));
let mut db = MemoryDB::new(); let mut db = MemoryDB::new();
let mut db = AccountDBMut::new(&mut db, &Address::new()); let mut db = AccountDBMut::new(&mut db, &Address::new());
a.set_storage(0.into(), 0x1234.into()); a.set_storage(x!(0), x!(0x1234));
assert_eq!(a.storage_root(), None); assert_eq!(a.storage_root(), None);
a.commit_storage(&Default::default(), &mut db); a.commit_storage(&mut db);
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2"); assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
} }
#[test] #[test]
fn commit_remove_commit_storage() { fn commit_remove_commit_storage() {
let mut a = Account::new_contract(69.into(), 0.into()); let mut a = Account::new_contract(x!(69), x!(0));
let mut db = MemoryDB::new(); let mut db = MemoryDB::new();
let mut db = AccountDBMut::new(&mut db, &Address::new()); let mut db = AccountDBMut::new(&mut db, &Address::new());
a.set_storage(0.into(), 0x1234.into()); a.set_storage(x!(0), x!(0x1234));
a.commit_storage(&Default::default(), &mut db); a.commit_storage(&mut db);
a.set_storage(1.into(), 0x1234.into()); a.set_storage(x!(1), x!(0x1234));
a.commit_storage(&Default::default(), &mut db); a.commit_storage(&mut db);
a.set_storage(1.into(), 0.into()); a.set_storage(x!(1), x!(0));
a.commit_storage(&Default::default(), &mut db); a.commit_storage(&mut db);
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2"); assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
} }
#[test] #[test]
fn commit_code() { fn commit_code() {
let mut a = Account::new_contract(69.into(), 0.into()); let mut a = Account::new_contract(x!(69), x!(0));
let mut db = MemoryDB::new(); let mut db = MemoryDB::new();
let mut db = AccountDBMut::new(&mut db, &Address::new()); let mut db = AccountDBMut::new(&mut db, &Address::new());
a.init_code(vec![0x55, 0x44, 0xffu8]); a.init_code(vec![0x55, 0x44, 0xffu8]);
assert_eq!(a.code_filth, Filth::Dirty); assert_eq!(a.code_hash(), SHA3_EMPTY);
assert_eq!(a.code_size(), Some(3));
a.commit_code(&mut db); a.commit_code(&mut db);
assert_eq!(a.code_hash().hex(), "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb"); 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_filth, Filth::Dirty);
a.commit_code(&mut db);
assert_eq!(a.code_filth, Filth::Clean);
assert_eq!(a.code_hash().hex(), "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb");
a.reset_code(vec![0x55]);
assert_eq!(a.code_filth, Filth::Dirty);
a.commit_code(&mut db);
assert_eq!(a.code_hash().hex(), "37bf2238b11b68cdc8382cece82651b59d3c3988873b6e0f33d79694aa45f1be");
}
#[test] #[test]
fn rlpio() { fn rlpio() {
let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new()); let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new());
@@ -552,6 +342,8 @@ mod tests {
#[test] #[test]
fn new_account() { fn new_account() {
use rustc_serialize::hex::ToHex;
let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new()); let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new());
assert_eq!(a.rlp().to_hex(), "f8448045a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); assert_eq!(a.rlp().to_hex(), "f8448045a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
assert_eq!(a.balance(), &U256::from(69u8)); assert_eq!(a.balance(), &U256::from(69u8));
@@ -562,6 +354,8 @@ mod tests {
#[test] #[test]
fn create_account() { fn create_account() {
use rustc_serialize::hex::ToHex;
let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new()); let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new());
assert_eq!(a.rlp().to_hex(), "f8448045a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); assert_eq!(a.rlp().to_hex(), "f8448045a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
} }

View File

@@ -1,59 +1,26 @@
// 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/>.
//! DB backend wrapper for Account trie //! DB backend wrapper for Account trie
use util::*; use util::*;
static NULL_RLP_STATIC: [u8; 1] = [0x80; 1]; static NULL_RLP_STATIC: [u8; 1] = [0x80; 1];
// combines a key with an address hash to ensure uniqueness.
// leaves the first 96 bits untouched in order to support partial key lookup.
#[inline]
fn combine_key<'a>(address_hash: &'a H256, key: &'a H256) -> H256 {
let mut dst = key.clone();
{
let last_src: &[u8] = &*address_hash;
let last_dst: &mut [u8] = &mut *dst;
for (k, a) in last_dst[12..].iter_mut().zip(&last_src[12..]) {
*k ^= *a
}
}
dst
}
// TODO: introduce HashDBMut? // TODO: introduce HashDBMut?
/// DB backend wrapper for Account trie /// DB backend wrapper for Account trie
/// Transforms trie node keys for the database /// Transforms trie node keys for the database
pub struct AccountDB<'db> { pub struct AccountDB<'db> {
db: &'db HashDB, db: &'db HashDB,
address_hash: H256, address: H256,
}
#[inline]
fn combine_key<'a>(address: &'a H256, key: &'a H256) -> H256 {
address ^ key
} }
impl<'db> AccountDB<'db> { impl<'db> AccountDB<'db> {
/// Create a new AccountDB from an address. pub fn new(db: &'db HashDB, address: &Address) -> AccountDB<'db> {
pub fn new(db: &'db HashDB, address: &Address) -> Self {
Self::from_hash(db, address.sha3())
}
/// Create a new AcountDB from an address' hash.
pub fn from_hash(db: &'db HashDB, address_hash: H256) -> Self {
AccountDB { AccountDB {
db: db, db: db,
address_hash: address_hash, address: x!(address),
} }
} }
} }
@@ -63,18 +30,18 @@ impl<'db> HashDB for AccountDB<'db>{
unimplemented!() unimplemented!()
} }
fn get(&self, key: &H256) -> Option<&[u8]> { fn lookup(&self, key: &H256) -> Option<&[u8]> {
if key == &SHA3_NULL_RLP { if key == &SHA3_NULL_RLP {
return Some(&NULL_RLP_STATIC); return Some(&NULL_RLP_STATIC);
} }
self.db.get(&combine_key(&self.address_hash, key)) self.db.lookup(&combine_key(&self.address, key))
} }
fn contains(&self, key: &H256) -> bool { fn exists(&self, key: &H256) -> bool {
if key == &SHA3_NULL_RLP { if key == &SHA3_NULL_RLP {
return true; return true;
} }
self.db.contains(&combine_key(&self.address_hash, key)) self.db.exists(&combine_key(&self.address, key))
} }
fn insert(&mut self, _value: &[u8]) -> H256 { fn insert(&mut self, _value: &[u8]) -> H256 {
@@ -85,7 +52,7 @@ impl<'db> HashDB for AccountDB<'db>{
unimplemented!() unimplemented!()
} }
fn remove(&mut self, _key: &H256) { fn kill(&mut self, _key: &H256) {
unimplemented!() unimplemented!()
} }
} }
@@ -93,26 +60,20 @@ impl<'db> HashDB for AccountDB<'db>{
/// DB backend wrapper for Account trie /// DB backend wrapper for Account trie
pub struct AccountDBMut<'db> { pub struct AccountDBMut<'db> {
db: &'db mut HashDB, db: &'db mut HashDB,
address_hash: H256, address: H256,
} }
impl<'db> AccountDBMut<'db> { impl<'db> AccountDBMut<'db> {
/// Create a new AccountDB from an address. pub fn new(db: &'db mut HashDB, address: &Address) -> AccountDBMut<'db> {
pub fn new(db: &'db mut HashDB, address: &Address) -> Self {
Self::from_hash(db, address.sha3())
}
/// Create a new AcountDB from an address' hash.
pub fn from_hash(db: &'db mut HashDB, address_hash: H256) -> Self {
AccountDBMut { AccountDBMut {
db: db, db: db,
address_hash: address_hash, address: x!(address),
} }
} }
#[allow(dead_code)] #[allow(dead_code)]
pub fn immutable(&'db self) -> AccountDB<'db> { pub fn immutable(&'db self) -> AccountDB<'db> {
AccountDB { db: self.db, address_hash: self.address_hash.clone() } AccountDB { db: self.db, address: self.address.clone() }
} }
} }
@@ -121,18 +82,18 @@ impl<'db> HashDB for AccountDBMut<'db>{
unimplemented!() unimplemented!()
} }
fn get(&self, key: &H256) -> Option<&[u8]> { fn lookup(&self, key: &H256) -> Option<&[u8]> {
if key == &SHA3_NULL_RLP { if key == &SHA3_NULL_RLP {
return Some(&NULL_RLP_STATIC); return Some(&NULL_RLP_STATIC);
} }
self.db.get(&combine_key(&self.address_hash, key)) self.db.lookup(&combine_key(&self.address, key))
} }
fn contains(&self, key: &H256) -> bool { fn exists(&self, key: &H256) -> bool {
if key == &SHA3_NULL_RLP { if key == &SHA3_NULL_RLP {
return true; return true;
} }
self.db.contains(&combine_key(&self.address_hash, key)) self.db.exists(&combine_key(&self.address, key))
} }
fn insert(&mut self, value: &[u8]) -> H256 { fn insert(&mut self, value: &[u8]) -> H256 {
@@ -140,7 +101,7 @@ impl<'db> HashDB for AccountDBMut<'db>{
return SHA3_NULL_RLP.clone(); return SHA3_NULL_RLP.clone();
} }
let k = value.sha3(); let k = value.sha3();
let ak = combine_key(&self.address_hash, &k); let ak = combine_key(&self.address, &k);
self.db.emplace(ak, value.to_vec()); self.db.emplace(ak, value.to_vec());
k k
} }
@@ -149,16 +110,16 @@ impl<'db> HashDB for AccountDBMut<'db>{
if key == SHA3_NULL_RLP { if key == SHA3_NULL_RLP {
return; return;
} }
let key = combine_key(&self.address_hash, &key); let key = combine_key(&self.address, &key);
self.db.emplace(key, value.to_vec()) self.db.emplace(key, value.to_vec())
} }
fn remove(&mut self, key: &H256) { fn kill(&mut self, key: &H256) {
if key == &SHA3_NULL_RLP { if key == &SHA3_NULL_RLP {
return; return;
} }
let key = combine_key(&self.address_hash, key); let key = combine_key(&self.address, key);
self.db.remove(&key) self.db.kill(&key)
} }
} }

View File

@@ -16,56 +16,12 @@
//! Diff between two accounts. //! Diff between two accounts.
use util::numbers::*; use util::*;
use std::cmp::*; #[cfg(test)]
use std::fmt; use pod_account::*;
use ipc::binary::{BinaryConvertError, BinaryConvertable};
use util::Bytes;
use std::collections::{VecDeque, BTreeMap};
use std::mem;
#[derive(Debug, PartialEq, Eq, Clone, Binary)] #[derive(Debug,Clone,PartialEq,Eq)]
/// Diff type for specifying a change (or not). /// Change in existance type.
pub enum Diff<T> where T: Eq + BinaryConvertable {
/// Both sides are the same.
Same,
/// Left (pre, source) side doesn't include value, right side (post, destination) does.
Born(T),
/// Both sides include data; it chaged value between them.
Changed(T, T),
/// Left (pre, source) side does include value, right side (post, destination) does not.
Died(T),
}
impl<T> Diff<T> where T: Eq + BinaryConvertable {
/// Construct new object with given `pre` and `post`.
pub fn new(pre: T, post: T) -> Self { if pre == post { Diff::Same } else { Diff::Changed(pre, post) } }
/// Get the before value, if there is one.
pub fn pre(&self) -> Option<&T> { match *self { Diff::Died(ref x) | Diff::Changed(ref x, _) => Some(x), _ => None } }
/// Get the after value, if there is one.
pub fn post(&self) -> Option<&T> { match *self { Diff::Born(ref x) | Diff::Changed(_, ref x) => Some(x), _ => None } }
/// Determine whether there was a change or not.
pub fn is_same(&self) -> bool { match *self { Diff::Same => true, _ => false }}
}
#[derive(Debug, PartialEq, Eq, Clone, Binary)]
/// Account diff.
pub struct AccountDiff {
/// Change in balance, allowed to be `Diff::Same`.
pub balance: Diff<U256>,
/// Change in nonce, allowed to be `Diff::Same`.
pub nonce: Diff<U256>, // Allowed to be Same
/// Change in code, allowed to be `Diff::Same`.
pub code: Diff<Bytes>, // Allowed to be Same
/// Change in storage, values are not allowed to be `Diff::Same`.
pub storage: BTreeMap<H256, Diff<H256>>,
}
#[derive(Debug, PartialEq, Eq, Clone, Binary)]
/// Change in existance type.
// TODO: include other types of change. // TODO: include other types of change.
pub enum Existance { pub enum Existance {
/// Item came into existance. /// Item came into existance.
@@ -87,6 +43,19 @@ impl fmt::Display for Existance {
} }
} }
#[derive(Debug,Clone,PartialEq,Eq)]
/// Account diff.
pub struct AccountDiff {
/// Change in balance, allowed to be `Diff::Same`.
pub balance: Diff<U256>,
/// Change in nonce, allowed to be `Diff::Same`.
pub nonce: Diff<U256>, // Allowed to be Same
/// Change in code, allowed to be `Diff::Same`.
pub code: Diff<Bytes>, // Allowed to be Same
/// Change in storage, values are not allowed to be `Diff::Same`.
pub storage: BTreeMap<H256, Diff<H256>>,
}
impl AccountDiff { impl AccountDiff {
/// Get `Existance` projection. /// Get `Existance` projection.
pub fn existance(&self) -> Existance { pub fn existance(&self) -> Existance {
@@ -96,12 +65,51 @@ impl AccountDiff {
_ => Existance::Alive, _ => Existance::Alive,
} }
} }
#[cfg(test)]
/// Determine difference between two optionally existant `Account`s. Returns None
/// if they are the same.
pub fn diff_pod(pre: Option<&PodAccount>, post: Option<&PodAccount>) -> Option<AccountDiff> {
match (pre, post) {
(None, Some(x)) => Some(AccountDiff {
balance: Diff::Born(x.balance),
nonce: Diff::Born(x.nonce),
code: Diff::Born(x.code.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()),
storage: x.storage.iter().map(|(k, v)| (k.clone(), Diff::Died(v.clone()))).collect(),
}),
(Some(pre), Some(post)) => {
let storage: Vec<_> = pre.storage.keys().merge(post.storage.keys())
.filter(|k| pre.storage.get(k).unwrap_or(&H256::new()) != post.storage.get(k).unwrap_or(&H256::new()))
.collect();
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()),
storage: storage.into_iter().map(|k|
(k.clone(), Diff::new(
pre.storage.get(&k).cloned().unwrap_or_else(H256::new),
post.storage.get(&k).cloned().unwrap_or_else(H256::new)
))).collect(),
};
if r.balance.is_same() && r.nonce.is_same() && r.code.is_same() && r.storage.is_empty() {
None
} else {
Some(r)
}
},
_ => None,
}
}
} }
// TODO: refactor into something nicer. // TODO: refactor into something nicer.
fn interpreted_hash(u: &H256) -> String { fn interpreted_hash(u: &H256) -> String {
use util::bytes::*;
if u <= &H256::from(0xffffffff) { if u <= &H256::from(0xffffffff) {
format!("{} = 0x{:x}", U256::from(u.as_slice()).low_u32(), U256::from(u.as_slice()).low_u32()) format!("{} = 0x{:x}", U256::from(u.as_slice()).low_u32(), U256::from(u.as_slice()).low_u32())
} else if u <= &H256::from(u64::max_value()) { } else if u <= &H256::from(u64::max_value()) {
@@ -115,8 +123,6 @@ fn interpreted_hash(u: &H256) -> String {
impl fmt::Display for AccountDiff { impl fmt::Display for AccountDiff {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use util::bytes::*;
match self.nonce { match self.nonce {
Diff::Born(ref x) => try!(write!(f, " non {}", x)), Diff::Born(ref x) => try!(write!(f, " non {}", x)),
Diff::Changed(ref pre, ref post) => try!(write!(f, "#{} ({} {} {})", post, pre, if pre > post {"-"} else {"+"}, *max(pre, post) - * min(pre, post))), Diff::Changed(ref pre, ref post) => try!(write!(f, "#{} ({} {} {})", post, pre, if pre > post {"-"} else {"+"}, *max(pre, post) - * min(pre, post))),

View File

@@ -1,355 +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/>.
//! Account management.
use std::fmt;
use std::collections::HashMap;
use std::time::{Instant, Duration};
use util::{Address as H160, H256, H520, Mutex, RwLock};
use ethstore::{SecretStore, Error as SSError, SafeAccount, EthStore};
use ethstore::dir::{KeyDirectory};
use ethstore::ethkey::{Address as SSAddress, Message as SSMessage, Secret as SSSecret, Random, Generator};
/// Type of unlock.
#[derive(Clone)]
enum Unlock {
/// If account is unlocked temporarily, it should be locked after first usage.
Temp,
/// Account unlocked permantently can always sign message.
/// Use with caution.
Perm,
/// Account unlocked with a timeout
Timed((Instant, u32)),
}
/// Data associated with account.
#[derive(Clone)]
struct AccountData {
unlock: Unlock,
password: String,
}
/// `AccountProvider` errors.
#[derive(Debug)]
pub enum Error {
/// Returned when account is not unlocked.
NotUnlocked,
/// Returned when signing fails.
SStore(SSError),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
Error::NotUnlocked => write!(f, "Account is locked"),
Error::SStore(ref e) => write!(f, "{}", e),
}
}
}
impl From<SSError> for Error {
fn from(e: SSError) -> Self {
Error::SStore(e)
}
}
macro_rules! impl_bridge_type {
($name: ident, $size: expr, $core: ident, $store: ident) => {
/// Primitive
pub struct $name([u8; $size]);
impl From<[u8; $size]> for $name {
fn from(s: [u8; $size]) -> Self {
$name(s)
}
}
impl From<$core> for $name {
fn from(s: $core) -> Self {
$name(s.0)
}
}
impl From<$store> for $name {
fn from(s: $store) -> Self {
$name(s.into())
}
}
impl Into<$core> for $name {
fn into(self) -> $core {
$core(self.0)
}
}
impl Into<$store> for $name {
fn into(self) -> $store {
$store::from(self.0)
}
}
}
}
impl_bridge_type!(Secret, 32, H256, SSSecret);
impl_bridge_type!(Message, 32, H256, SSMessage);
impl_bridge_type!(Address, 20, H160, SSAddress);
#[derive(Default)]
struct NullDir {
accounts: RwLock<HashMap<SSAddress, SafeAccount>>,
}
impl KeyDirectory for NullDir {
fn load(&self) -> Result<Vec<SafeAccount>, SSError> {
Ok(self.accounts.read().values().cloned().collect())
}
fn insert(&self, account: SafeAccount) -> Result<SafeAccount, SSError> {
self.accounts.write().insert(account.address.clone(), account.clone());
Ok(account)
}
fn remove(&self, address: &SSAddress) -> Result<(), SSError> {
self.accounts.write().remove(address);
Ok(())
}
}
/// Account management.
/// Responsible for unlocking accounts.
pub struct AccountProvider {
unlocked: Mutex<HashMap<SSAddress, AccountData>>,
sstore: Box<SecretStore>,
}
/// Collected account metadata
#[derive(Clone, Debug, PartialEq)]
pub struct AccountMeta {
/// The name of the account.
pub name: String,
/// The rest of the metadata of the account.
pub meta: String,
/// The 128-bit UUID of the account, if it has one (brain-wallets don't).
pub uuid: Option<String>,
}
impl Default for AccountMeta {
fn default() -> Self {
AccountMeta {
name: String::new(),
meta: "{}".to_owned(),
uuid: None,
}
}
}
impl AccountProvider {
/// Creates new account provider.
pub fn new(sstore: Box<SecretStore>) -> Self {
AccountProvider {
unlocked: Mutex::new(HashMap::new()),
sstore: sstore,
}
}
/// Creates not disk backed provider.
pub fn transient_provider() -> Self {
AccountProvider {
unlocked: Mutex::new(HashMap::new()),
sstore: Box::new(EthStore::open(Box::new(NullDir::default())).unwrap())
}
}
/// Creates new random account.
pub fn new_account(&self, password: &str) -> Result<H160, Error> {
let secret = Random.generate().unwrap().secret().clone();
let address = try!(self.sstore.insert_account(secret, password));
Ok(Address::from(address).into())
}
/// Inserts new account into underlying store.
/// Does not unlock account!
pub fn insert_account<S>(&self, secret: S, password: &str) -> Result<H160, Error> where Secret: From<S> {
let s = Secret::from(secret);
let address = try!(self.sstore.insert_account(s.into(), password));
Ok(Address::from(address).into())
}
/// Returns addresses of all accounts.
pub fn accounts(&self) -> Result<Vec<H160>, Error> {
let accounts = try!(self.sstore.accounts()).into_iter().map(|a| H160(a.into())).collect();
Ok(accounts)
}
/// Returns each account along with name and meta.
pub fn accounts_info(&self) -> Result<HashMap<H160, AccountMeta>, Error> {
let r: HashMap<H160, AccountMeta> = try!(self.sstore.accounts())
.into_iter()
.map(|a| (H160(a.clone().into()), self.account_meta(a).unwrap_or_else(|_| Default::default())))
.collect();
Ok(r)
}
/// Returns each account along with name and meta.
pub fn account_meta<A>(&self, account: A) -> Result<AccountMeta, Error> where Address: From<A> {
let account = Address::from(account).into();
Ok(AccountMeta {
name: try!(self.sstore.name(&account)),
meta: try!(self.sstore.meta(&account)),
uuid: self.sstore.uuid(&account).ok().map(Into::into), // allowed to not have a UUID
})
}
/// Returns each account along with name and meta.
pub fn set_account_name<A>(&self, account: A, name: String) -> Result<(), Error> where Address: From<A> {
let account = Address::from(account).into();
try!(self.sstore.set_name(&account, name));
Ok(())
}
/// Returns each account along with name and meta.
pub fn set_account_meta<A>(&self, account: A, meta: String) -> Result<(), Error> where Address: From<A> {
let account = Address::from(account).into();
try!(self.sstore.set_meta(&account, meta));
Ok(())
}
/// Helper method used for unlocking accounts.
fn unlock_account<A>(&self, account: A, password: String, unlock: Unlock) -> Result<(), Error> where Address: From<A> {
let a = Address::from(account);
let account = a.into();
// verify password by signing dump message
// result may be discarded
let _ = try!(self.sstore.sign(&account, &password, &Default::default()));
// check if account is already unlocked pernamently, if it is, do nothing
let mut unlocked = self.unlocked.lock();
if let Some(data) = unlocked.get(&account) {
if let Unlock::Perm = data.unlock {
return Ok(())
}
}
let data = AccountData {
unlock: unlock,
password: password,
};
unlocked.insert(account, data);
Ok(())
}
/// Unlocks account permanently.
pub fn unlock_account_permanently<A>(&self, account: A, password: String) -> Result<(), Error> where Address: From<A> {
self.unlock_account(account, password, Unlock::Perm)
}
/// Unlocks account temporarily (for one signing).
pub fn unlock_account_temporarily<A>(&self, account: A, password: String) -> Result<(), Error> where Address: From<A> {
self.unlock_account(account, password, Unlock::Temp)
}
/// Unlocks account temporarily with a timeout.
pub fn unlock_account_timed<A>(&self, account: A, password: String, duration_ms: u32) -> Result<(), Error> where Address: From<A> {
self.unlock_account(account, password, Unlock::Timed((Instant::now(), duration_ms)))
}
/// Checks if given account is unlocked
pub fn is_unlocked<A>(&self, account: A) -> bool where Address: From<A> {
let account = Address::from(account).into();
let unlocked = self.unlocked.lock();
unlocked.get(&account).is_some()
}
/// Signs the message. Account must be unlocked.
pub fn sign<A, M>(&self, account: A, message: M) -> Result<H520, Error> where Address: From<A>, Message: From<M> {
let account = Address::from(account).into();
let message = Message::from(message).into();
let data = {
let mut unlocked = self.unlocked.lock();
let data = try!(unlocked.get(&account).ok_or(Error::NotUnlocked)).clone();
if let Unlock::Temp = data.unlock {
unlocked.remove(&account).expect("data exists: so key must exist: qed");
}
if let Unlock::Timed((ref start, ref duration)) = data.unlock {
if start.elapsed() > Duration::from_millis(*duration as u64) {
unlocked.remove(&account).expect("data exists: so key must exist: qed");
return Err(Error::NotUnlocked);
}
}
data
};
let signature = try!(self.sstore.sign(&account, &data.password, &message));
Ok(H520(signature.into()))
}
/// Unlocks an account, signs the message, and locks it again.
pub fn sign_with_password<A, M>(&self, account: A, password: String, message: M) -> Result<H520, Error> where Address: From<A>, Message: From<M> {
let account = Address::from(account).into();
let message = Message::from(message).into();
let signature = try!(self.sstore.sign(&account, &password, &message));
Ok(H520(signature.into()))
}
}
#[cfg(test)]
mod tests {
use super::AccountProvider;
use ethstore::ethkey::{Generator, Random};
use std::time::Duration;
#[test]
fn unlock_account_temp() {
let kp = Random.generate().unwrap();
let ap = AccountProvider::transient_provider();
assert!(ap.insert_account(kp.secret().clone(), "test").is_ok());
assert!(ap.unlock_account_temporarily(kp.address(), "test1".into()).is_err());
assert!(ap.unlock_account_temporarily(kp.address(), "test".into()).is_ok());
assert!(ap.sign(kp.address(), [0u8; 32]).is_ok());
assert!(ap.sign(kp.address(), [0u8; 32]).is_err());
}
#[test]
fn unlock_account_perm() {
let kp = Random.generate().unwrap();
let ap = AccountProvider::transient_provider();
assert!(ap.insert_account(kp.secret().clone(), "test").is_ok());
assert!(ap.unlock_account_permanently(kp.address(), "test1".into()).is_err());
assert!(ap.unlock_account_permanently(kp.address(), "test".into()).is_ok());
assert!(ap.sign(kp.address(), [0u8; 32]).is_ok());
assert!(ap.sign(kp.address(), [0u8; 32]).is_ok());
assert!(ap.unlock_account_temporarily(kp.address(), "test".into()).is_ok());
assert!(ap.sign(kp.address(), [0u8; 32]).is_ok());
assert!(ap.sign(kp.address(), [0u8; 32]).is_ok());
}
#[test]
fn unlock_account_timer() {
let kp = Random.generate().unwrap();
let ap = AccountProvider::transient_provider();
assert!(ap.insert_account(kp.secret().clone(), "test").is_ok());
assert!(ap.unlock_account_timed(kp.address(), "test1".into(), 2000).is_err());
assert!(ap.unlock_account_timed(kp.address(), "test".into(), 2000).is_ok());
assert!(ap.sign(kp.address(), [0u8; 32]).is_ok());
::std::thread::sleep(Duration::from_millis(2000));
assert!(ap.sign(kp.address(), [0u8; 32]).is_err());
}
}

View File

@@ -16,8 +16,6 @@
//! Evm input params. //! Evm input params.
use common::*; use common::*;
use ethjson;
use types::executed::CallType;
/// Transaction value /// Transaction value
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@@ -28,23 +26,12 @@ pub enum ActionValue {
Apparent(U256) Apparent(U256)
} }
impl ActionValue {
/// Returns action value as U256.
pub fn value(&self) -> U256 {
match *self {
ActionValue::Transfer(x) | ActionValue::Apparent(x) => x
}
}
}
// TODO: should be a trait, possible to avoid cloning everything from a Transaction(/View). // TODO: should be a trait, possible to avoid cloning everything from a Transaction(/View).
/// Action (call/create) input params. Everything else should be specified in Externalities. /// Action (call/create) input params. Everything else should be specified in Externalities.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ActionParams { pub struct ActionParams {
/// Address of currently executed code. /// Address of currently executed code.
pub code_address: Address, pub code_address: Address,
/// Hash of currently executed code.
pub code_hash: H256,
/// Receive address. Usually equal to code_address, /// Receive address. Usually equal to code_address,
/// except when called using CALLCODE. /// except when called using CALLCODE.
pub address: Address, pub address: Address,
@@ -59,12 +46,9 @@ pub struct ActionParams {
/// Transaction value. /// Transaction value.
pub value: ActionValue, pub value: ActionValue,
/// Code being executed. /// Code being executed.
pub code: Option<Arc<Bytes>>, pub code: Option<Bytes>,
/// Input data. /// Input data.
pub data: Option<Bytes>, pub data: Option<Bytes>
/// Type of call
pub call_type: CallType,
} }
impl Default for ActionParams { impl Default for ActionParams {
@@ -72,7 +56,6 @@ impl Default for ActionParams {
fn default() -> ActionParams { fn default() -> ActionParams {
ActionParams { ActionParams {
code_address: Address::new(), code_address: Address::new(),
code_hash: SHA3_EMPTY,
address: Address::new(), address: Address::new(),
sender: Address::new(), sender: Address::new(),
origin: Address::new(), origin: Address::new(),
@@ -80,27 +63,7 @@ impl Default for ActionParams {
gas_price: U256::zero(), gas_price: U256::zero(),
value: ActionValue::Transfer(U256::zero()), value: ActionValue::Transfer(U256::zero()),
code: None, 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(),
code_hash: (&*t.code).sha3(),
address: address,
sender: t.sender.into(),
origin: t.origin.into(),
code: Some(Arc::new(t.code.into())),
data: Some(t.data.into()),
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

@@ -16,16 +16,16 @@
//! Blockchain block. //! Blockchain block.
#![cfg_attr(feature="dev", allow(ptr_arg))] // Because of &LastHashes -> &Vec<_>
use common::*; use common::*;
use engines::Engine; use engine::*;
use state::*; use state::*;
use state_db::StateDB;
use verification::PreverifiedBlock; use verification::PreverifiedBlock;
use trace::FlatTrace;
use evm::Factory as EvmFactory;
/// A block, encoded as it is on the block chain. /// A block, encoded as it is on the block chain.
#[derive(Default, Debug, Clone, PartialEq)] // TODO: rename to Block
#[derive(Default, Debug, Clone)]
pub struct Block { pub struct Block {
/// The header of this block. /// The header of this block.
pub header: Header, pub header: Header,
@@ -37,21 +37,27 @@ pub struct Block {
impl Block { impl Block {
/// Returns true if the given bytes form a valid encoding of a block in RLP. /// Returns true if the given bytes form a valid encoding of a block in RLP.
// TODO: implement Decoder for this and have this use that.
pub fn is_good(b: &[u8]) -> bool { pub fn is_good(b: &[u8]) -> bool {
/*
let urlp = UntrustedRlp::new(&b);
if !urlp.is_list() || urlp.item_count() != 3 || urlp.size() != b.len() { return false; }
if urlp.val_at::<Header>(0).is_err() { return false; }
if !urlp.at(1).unwrap().is_list() { return false; }
if urlp.at(1).unwrap().iter().find(|i| i.as_val::<Transaction>().is_err()).is_some() {
return false;
}
if !urlp.at(2).unwrap().is_list() { return false; }
if urlp.at(2).unwrap().iter().find(|i| i.as_val::<Header>().is_err()).is_some() {
return false;
}
true*/
UntrustedRlp::new(b).as_val::<Block>().is_ok() UntrustedRlp::new(b).as_val::<Block>().is_ok()
} }
/// Get the RLP-encoding of the block with or without the seal.
pub fn rlp_bytes(&self, seal: Seal) -> Bytes {
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 { impl Decodable for Block {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder { fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
if decoder.as_raw().len() != try!(decoder.as_rlp().payload_info()).total() { if decoder.as_raw().len() != try!(decoder.as_rlp().payload_info()).total() {
@@ -70,93 +76,52 @@ impl Decodable for Block {
} }
/// Internal type for a block's common elements. /// Internal type for a block's common elements.
#[derive(Clone)] // TODO: rename to ExecutedBlock
// TODO: use BareBlock
#[derive(Debug)]
pub struct ExecutedBlock { pub struct ExecutedBlock {
base: Block, base: Block,
receipts: Vec<Receipt>, receipts: Vec<Receipt>,
transactions_set: HashSet<H256>, transactions_set: HashSet<H256>,
state: State, state: State,
traces: Option<Vec<Vec<FlatTrace>>>,
} }
/// A set of references to `ExecutedBlock` fields that are publicly accessible. /// A set of references to `ExecutedBlock` fields that are publicly accessible.
pub struct BlockRefMut<'a> { pub struct BlockRefMut<'a> {
/// Block header.
pub header: &'a mut Header,
/// Block transactions.
pub transactions: &'a [SignedTransaction],
/// Block uncles.
pub uncles: &'a [Header],
/// Transaction receipts.
pub receipts: &'a [Receipt],
/// State.
pub state: &'a mut State,
/// Traces.
pub traces: &'a Option<Vec<Vec<FlatTrace>>>,
}
/// A set of immutable references to `ExecutedBlock` fields that are publicly accessible.
pub struct BlockRef<'a> {
/// Block header. /// Block header.
pub header: &'a Header, pub header: &'a Header,
/// Block transactions. /// Block transactions.
pub transactions: &'a [SignedTransaction], pub transactions: &'a Vec<SignedTransaction>,
/// Block uncles. /// Block uncles.
pub uncles: &'a [Header], pub uncles: &'a Vec<Header>,
/// Transaction receipts. /// Transaction receipts.
pub receipts: &'a [Receipt], pub receipts: &'a Vec<Receipt>,
/// State. /// State.
pub state: &'a State, pub state: &'a mut State,
/// Traces.
pub traces: &'a Option<Vec<Vec<FlatTrace>>>,
} }
impl ExecutedBlock { impl ExecutedBlock {
/// Create a new block from the given `state`. /// Create a new block from the given `state`.
fn new(state: State, tracing: bool) -> ExecutedBlock { fn new(state: State) -> ExecutedBlock { ExecutedBlock { base: Default::default(), receipts: Default::default(), transactions_set: Default::default(), state: state } }
ExecutedBlock {
base: Default::default(),
receipts: Default::default(),
transactions_set: Default::default(),
state: state,
traces: if tracing {Some(Vec::new())} else {None},
}
}
/// Get a structure containing individual references to all public fields. /// Get a structure containing individual references to all public fields.
pub fn fields_mut(&mut self) -> BlockRefMut { pub fn fields(&mut self) -> BlockRefMut {
BlockRefMut { BlockRefMut {
header: &mut self.base.header, header: &self.base.header,
transactions: &self.base.transactions, transactions: &self.base.transactions,
uncles: &self.base.uncles, uncles: &self.base.uncles,
state: &mut self.state, state: &mut self.state,
receipts: &self.receipts, receipts: &self.receipts,
traces: &self.traces,
}
}
/// Get a structure containing individual references to all public fields.
pub fn fields(&self) -> BlockRef {
BlockRef {
header: &self.base.header,
transactions: &self.base.transactions,
uncles: &self.base.uncles,
state: &self.state,
receipts: &self.receipts,
traces: &self.traces,
} }
} }
} }
/// Trait for a object that is a `ExecutedBlock`. /// Trait for a object that is_a `ExecutedBlock`.
pub trait IsBlock { pub trait IsBlock {
/// Get the `ExecutedBlock` associated with this object. /// Get the block associated with this object.
fn block(&self) -> &ExecutedBlock; 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. /// Get the header associated with this object's block.
fn header(&self) -> &Header { &self.block().base.header } fn header(&self) -> &Header { &self.block().base.header }
@@ -164,22 +129,13 @@ pub trait IsBlock {
fn state(&self) -> &State { &self.block().state } fn state(&self) -> &State { &self.block().state }
/// Get all information on transactions in this block. /// Get all information on transactions in this block.
fn transactions(&self) -> &[SignedTransaction] { &self.block().base.transactions } fn transactions(&self) -> &Vec<SignedTransaction> { &self.block().base.transactions }
/// Get all information on receipts in this block. /// Get all information on receipts in this block.
fn receipts(&self) -> &[Receipt] { &self.block().receipts } fn receipts(&self) -> &Vec<Receipt> { &self.block().receipts }
/// Get all information concerning transaction tracing in this block.
fn traces(&self) -> &Option<Vec<Vec<FlatTrace>>> { &self.block().traces }
/// Get all uncles in this block. /// Get all uncles in this block.
fn uncles(&self) -> &[Header] { &self.block().base.uncles } 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) -> StateDB;
} }
impl IsBlock for ExecutedBlock { impl IsBlock for ExecutedBlock {
@@ -193,59 +149,32 @@ impl IsBlock for ExecutedBlock {
pub struct OpenBlock<'x> { pub struct OpenBlock<'x> {
block: ExecutedBlock, block: ExecutedBlock,
engine: &'x Engine, engine: &'x Engine,
vm_factory: &'x EvmFactory, last_hashes: LastHashes,
last_hashes: Arc<LastHashes>,
} }
/// Just like `OpenBlock`, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields, /// Just like OpenBlock, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields,
/// and collected the uncles. /// and collected the uncles.
/// ///
/// There is no function available to push a transaction. /// There is no function available to push a transaction.
#[derive(Clone)]
pub struct ClosedBlock { pub struct ClosedBlock {
block: ExecutedBlock, block: ExecutedBlock,
uncle_bytes: Bytes, uncle_bytes: Bytes,
last_hashes: Arc<LastHashes>,
unclosed_state: State,
}
/// Just like `ClosedBlock` except that we can't reopen it and it's faster.
///
/// We actually store the post-`Engine::on_close_block` state, unlike in `ClosedBlock` where it's the pre.
#[derive(Clone)]
pub struct LockedBlock {
block: ExecutedBlock,
uncle_bytes: Bytes,
} }
/// A block that has a valid seal. /// A block that has a valid seal.
/// ///
/// The block's header has valid seal arguments. The block cannot be reversed into a `ClosedBlock` or `OpenBlock`. /// The block's header has valid seal arguments. The block cannot be reversed into a ClosedBlock or OpenBlock.
pub struct SealedBlock { pub struct SealedBlock {
block: ExecutedBlock, block: ExecutedBlock,
uncle_bytes: Bytes, uncle_bytes: Bytes,
} }
impl<'x> OpenBlock<'x> { impl<'x> OpenBlock<'x> {
#[cfg_attr(feature="dev", allow(too_many_arguments))] /// Create a new OpenBlock ready for transaction pushing.
/// Create a new `OpenBlock` ready for transaction pushing. pub fn new(engine: &'x Engine, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes, author: Address, gas_floor_target: U256, extra_data: Bytes) -> Self {
pub fn new(
engine: &'x Engine,
vm_factory: &'x EvmFactory,
trie_factory: TrieFactory,
tracing: bool,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
author: Address,
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(), trie_factory));
let mut r = OpenBlock { let mut r = OpenBlock {
block: ExecutedBlock::new(state, tracing), block: ExecutedBlock::new(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce())),
engine: engine, engine: engine,
vm_factory: vm_factory,
last_hashes: last_hashes, last_hashes: last_hashes,
}; };
@@ -256,9 +185,9 @@ impl<'x> OpenBlock<'x> {
r.block.base.header.extra_data = extra_data; r.block.base.header.extra_data = extra_data;
r.block.base.header.note_dirty(); r.block.base.header.note_dirty();
engine.populate_from_parent(&mut r.block.base.header, parent, gas_range_target.0, gas_range_target.1); engine.populate_from_parent(&mut r.block.base.header, parent, gas_floor_target);
engine.on_new_block(&mut r.block); engine.on_new_block(&mut r.block);
Ok(r) r
} }
/// Alter the author for the block. /// Alter the author for the block.
@@ -276,15 +205,6 @@ impl<'x> OpenBlock<'x> {
/// Alter the gas limit for the block. /// Alter the gas limit for the block.
pub fn set_gas_used(&mut self, a: U256) { self.block.base.header.set_gas_used(a); } pub fn set_gas_used(&mut self, a: U256) { self.block.base.header.set_gas_used(a); }
/// Alter the uncles hash the block.
pub fn set_uncles_hash(&mut self, h: H256) { self.block.base.header.set_uncles_hash(h); }
/// Alter transactions root for the block.
pub fn set_transactions_root(&mut self, h: H256) { self.block.base.header.set_transactions_root(h); }
/// Alter the receipts root for the block.
pub fn set_receipts_root(&mut self, h: H256) { self.block.base.header.set_receipts_root(h); }
/// Alter the extra_data for the block. /// Alter the extra_data for the block.
pub fn set_extra_data(&mut self, extra_data: Bytes) -> Result<(), BlockError> { pub fn set_extra_data(&mut self, extra_data: Bytes) -> Result<(), BlockError> {
if extra_data.len() > self.engine.maximum_extra_data_size() { if extra_data.len() > self.engine.maximum_extra_data_size() {
@@ -317,7 +237,7 @@ impl<'x> OpenBlock<'x> {
author: self.block.base.header.author.clone(), author: self.block.base.header.author.clone(),
timestamp: self.block.base.header.timestamp, timestamp: self.block.base.header.timestamp,
difficulty: self.block.base.header.difficulty.clone(), difficulty: self.block.base.header.difficulty.clone(),
last_hashes: self.last_hashes.clone(), 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_used: self.block.receipts.last().map_or(U256::zero(), |r| r.gas_used),
gas_limit: self.block.base.header.gas_limit.clone(), gas_limit: self.block.base.header.gas_limit.clone(),
} }
@@ -327,31 +247,22 @@ impl<'x> OpenBlock<'x> {
/// ///
/// If valid, it will be executed, and archived together with the receipt. /// If valid, it will be executed, and archived together with the receipt.
pub fn push_transaction(&mut self, t: SignedTransaction, h: Option<H256>) -> Result<&Receipt, Error> { pub fn push_transaction(&mut self, t: SignedTransaction, h: Option<H256>) -> Result<&Receipt, Error> {
if self.block.transactions_set.contains(&t.hash()) {
return Err(From::from(TransactionError::AlreadyImported));
}
let env_info = self.env_info(); let env_info = self.env_info();
// info!("env_info says gas_used={}", env_info.gas_used); // info!("env_info says gas_used={}", env_info.gas_used);
match self.block.state.apply(&env_info, self.engine, self.vm_factory, &t, self.block.traces.is_some()) { match self.block.state.apply(&env_info, self.engine, &t) {
Ok(outcome) => { Ok(receipt) => {
self.block.transactions_set.insert(h.unwrap_or_else(||t.hash())); self.block.transactions_set.insert(h.unwrap_or_else(||t.hash()));
self.block.base.transactions.push(t); self.block.base.transactions.push(t);
let t = outcome.trace; self.block.receipts.push(receipt);
self.block.traces.as_mut().map(|traces| traces.push(t)); Ok(&self.block.receipts.last().unwrap())
self.block.receipts.push(outcome.receipt);
Ok(self.block.receipts.last().unwrap())
} }
Err(x) => Err(From::from(x)) Err(x) => Err(From::from(x))
} }
} }
/// Turn this into a `ClosedBlock`. A `BlockChain` must be provided in order to figure out the uncles. /// Turn this into a `ClosedBlock`. A BlockChain must be provided in order to figure out the uncles.
pub fn close(self) -> ClosedBlock { pub fn close(self) -> ClosedBlock {
let mut s = self; let mut s = self;
let unclosed_state = s.block.state.clone();
s.engine.on_close_block(&mut s.block); s.engine.on_close_block(&mut s.block);
s.block.base.header.transactions_root = ordered_trie_root(s.block.base.transactions.iter().map(|ref e| e.rlp_bytes().to_vec()).collect()); s.block.base.header.transactions_root = ordered_trie_root(s.block.base.transactions.iter().map(|ref e| e.rlp_bytes().to_vec()).collect());
let uncle_bytes = s.block.base.uncles.iter().fold(RlpStream::new_list(s.block.base.uncles.len()), |mut s, u| {s.append_raw(&u.rlp(Seal::With), 1); s} ).out(); let uncle_bytes = s.block.base.uncles.iter().fold(RlpStream::new_list(s.block.base.uncles.len()), |mut s, u| {s.append_raw(&u.rlp(Seal::With), 1); s} ).out();
@@ -365,40 +276,8 @@ impl<'x> OpenBlock<'x> {
ClosedBlock { ClosedBlock {
block: s.block, block: s.block,
uncle_bytes: uncle_bytes, uncle_bytes: uncle_bytes,
last_hashes: s.last_hashes,
unclosed_state: unclosed_state,
} }
} }
/// Turn this into a `LockedBlock`. A BlockChain must be provided in order to figure out the uncles.
pub fn close_and_lock(self) -> LockedBlock {
let mut s = self;
s.engine.on_close_block(&mut s.block);
if s.block.base.header.transactions_root.is_zero() || s.block.base.header.transactions_root == SHA3_NULL_RLP {
s.block.base.header.transactions_root = ordered_trie_root(s.block.base.transactions.iter().map(|ref e| e.rlp_bytes().to_vec()).collect());
}
let uncle_bytes = s.block.base.uncles.iter().fold(RlpStream::new_list(s.block.base.uncles.len()), |mut s, u| {s.append_raw(&u.rlp(Seal::With), 1); s} ).out();
if s.block.base.header.uncles_hash.is_zero() {
s.block.base.header.uncles_hash = uncle_bytes.sha3();
}
if s.block.base.header.receipts_root.is_zero() || s.block.base.header.receipts_root == SHA3_NULL_RLP {
s.block.base.header.receipts_root = ordered_trie_root(s.block.receipts.iter().map(|ref r| r.rlp_bytes().to_vec()).collect());
}
s.block.base.header.state_root = s.block.state.root().clone();
s.block.base.header.log_bloom = s.block.receipts.iter().fold(LogBloom::zero(), |mut b, r| {b = &b | &r.log_bloom; b}); //TODO: use |= operator
s.block.base.header.gas_used = s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used);
s.block.base.header.note_dirty();
LockedBlock {
block: s.block,
uncle_bytes: uncle_bytes,
}
}
#[cfg(test)]
/// Return mutable block reference. To be used in tests only.
pub fn block_mut (&mut self) -> &mut ExecutedBlock { &mut self.block }
} }
impl<'x> IsBlock for OpenBlock<'x> { impl<'x> IsBlock for OpenBlock<'x> {
@@ -409,40 +288,10 @@ impl<'x> IsBlock for ClosedBlock {
fn block(&self) -> &ExecutedBlock { &self.block } fn block(&self) -> &ExecutedBlock { &self.block }
} }
impl<'x> IsBlock for LockedBlock {
fn block(&self) -> &ExecutedBlock { &self.block }
}
impl ClosedBlock { impl ClosedBlock {
/// Get the hash of the header without seal arguments. /// Get the hash of the header without seal arguments.
pub fn hash(&self) -> H256 { self.header().rlp_sha3(Seal::Without) } pub fn hash(&self) -> H256 { self.header().rlp_sha3(Seal::Without) }
/// Turn this into a `LockedBlock`, unable to be reopened again.
pub fn lock(self) -> LockedBlock {
LockedBlock {
block: self.block,
uncle_bytes: self.uncle_bytes,
}
}
/// Given an engine reference, reopen the `ClosedBlock` into an `OpenBlock`.
pub fn reopen<'a>(self, engine: &'a Engine, vm_factory: &'a EvmFactory) -> OpenBlock<'a> {
// revert rewards (i.e. set state back at last transaction's state).
let mut block = self.block;
block.state = self.unclosed_state;
OpenBlock {
block: block,
engine: engine,
vm_factory: vm_factory,
last_hashes: self.last_hashes,
}
}
}
impl LockedBlock {
/// Get the hash of the header without seal arguments.
pub fn hash(&self) -> H256 { self.header().rlp_sha3(Seal::Without) }
/// Provide a valid seal in order to turn this into a `SealedBlock`. /// Provide a valid seal in order to turn this into a `SealedBlock`.
/// ///
/// NOTE: This does not check the validity of `seal` with the engine. /// NOTE: This does not check the validity of `seal` with the engine.
@@ -458,7 +307,7 @@ impl LockedBlock {
/// Provide a valid seal in order to turn this into a `SealedBlock`. /// Provide a valid seal in order to turn this into a `SealedBlock`.
/// This does check the validity of `seal` with the engine. /// This does check the validity of `seal` with the engine.
/// Returns the `ClosedBlock` back again if the seal is no good. /// Returns the `ClosedBlock` back again if the seal is no good.
pub fn try_seal(self, engine: &Engine, seal: Vec<Bytes>) -> Result<SealedBlock, LockedBlock> { pub fn try_seal(self, engine: &Engine, seal: Vec<Bytes>) -> Result<SealedBlock, ClosedBlock> {
let mut s = self; let mut s = self;
s.block.base.header.set_seal(seal); s.block.base.header.set_seal(seal);
match engine.verify_block_seal(&s.block.base.header) { match engine.verify_block_seal(&s.block.base.header) {
@@ -466,13 +315,9 @@ impl LockedBlock {
_ => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }), _ => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }),
} }
} }
}
impl Drain for LockedBlock {
/// Drop this object and return the underlieing database. /// Drop this object and return the underlieing database.
fn drain(self) -> StateDB { pub fn drain(self) -> Box<JournalDB> { self.block.state.drop().1 }
self.block.state.drop().1
}
} }
impl SealedBlock { impl SealedBlock {
@@ -484,13 +329,9 @@ impl SealedBlock {
block_rlp.append_raw(&self.uncle_bytes, 1); block_rlp.append_raw(&self.uncle_bytes, 1);
block_rlp.out() block_rlp.out()
} }
}
impl Drain for SealedBlock {
/// Drop this object and return the underlieing database. /// Drop this object and return the underlieing database.
fn drain(self) -> StateDB { pub fn drain(self) -> Box<JournalDB> { self.block.state.drop().1 }
self.block.state.drop().1
}
} }
impl IsBlock for SealedBlock { impl IsBlock for SealedBlock {
@@ -498,87 +339,40 @@ impl IsBlock for SealedBlock {
} }
/// Enact the block given by block header, transactions and uncles /// Enact the block given by block header, transactions and uncles
#[cfg_attr(feature="dev", allow(too_many_arguments))] pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes) -> Result<ClosedBlock, Error> {
pub fn enact(
header: &Header,
transactions: &[SignedTransaction],
uncles: &[Header],
engine: &Engine,
tracing: bool,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
vm_factory: &EvmFactory,
trie_factory: TrieFactory,
) -> Result<LockedBlock, Error> {
{ {
if ::log::max_log_level() >= ::log::LogLevel::Trace { if ::log::max_log_level() >= ::log::LogLevel::Trace {
let s = try!(State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce(), trie_factory.clone())); let s = State::from_existing(db.spawn(), parent.state_root().clone(), engine.account_start_nonce());
trace!(target: "enact", "num={}, root={}, author={}, author_balance={}\n", header.number(), s.root(), header.author(), s.balance(&header.author())); trace!("enact(): root={}, author={}, author_balance={}\n", s.root(), header.author(), s.balance(&header.author()));
} }
} }
let mut b = try!(OpenBlock::new(engine, vm_factory, trie_factory, tracing, db, parent, last_hashes, Address::new(), (3141562.into(), 31415620.into()), vec![])); let mut b = OpenBlock::new(engine, db, parent, last_hashes, header.author().clone(), x!(3141562), header.extra_data().clone());
b.set_difficulty(*header.difficulty()); b.set_difficulty(*header.difficulty());
b.set_gas_limit(*header.gas_limit()); b.set_gas_limit(*header.gas_limit());
b.set_timestamp(header.timestamp()); 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));
b.set_uncles_hash(header.uncles_hash().clone());
b.set_transactions_root(header.transactions_root().clone());
b.set_receipts_root(header.receipts_root().clone());
for t in transactions { try!(b.push_transaction(t.clone(), None)); } for t in transactions { try!(b.push_transaction(t.clone(), None)); }
for u in uncles { try!(b.push_uncle(u.clone())); } for u in uncles { try!(b.push_uncle(u.clone())); }
Ok(b.close_and_lock()) Ok(b.close())
} }
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
#[cfg_attr(feature="dev", allow(too_many_arguments))] pub fn enact_bytes(block_bytes: &[u8], engine: &Engine, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes) -> Result<ClosedBlock, Error> {
pub fn enact_bytes(
block_bytes: &[u8],
engine: &Engine,
tracing: bool,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
vm_factory: &EvmFactory,
trie_factory: TrieFactory,
) -> Result<LockedBlock, Error> {
let block = BlockView::new(block_bytes); let block = BlockView::new(block_bytes);
let header = block.header(); let header = block.header();
enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes, vm_factory, trie_factory) enact(&header, &block.transactions(), &block.uncles(), engine, db, parent, last_hashes)
} }
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
#[cfg_attr(feature="dev", allow(too_many_arguments))] pub fn enact_verified(block: &PreverifiedBlock, engine: &Engine, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes) -> Result<ClosedBlock, Error> {
pub fn enact_verified(
block: &PreverifiedBlock,
engine: &Engine,
tracing: bool,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
vm_factory: &EvmFactory,
trie_factory: TrieFactory,
) -> Result<LockedBlock, Error> {
let view = BlockView::new(&block.bytes); let view = BlockView::new(&block.bytes);
enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, vm_factory, trie_factory) enact(&block.header, &block.transactions, &view.uncles(), engine, db, parent, last_hashes)
} }
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards
#[cfg_attr(feature="dev", allow(too_many_arguments))] pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes) -> Result<SealedBlock, Error> {
pub fn enact_and_seal(
block_bytes: &[u8],
engine: &Engine,
tracing: bool,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
vm_factory: &EvmFactory,
trie_factory: TrieFactory,
) -> Result<SealedBlock, Error> {
let header = BlockView::new(block_bytes).header_view(); let header = BlockView::new(block_bytes).header_view();
Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, vm_factory, trie_factory)).seal(engine, header.seal()))) Ok(try!(try!(enact_bytes(block_bytes, engine, db, parent, last_hashes)).seal(engine, header.seal())))
} }
#[cfg(test)] #[cfg(test)]
@@ -586,79 +380,72 @@ mod tests {
use tests::helpers::*; use tests::helpers::*;
use super::*; use super::*;
use common::*; use common::*;
use engine::*;
#[test] #[test]
fn open_block() { fn open_block() {
use spec::*; use spec::*;
let spec = Spec::new_test(); let engine = Spec::new_test().to_engine().unwrap();
let genesis_header = spec.genesis_header(); let genesis_header = engine.spec().genesis_header();
let mut db_result = get_temp_state_db(); let mut db_result = get_temp_journal_db();
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(&mut db).unwrap(); engine.spec().ensure_db_good(db.as_hashdb_mut());
let last_hashes = Arc::new(vec![genesis_header.hash()]); let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default(); let b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]);
let b = OpenBlock::new(&*spec.engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = b.close();
let b = b.close_and_lock(); let _ = b.seal(engine.deref(), vec![]);
let _ = b.seal(&*spec.engine, vec![]);
} }
#[test] #[test]
fn enact_block() { fn enact_block() {
use spec::*; use spec::*;
let spec = Spec::new_test(); let engine = Spec::new_test().to_engine().unwrap();
let engine = &*spec.engine; let genesis_header = engine.spec().genesis_header();
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_state_db(); let mut db_result = get_temp_journal_db();
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(&mut db).unwrap(); engine.spec().ensure_db_good(db.as_hashdb_mut());
let vm_factory = Default::default(); let b = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()], Address::zero(), x!(3141562), vec![]).close().seal(engine.deref(), vec![]).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let b = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap()
.close_and_lock().seal(engine, vec![]).unwrap();
let orig_bytes = b.rlp_bytes(); let orig_bytes = b.rlp_bytes();
let orig_db = b.drain(); let orig_db = b.drain();
let mut db_result = get_temp_state_db(); let mut db_result = get_temp_journal_db();
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(&mut db).unwrap(); engine.spec().ensure_db_good(db.as_hashdb_mut());
let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, &Default::default(), Default::default()).unwrap(); let e = enact_and_seal(&orig_bytes, engine.deref(), db, &genesis_header, vec![genesis_header.hash()]).unwrap();
assert_eq!(e.rlp_bytes(), orig_bytes); assert_eq!(e.rlp_bytes(), orig_bytes);
let db = e.drain(); let db = e.drain();
assert_eq!(orig_db.journal_db().keys(), db.journal_db().keys()); assert_eq!(orig_db.keys(), db.keys());
assert!(orig_db.journal_db().keys().iter().filter(|k| orig_db.journal_db().get(k.0) != db.journal_db().get(k.0)).next() == None); assert!(orig_db.keys().iter().filter(|k| orig_db.get(k.0) != db.get(k.0)).next() == None);
} }
#[test] #[test]
fn enact_block_with_uncle() { fn enact_block_with_uncle() {
use spec::*; use spec::*;
let spec = Spec::new_test(); let engine = Spec::new_test().to_engine().unwrap();
let engine = &*spec.engine; let genesis_header = engine.spec().genesis_header();
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_state_db(); let mut db_result = get_temp_journal_db();
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(&mut db).unwrap(); engine.spec().ensure_db_good(db.as_hashdb_mut());
let vm_factory = Default::default(); let mut open_block = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()], Address::zero(), x!(3141562), vec![]);
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let mut open_block = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut uncle1_header = Header::new(); let mut uncle1_header = Header::new();
uncle1_header.extra_data = b"uncle1".to_vec(); uncle1_header.extra_data = b"uncle1".to_vec();
let mut uncle2_header = Header::new(); let mut uncle2_header = Header::new();
uncle2_header.extra_data = b"uncle2".to_vec(); uncle2_header.extra_data = b"uncle2".to_vec();
open_block.push_uncle(uncle1_header).unwrap(); open_block.push_uncle(uncle1_header).unwrap();
open_block.push_uncle(uncle2_header).unwrap(); open_block.push_uncle(uncle2_header).unwrap();
let b = open_block.close_and_lock().seal(engine, vec![]).unwrap(); let b = open_block.close().seal(engine.deref(), vec![]).unwrap();
let orig_bytes = b.rlp_bytes(); let orig_bytes = b.rlp_bytes();
let orig_db = b.drain(); let orig_db = b.drain();
let mut db_result = get_temp_state_db(); let mut db_result = get_temp_journal_db();
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(&mut db).unwrap(); engine.spec().ensure_db_good(db.as_hashdb_mut());
let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, &Default::default(), Default::default()).unwrap(); let e = enact_and_seal(&orig_bytes, engine.deref(), db, &genesis_header, vec![genesis_header.hash()]).unwrap();
let bytes = e.rlp_bytes(); let bytes = e.rlp_bytes();
assert_eq!(bytes, orig_bytes); assert_eq!(bytes, orig_bytes);
@@ -666,7 +453,7 @@ mod tests {
assert_eq!(uncles[1].extra_data, b"uncle2"); assert_eq!(uncles[1].extra_data, b"uncle2");
let db = e.drain(); let db = e.drain();
assert_eq!(orig_db.journal_db().keys(), db.journal_db().keys()); assert_eq!(orig_db.keys(), db.keys());
assert!(orig_db.journal_db().keys().iter().filter(|k| orig_db.journal_db().get(k.0) != db.journal_db().get(k.0)).next() == None); assert!(orig_db.keys().iter().filter(|k| orig_db.get(k.0) != db.get(k.0)).next() == None);
} }
} }

View File

@@ -14,22 +14,19 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! A queue of blocks. Sits between network or other I/O and the `BlockChain`. //! A queue of blocks. Sits between network or other I/O and the BlockChain.
//! Sorts them ready for blockchain insertion. //! Sorts them ready for blockchain insertion.
use std::thread::{JoinHandle, self}; use std::thread::{JoinHandle, self};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering as AtomicOrdering}; use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering};
use std::sync::{Condvar as SCondvar, Mutex as SMutex};
use util::*; use util::*;
use io::*;
use verification::*; use verification::*;
use error::*; use error::*;
use engines::Engine; use engine::Engine;
use views::*; use views::*;
use header::*; use header::*;
use service::*; use service::*;
use client::BlockStatus; use client::BlockStatus;
use util::panics::*;
pub use types::block_queue_info::BlockQueueInfo;
known_heap_size!(0, UnverifiedBlock, VerifyingBlock, PreverifiedBlock); known_heap_size!(0, UnverifiedBlock, VerifyingBlock, PreverifiedBlock);
@@ -37,7 +34,7 @@ const MIN_MEM_LIMIT: usize = 16384;
const MIN_QUEUE_LIMIT: usize = 512; const MIN_QUEUE_LIMIT: usize = 512;
/// Block queue configuration /// Block queue configuration
#[derive(Debug, PartialEq)] #[derive(Debug)]
pub struct BlockQueueConfig { pub struct BlockQueueConfig {
/// Maximum number of blocks to keep in unverified queue. /// Maximum number of blocks to keep in unverified queue.
/// When the limit is reached, is_full returns true. /// When the limit is reached, is_full returns true.
@@ -56,6 +53,22 @@ impl Default for BlockQueueConfig {
} }
} }
/// Block queue status
#[derive(Debug)]
pub struct BlockQueueInfo {
/// Number of queued blocks pending verification
pub unverified_queue_size: usize,
/// Number of verified queued blocks pending import
pub verified_queue_size: usize,
/// Number of blocks being verified
pub verifying_queue_size: usize,
/// Configured maximum number of blocks in the queue
pub max_queue_size: usize,
/// Configured maximum number of bytes to use
pub max_mem_use: usize,
/// Heap memory used in bytes
pub mem_used: usize,
}
impl BlockQueueInfo { impl BlockQueueInfo {
/// The total size of the queues. /// The total size of the queues.
@@ -76,24 +89,17 @@ impl BlockQueueInfo {
} }
} }
// the internal queue sizes. /// A queue of blocks. Sits between network or other I/O and the BlockChain.
struct Sizes {
unverified: AtomicUsize,
verifying: AtomicUsize,
verified: AtomicUsize,
}
/// A queue of blocks. Sits between network or other I/O and the `BlockChain`.
/// Sorts them ready for blockchain insertion. /// Sorts them ready for blockchain insertion.
pub struct BlockQueue { pub struct BlockQueue {
panic_handler: Arc<PanicHandler>, panic_handler: Arc<PanicHandler>,
engine: Arc<Engine>, engine: Arc<Box<Engine>>,
more_to_verify: Arc<SCondvar>, more_to_verify: Arc<Condvar>,
verification: Arc<Verification>, verification: Arc<Verification>,
verifiers: Vec<JoinHandle<()>>, verifiers: Vec<JoinHandle<()>>,
deleting: Arc<AtomicBool>, deleting: Arc<AtomicBool>,
ready_signal: Arc<QueueSignal>, ready_signal: Arc<QueueSignal>,
empty: Arc<SCondvar>, empty: Arc<Condvar>,
processing: RwLock<HashSet<H256>>, processing: RwLock<HashSet<H256>>,
max_queue_size: usize, max_queue_size: usize,
max_mem_use: usize, max_mem_use: usize,
@@ -112,35 +118,19 @@ struct VerifyingBlock {
struct QueueSignal { struct QueueSignal {
deleting: Arc<AtomicBool>, deleting: Arc<AtomicBool>,
signalled: AtomicBool, signalled: AtomicBool,
message_channel: IoChannel<ClientIoMessage>, message_channel: IoChannel<NetSyncMessage>,
} }
impl QueueSignal { impl QueueSignal {
#[cfg_attr(feature="dev", allow(bool_comparison))] #[cfg_attr(feature="dev", allow(bool_comparison))]
fn set_sync(&self) { fn set(&self) {
// Do not signal when we are about to close // Do not signal when we are about to close
if self.deleting.load(AtomicOrdering::Relaxed) { if self.deleting.load(AtomicOrdering::Relaxed) {
return; return;
} }
if self.signalled.compare_and_swap(false, true, AtomicOrdering::Relaxed) == false { if self.signalled.compare_and_swap(false, true, AtomicOrdering::Relaxed) == false {
if let Err(e) = self.message_channel.send_sync(ClientIoMessage::BlockVerified) { self.message_channel.send(UserMessage(SyncMessage::BlockVerified)).expect("Error sending BlockVerified message");
debug!("Error sending BlockVerified message: {:?}", e);
}
}
}
#[cfg_attr(feature="dev", allow(bool_comparison))]
fn set_async(&self) {
// Do not signal when we are about to close
if self.deleting.load(AtomicOrdering::Relaxed) {
return;
}
if self.signalled.compare_and_swap(false, true, AtomicOrdering::Relaxed) == false {
if let Err(e) = self.message_channel.send(ClientIoMessage::BlockVerified) {
debug!("Error sending BlockVerified message: {:?}", e);
}
} }
} }
@@ -152,38 +142,28 @@ impl QueueSignal {
struct Verification { struct Verification {
// All locks must be captured in the order declared here. // All locks must be captured in the order declared here.
unverified: Mutex<VecDeque<UnverifiedBlock>>, unverified: Mutex<VecDeque<UnverifiedBlock>>,
verifying: Mutex<VecDeque<VerifyingBlock>>,
verified: Mutex<VecDeque<PreverifiedBlock>>, verified: Mutex<VecDeque<PreverifiedBlock>>,
verifying: Mutex<VecDeque<VerifyingBlock>>,
bad: Mutex<HashSet<H256>>, bad: Mutex<HashSet<H256>>,
more_to_verify: SMutex<()>,
empty: SMutex<()>,
sizes: Sizes,
} }
impl BlockQueue { impl BlockQueue {
/// Creates a new queue instance. /// Creates a new queue instance.
pub fn new(config: BlockQueueConfig, engine: Arc<Engine>, message_channel: IoChannel<ClientIoMessage>) -> BlockQueue { pub fn new(config: BlockQueueConfig, engine: Arc<Box<Engine>>, message_channel: IoChannel<NetSyncMessage>) -> BlockQueue {
let verification = Arc::new(Verification { let verification = Arc::new(Verification {
unverified: Mutex::new(VecDeque::new()), unverified: Mutex::new(VecDeque::new()),
verifying: Mutex::new(VecDeque::new()),
verified: Mutex::new(VecDeque::new()), verified: Mutex::new(VecDeque::new()),
verifying: Mutex::new(VecDeque::new()),
bad: Mutex::new(HashSet::new()), bad: Mutex::new(HashSet::new()),
more_to_verify: SMutex::new(()),
empty: SMutex::new(()),
sizes: Sizes {
unverified: AtomicUsize::new(0),
verifying: AtomicUsize::new(0),
verified: AtomicUsize::new(0),
}
}); });
let more_to_verify = Arc::new(SCondvar::new()); let more_to_verify = Arc::new(Condvar::new());
let deleting = Arc::new(AtomicBool::new(false)); let deleting = Arc::new(AtomicBool::new(false));
let ready_signal = Arc::new(QueueSignal { let ready_signal = Arc::new(QueueSignal {
deleting: deleting.clone(), deleting: deleting.clone(),
signalled: AtomicBool::new(false), signalled: AtomicBool::new(false),
message_channel: message_channel message_channel: message_channel
}); });
let empty = Arc::new(SCondvar::new()); let empty = Arc::new(Condvar::new());
let panic_handler = PanicHandler::new_in_arc(); let panic_handler = PanicHandler::new_in_arc();
let mut verifiers: Vec<JoinHandle<()>> = Vec::new(); let mut verifiers: Vec<JoinHandle<()>> = Vec::new();
@@ -222,17 +202,17 @@ impl BlockQueue {
} }
} }
fn verify(verification: Arc<Verification>, engine: Arc<Engine>, wait: Arc<SCondvar>, ready: Arc<QueueSignal>, deleting: Arc<AtomicBool>, empty: Arc<SCondvar>) { fn verify(verification: Arc<Verification>, engine: Arc<Box<Engine>>, wait: Arc<Condvar>, ready: Arc<QueueSignal>, deleting: Arc<AtomicBool>, empty: Arc<Condvar>) {
while !deleting.load(AtomicOrdering::Acquire) { while !deleting.load(AtomicOrdering::Acquire) {
{ {
let mut more_to_verify = verification.more_to_verify.lock().unwrap(); let mut unverified = verification.unverified.lock().unwrap();
if verification.unverified.lock().is_empty() && verification.verifying.lock().is_empty() { if unverified.is_empty() && verification.verifying.lock().unwrap().is_empty() {
empty.notify_all(); empty.notify_all();
} }
while verification.unverified.lock().is_empty() && !deleting.load(AtomicOrdering::Acquire) { while unverified.is_empty() && !deleting.load(AtomicOrdering::Acquire) {
more_to_verify = wait.wait(more_to_verify).unwrap(); unverified = wait.wait(unverified).unwrap();
} }
if deleting.load(AtomicOrdering::Acquire) { if deleting.load(AtomicOrdering::Acquire) {
@@ -241,111 +221,85 @@ impl BlockQueue {
} }
let block = { let block = {
let mut unverified = verification.unverified.lock(); let mut unverified = verification.unverified.lock().unwrap();
if unverified.is_empty() { if unverified.is_empty() {
continue; continue;
} }
let mut verifying = verification.verifying.lock(); let mut verifying = verification.verifying.lock().unwrap();
let block = unverified.pop_front().unwrap(); let block = unverified.pop_front().unwrap();
verification.sizes.unverified.fetch_sub(block.heap_size_of_children(), AtomicOrdering::SeqCst);
verifying.push_back(VerifyingBlock{ hash: block.header.hash(), block: None }); verifying.push_back(VerifyingBlock{ hash: block.header.hash(), block: None });
block block
}; };
let block_hash = block.header.hash(); let block_hash = block.header.hash();
let is_ready = match verify_block_unordered(block.header, block.bytes, &*engine) { match verify_block_unordered(block.header, block.bytes, engine.deref().deref()) {
Ok(verified) => { Ok(verified) => {
let mut verifying = verification.verifying.lock(); let mut verifying = verification.verifying.lock().unwrap();
for e in verifying.iter_mut() { for e in verifying.iter_mut() {
if e.hash == block_hash { if e.hash == block_hash {
verification.sizes.verifying.fetch_add(verified.heap_size_of_children(), AtomicOrdering::SeqCst);
e.block = Some(verified); e.block = Some(verified);
break; break;
} }
} }
if !verifying.is_empty() && verifying.front().unwrap().hash == block_hash { if !verifying.is_empty() && verifying.front().unwrap().hash == block_hash {
// we're next! // we're next!
let mut verified = verification.verified.lock(); let mut verified = verification.verified.lock().unwrap();
let mut bad = verification.bad.lock(); let mut bad = verification.bad.lock().unwrap();
BlockQueue::drain_verifying(&mut verifying, &mut verified, &mut bad, &verification.sizes); BlockQueue::drain_verifying(&mut verifying, &mut verified, &mut bad);
true ready.set();
} else {
false
} }
}, },
Err(err) => { Err(err) => {
let mut verifying = verification.verifying.lock(); let mut verifying = verification.verifying.lock().unwrap();
let mut verified = verification.verified.lock(); let mut verified = verification.verified.lock().unwrap();
let mut bad = verification.bad.lock(); let mut bad = verification.bad.lock().unwrap();
warn!(target: "client", "Stage 2 block verification failed for {}\nError: {:?}", block_hash, err); warn!(target: "client", "Stage 2 block verification failed for {}\nError: {:?}", block_hash, err);
bad.insert(block_hash.clone()); bad.insert(block_hash.clone());
verifying.retain(|e| e.hash != block_hash); verifying.retain(|e| e.hash != block_hash);
if !verifying.is_empty() && verifying.front().unwrap().hash == block_hash { BlockQueue::drain_verifying(&mut verifying, &mut verified, &mut bad);
BlockQueue::drain_verifying(&mut verifying, &mut verified, &mut bad, &verification.sizes); ready.set();
true
} else {
false
}
} }
};
if is_ready {
// Import the block immediately
ready.set_sync();
} }
} }
} }
fn drain_verifying(verifying: &mut VecDeque<VerifyingBlock>, verified: &mut VecDeque<PreverifiedBlock>, bad: &mut HashSet<H256>, sizes: &Sizes) { fn drain_verifying(verifying: &mut VecDeque<VerifyingBlock>, verified: &mut VecDeque<PreverifiedBlock>, bad: &mut HashSet<H256>) {
let mut removed_size = 0;
let mut inserted_size = 0;
while !verifying.is_empty() && verifying.front().unwrap().block.is_some() { while !verifying.is_empty() && verifying.front().unwrap().block.is_some() {
let block = verifying.pop_front().unwrap().block.unwrap(); let block = verifying.pop_front().unwrap().block.unwrap();
let size = block.heap_size_of_children(); if bad.contains(&block.header.parent_hash) {
removed_size += size;
if bad.contains(&block.header.parent_hash()) {
bad.insert(block.header.hash()); bad.insert(block.header.hash());
} else { }
inserted_size += size; else {
verified.push_back(block); verified.push_back(block);
} }
} }
sizes.verifying.fetch_sub(removed_size, AtomicOrdering::SeqCst);
sizes.verified.fetch_add(inserted_size, AtomicOrdering::SeqCst);
} }
/// Clear the queue and stop verification activity. /// Clear the queue and stop verification activity.
pub fn clear(&self) { pub fn clear(&self) {
let mut unverified = self.verification.unverified.lock(); let mut unverified = self.verification.unverified.lock().unwrap();
let mut verifying = self.verification.verifying.lock(); let mut verifying = self.verification.verifying.lock().unwrap();
let mut verified = self.verification.verified.lock(); let mut verified = self.verification.verified.lock().unwrap();
unverified.clear(); unverified.clear();
verifying.clear(); verifying.clear();
verified.clear(); verified.clear();
self.processing.write().unwrap().clear();
let sizes = &self.verification.sizes;
sizes.unverified.store(0, AtomicOrdering::Release);
sizes.verifying.store(0, AtomicOrdering::Release);
sizes.verified.store(0, AtomicOrdering::Release);
self.processing.write().clear();
} }
/// Wait for unverified queue to be empty /// Wait for unverified queue to be empty
pub fn flush(&self) { pub fn flush(&self) {
let mut lock = self.verification.empty.lock().unwrap(); let mut unverified = self.verification.unverified.lock().unwrap();
while !self.verification.unverified.lock().is_empty() || !self.verification.verifying.lock().is_empty() { while !unverified.is_empty() || !self.verification.verifying.lock().unwrap().is_empty() {
lock = self.empty.wait(lock).unwrap(); unverified = self.empty.wait(unverified).unwrap();
} }
} }
/// Check if the block is currently in the queue /// Check if the block is currently in the queue
pub fn block_status(&self, hash: &H256) -> BlockStatus { pub fn block_status(&self, hash: &H256) -> BlockStatus {
if self.processing.read().contains(hash) { if self.processing.read().unwrap().contains(&hash) {
return BlockStatus::Queued; return BlockStatus::Queued;
} }
if self.verification.bad.lock().contains(hash) { if self.verification.bad.lock().unwrap().contains(&hash) {
return BlockStatus::Bad; return BlockStatus::Bad;
} }
BlockStatus::Unknown BlockStatus::Unknown
@@ -356,33 +310,31 @@ impl BlockQueue {
let header = BlockView::new(&bytes).header(); let header = BlockView::new(&bytes).header();
let h = header.hash(); let h = header.hash();
{ {
if self.processing.read().contains(&h) { if self.processing.read().unwrap().contains(&h) {
return Err(ImportError::AlreadyQueued.into()); return Err(x!(ImportError::AlreadyQueued));
} }
let mut bad = self.verification.bad.lock(); let mut bad = self.verification.bad.lock().unwrap();
if bad.contains(&h) { if bad.contains(&h) {
return Err(ImportError::KnownBad.into()); return Err(x!(ImportError::KnownBad));
} }
if bad.contains(&header.parent_hash) { if bad.contains(&header.parent_hash) {
bad.insert(h.clone()); bad.insert(h.clone());
return Err(ImportError::KnownBad.into()); return Err(x!(ImportError::KnownBad));
} }
} }
match verify_block_basic(&header, &bytes, &*self.engine) { match verify_block_basic(&header, &bytes, self.engine.deref().deref()) {
Ok(()) => { Ok(()) => {
self.processing.write().insert(h.clone()); self.processing.write().unwrap().insert(h.clone());
let block = UnverifiedBlock { header: header, bytes: bytes }; self.verification.unverified.lock().unwrap().push_back(UnverifiedBlock { header: header, bytes: bytes });
self.verification.sizes.unverified.fetch_add(block.heap_size_of_children(), AtomicOrdering::SeqCst);
self.verification.unverified.lock().push_back(block);
self.more_to_verify.notify_all(); self.more_to_verify.notify_all();
Ok(h) Ok(h)
}, },
Err(err) => { Err(err) => {
warn!(target: "client", "Stage 1 block verification failed for {}\nError: {:?}", BlockView::new(&bytes).header_view().sha3(), err); warn!(target: "client", "Stage 1 block verification failed for {}\nError: {:?}", BlockView::new(&bytes).header_view().sha3(), err);
self.verification.bad.lock().insert(h.clone()); self.verification.bad.lock().unwrap().insert(h.clone());
Err(err) Err(err)
} }
} }
@@ -393,80 +345,68 @@ impl BlockQueue {
if block_hashes.is_empty() { if block_hashes.is_empty() {
return; return;
} }
let mut verified_lock = self.verification.verified.lock(); let mut verified_lock = self.verification.verified.lock().unwrap();
let mut verified = &mut *verified_lock; let mut verified = verified_lock.deref_mut();
let mut bad = self.verification.bad.lock(); let mut bad = self.verification.bad.lock().unwrap();
let mut processing = self.processing.write(); let mut processing = self.processing.write().unwrap();
bad.reserve(block_hashes.len()); bad.reserve(block_hashes.len());
for hash in block_hashes { for hash in block_hashes {
bad.insert(hash.clone()); bad.insert(hash.clone());
processing.remove(hash); processing.remove(&hash);
} }
let mut new_verified = VecDeque::new(); let mut new_verified = VecDeque::new();
let mut removed_size = 0;
for block in verified.drain(..) { for block in verified.drain(..) {
if bad.contains(&block.header.parent_hash) { if bad.contains(&block.header.parent_hash) {
removed_size += block.heap_size_of_children();
bad.insert(block.header.hash()); bad.insert(block.header.hash());
processing.remove(&block.header.hash()); processing.remove(&block.header.hash());
} else { } else {
new_verified.push_back(block); new_verified.push_back(block);
} }
} }
self.verification.sizes.verified.fetch_sub(removed_size, AtomicOrdering::SeqCst);
*verified = new_verified; *verified = new_verified;
} }
/// Mark given item as processed. /// Mark given block as processed
/// Returns true if the queue becomes empty. pub fn mark_as_good(&self, block_hashes: &[H256]) {
pub fn mark_as_good(&self, hashes: &[H256]) -> bool { if block_hashes.is_empty() {
if hashes.is_empty() { return;
return self.processing.read().is_empty();
} }
let mut processing = self.processing.write(); let mut processing = self.processing.write().unwrap();
for hash in hashes { for hash in block_hashes {
processing.remove(hash); processing.remove(&hash);
} }
processing.is_empty()
} }
/// Removes up to `max` verified blocks from the queue /// Removes up to `max` verified blocks from the queue
pub fn drain(&self, max: usize) -> Vec<PreverifiedBlock> { pub fn drain(&self, max: usize) -> Vec<PreverifiedBlock> {
let mut verified = self.verification.verified.lock(); let mut verified = self.verification.verified.lock().unwrap();
let count = min(max, verified.len()); let count = min(max, verified.len());
let mut result = Vec::with_capacity(count); let mut result = Vec::with_capacity(count);
for _ in 0..count { for _ in 0..count {
let block = verified.pop_front().unwrap(); let block = verified.pop_front().unwrap();
self.verification.sizes.verified.fetch_sub(block.heap_size_of_children(), AtomicOrdering::SeqCst);
result.push(block); result.push(block);
} }
self.ready_signal.reset(); self.ready_signal.reset();
if !verified.is_empty() { if !verified.is_empty() {
self.ready_signal.set_async(); self.ready_signal.set();
} }
result result
} }
/// Get queue status. /// Get queue status.
pub fn queue_info(&self) -> BlockQueueInfo { pub fn queue_info(&self) -> BlockQueueInfo {
use std::mem::size_of;
let (unverified_len, unverified_bytes) = { let (unverified_len, unverified_bytes) = {
let len = self.verification.unverified.lock().len(); let v = self.verification.unverified.lock().unwrap();
let size = self.verification.sizes.unverified.load(AtomicOrdering::Acquire); (v.len(), v.heap_size_of_children())
(len, size + len * size_of::<UnverifiedBlock>())
}; };
let (verifying_len, verifying_bytes) = { let (verifying_len, verifying_bytes) = {
let len = self.verification.verifying.lock().len(); let v = self.verification.verifying.lock().unwrap();
let size = self.verification.sizes.verifying.load(AtomicOrdering::Acquire); (v.len(), v.heap_size_of_children())
(len, size + len * size_of::<VerifyingBlock>())
}; };
let (verified_len, verified_bytes) = { let (verified_len, verified_bytes) = {
let len = self.verification.verified.lock().len(); let v = self.verification.verified.lock().unwrap();
let size = self.verification.sizes.verified.load(AtomicOrdering::Acquire); (v.len(), v.heap_size_of_children())
(len, size + len * size_of::<PreverifiedBlock>())
}; };
BlockQueueInfo { BlockQueueInfo {
unverified_queue_size: unverified_len, unverified_queue_size: unverified_len,
@@ -474,20 +414,23 @@ impl BlockQueue {
verified_queue_size: verified_len, verified_queue_size: verified_len,
max_queue_size: self.max_queue_size, max_queue_size: self.max_queue_size,
max_mem_use: self.max_mem_use, max_mem_use: self.max_mem_use,
mem_used: unverified_bytes mem_used:
+ verifying_bytes unverified_bytes
+ verified_bytes + verifying_bytes
+ verified_bytes
// TODO: https://github.com/servo/heapsize/pull/50
//+ self.processing.read().unwrap().heap_size_of_children(),
} }
} }
/// Optimise memory footprint of the heap fields. /// Optimise memory footprint of the heap fields.
pub fn collect_garbage(&self) { pub fn collect_garbage(&self) {
{ {
self.verification.unverified.lock().shrink_to_fit(); self.verification.unverified.lock().unwrap().shrink_to_fit();
self.verification.verifying.lock().shrink_to_fit(); self.verification.verifying.lock().unwrap().shrink_to_fit();
self.verification.verified.lock().shrink_to_fit(); self.verification.verified.lock().unwrap().shrink_to_fit();
} }
self.processing.write().shrink_to_fit(); self.processing.write().unwrap().shrink_to_fit();
} }
} }
@@ -513,7 +456,6 @@ impl Drop for BlockQueue {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use util::*; use util::*;
use io::*;
use spec::*; use spec::*;
use block_queue::*; use block_queue::*;
use tests::helpers::*; use tests::helpers::*;
@@ -522,16 +464,16 @@ mod tests {
fn get_test_queue() -> BlockQueue { fn get_test_queue() -> BlockQueue {
let spec = get_test_spec(); let spec = get_test_spec();
let engine = spec.engine; let engine = spec.to_engine().unwrap();
BlockQueue::new(BlockQueueConfig::default(), engine, IoChannel::disconnected()) BlockQueue::new(BlockQueueConfig::default(), Arc::new(engine), IoChannel::disconnected())
} }
#[test] #[test]
fn can_be_created() { fn can_be_created() {
// TODO better test // TODO better test
let spec = Spec::new_test(); let spec = Spec::new_test();
let engine = spec.engine; let engine = spec.to_engine().unwrap();
let _ = BlockQueue::new(BlockQueueConfig::default(), engine, IoChannel::disconnected()); let _ = BlockQueue::new(BlockQueueConfig::default(), Arc::new(engine), IoChannel::disconnected());
} }
#[test] #[test]
@@ -591,10 +533,10 @@ mod tests {
#[test] #[test]
fn test_mem_limit() { fn test_mem_limit() {
let spec = get_test_spec(); let spec = get_test_spec();
let engine = spec.engine; let engine = spec.to_engine().unwrap();
let mut config = BlockQueueConfig::default(); let mut config = BlockQueueConfig::default();
config.max_mem_use = super::MIN_MEM_LIMIT; // empty queue uses about 15000 config.max_mem_use = super::MIN_MEM_LIMIT; // empty queue uses about 15000
let queue = BlockQueue::new(config, engine, IoChannel::disconnected()); let queue = BlockQueue::new(config, Arc::new(engine), IoChannel::disconnected());
assert!(!queue.queue_info().is_full()); assert!(!queue.queue_info().is_full());
let mut blocks = get_good_dummy_block_seq(50); let mut blocks = get_good_dummy_block_seq(50);
for b in blocks.drain(..) { for b in blocks.drain(..) {

View File

@@ -14,7 +14,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use util::bytes::Bytes;
use util::numbers::{U256,H256}; use util::numbers::{U256,H256};
use header::BlockNumber; use header::BlockNumber;
@@ -26,7 +25,5 @@ pub struct BestBlock {
/// Best block number. /// Best block number.
pub number: BlockNumber, pub number: BlockNumber,
/// Best block total difficulty. /// Best block total difficulty.
pub total_difficulty: U256, pub total_difficulty: U256
/// Best block uncompressed bytes
pub block: Bytes,
} }

View File

@@ -31,24 +31,21 @@ pub struct BlockInfo {
} }
/// Describes location of newly inserted block. /// Describes location of newly inserted block.
#[derive(Debug, Clone)] #[derive(Clone)]
pub enum BlockLocation { pub enum BlockLocation {
/// It's part of the canon chain. /// It's part of the canon chain.
CanonChain, CanonChain,
/// It's not a part of the canon chain. /// It's not a part of the canon chain.
Branch, Branch,
/// It's part of the fork which should become canon chain, /// It's part of the fork which should become canon chain,
/// because its total difficulty is higher than current /// because it's total difficulty is higher than current
/// canon chain difficulty. /// canon chain difficulty.
BranchBecomingCanonChain(BranchBecomingCanonChainData), BranchBecomingCanonChain {
} /// Hash of the newest common ancestor with old canon chain.
ancestor: H256,
#[derive(Debug, Clone)] /// Hashes of the blocks between ancestor and this block.
pub struct BranchBecomingCanonChainData { enacted: Vec<H256>,
/// Hash of the newest common ancestor with old canon chain. /// Hashes of the blocks which were invalidated.
pub ancestor: H256, retracted: Vec<H256>,
/// Hashes of the blocks between ancestor and this block. }
pub enacted: Vec<H256>,
/// Hashes of the blocks which were invalidated.
pub retracted: Vec<H256>,
} }

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,102 @@
// 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::numbers::H256;
use chainfilter::BloomIndex;
/// Represents location of block bloom in extras database.
#[derive(Debug, PartialEq)]
pub struct BlocksBloomLocation {
/// Unique hash of BlocksBloom
pub hash: H256,
/// Index within BlocksBloom
pub index: usize,
}
/// Should be used to localize blocks blooms in extras database.
pub struct BloomIndexer {
index_size: usize,
levels: u8,
}
impl BloomIndexer {
/// Plain constructor.
pub fn new(index_size: usize, levels: u8) -> Self {
BloomIndexer {
index_size: index_size,
levels: levels
}
}
/// Calculates bloom's position in database.
pub fn location(&self, bloom_index: &BloomIndex) -> BlocksBloomLocation {
use std::{mem, ptr};
let hash = unsafe {
let mut hash: H256 = mem::zeroed();
ptr::copy(&[bloom_index.index / self.index_size] as *const usize as *const u8, hash.as_mut_ptr(), 8);
hash[8] = bloom_index.level;
hash.reverse();
hash
};
BlocksBloomLocation {
hash: hash,
index: bloom_index.index % self.index_size
}
}
/// Returns index size.
pub fn index_size(&self) -> usize {
self.index_size
}
/// Returns number of cache levels.
pub fn levels(&self) -> u8 {
self.levels
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use util::hash::{H256, FixedHash};
use chainfilter::BloomIndex;
use blockchain::bloom_indexer::{BloomIndexer, BlocksBloomLocation};
#[test]
fn test_bloom_indexer() {
let bi = BloomIndexer::new(16, 3);
let index = BloomIndex::new(0, 0);
assert_eq!(bi.location(&index), BlocksBloomLocation {
hash: H256::new(),
index: 0
});
let index = BloomIndex::new(1, 0);
assert_eq!(bi.location(&index), BlocksBloomLocation {
hash: H256::from_str("0000000000000000000000000000000000000000000000010000000000000000").unwrap(),
index: 0
});
let index = BloomIndex::new(0, 299_999);
assert_eq!(bi.location(&index), BlocksBloomLocation {
hash: H256::from_str("000000000000000000000000000000000000000000000000000000000000493d").unwrap(),
index: 15
});
}
}

View File

@@ -23,6 +23,8 @@ pub struct CacheSize {
pub block_details: usize, pub block_details: usize,
/// Transaction addresses cache size. /// Transaction addresses cache size.
pub transaction_addresses: usize, pub transaction_addresses: usize,
/// Logs cache size.
pub block_logs: usize,
/// Blooms cache size. /// Blooms cache size.
pub blocks_blooms: usize, pub blocks_blooms: usize,
/// Block receipts size. /// Block receipts size.
@@ -31,7 +33,5 @@ pub struct CacheSize {
impl CacheSize { impl CacheSize {
/// Total amount used by the cache. /// Total amount used by the cache.
pub fn total(&self) -> usize { pub fn total(&self) -> usize { self.blocks + self.block_details + self.transaction_addresses + self.block_logs + self.blocks_blooms }
self.blocks + self.block_details + self.transaction_addresses + self.blocks_blooms + self.block_receipts
}
} }

View File

@@ -1,39 +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/>.
//! Blockchain configuration.
/// Blockchain configuration.
#[derive(Debug, PartialEq)]
pub struct Config {
/// Preferred cache size in bytes.
pub pref_cache_size: usize,
/// Maximum cache size in bytes.
pub max_cache_size: usize,
/// Backing db cache_size
pub db_cache_size: Option<usize>,
}
impl Default for Config {
fn default() -> Self {
Config {
pref_cache_size: 1 << 14,
max_cache_size: 1 << 20,
db_cache_size: None,
}
}
}

View File

@@ -1,243 +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/>.
//! Blockchain DB extras.
use bloomchain;
use util::*;
use header::BlockNumber;
use receipt::Receipt;
use db::Key;
use blooms::{GroupPosition, BloomGroup};
/// Represents index of extra data in database
#[derive(Copy, Debug, Hash, Eq, PartialEq, Clone)]
pub enum ExtrasIndex {
/// Block details index
BlockDetails = 0,
/// Block hash index
BlockHash = 1,
/// Transaction address index
TransactionAddress = 2,
/// Block blooms index
BlocksBlooms = 3,
/// Block receipts index
BlockReceipts = 4,
}
fn with_index(hash: &H256, i: ExtrasIndex) -> H264 {
let mut result = H264::default();
result[0] = i as u8;
(*result)[1..].clone_from_slice(hash);
result
}
pub struct BlockNumberKey([u8; 5]);
impl Deref for BlockNumberKey {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Key<H256> for BlockNumber {
type Target = BlockNumberKey;
fn key(&self) -> Self::Target {
let mut result = [0u8; 5];
result[0] = ExtrasIndex::BlockHash as u8;
result[1] = (self >> 24) as u8;
result[2] = (self >> 16) as u8;
result[3] = (self >> 8) as u8;
result[4] = *self as u8;
BlockNumberKey(result)
}
}
impl Key<BlockDetails> for H256 {
type Target = H264;
fn key(&self) -> H264 {
with_index(self, ExtrasIndex::BlockDetails)
}
}
pub struct LogGroupKey([u8; 6]);
impl Deref for LogGroupKey {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct LogGroupPosition(GroupPosition);
impl From<bloomchain::group::GroupPosition> for LogGroupPosition {
fn from(position: bloomchain::group::GroupPosition) -> Self {
LogGroupPosition(From::from(position))
}
}
impl HeapSizeOf for LogGroupPosition {
fn heap_size_of_children(&self) -> usize {
self.0.heap_size_of_children()
}
}
impl Key<BloomGroup> for LogGroupPosition {
type Target = LogGroupKey;
fn key(&self) -> Self::Target {
let mut result = [0u8; 6];
result[0] = ExtrasIndex::BlocksBlooms as u8;
result[1] = self.0.level;
result[2] = (self.0.index >> 24) as u8;
result[3] = (self.0.index >> 16) as u8;
result[4] = (self.0.index >> 8) as u8;
result[5] = self.0.index as u8;
LogGroupKey(result)
}
}
impl Key<TransactionAddress> for H256 {
type Target = H264;
fn key(&self) -> H264 {
with_index(self, ExtrasIndex::TransactionAddress)
}
}
impl Key<BlockReceipts> for H256 {
type Target = H264;
fn key(&self) -> H264 {
with_index(self, ExtrasIndex::BlockReceipts)
}
}
/// Familial details concerning a block
#[derive(Debug, Clone)]
pub struct BlockDetails {
/// Block number
pub number: BlockNumber,
/// Total difficulty of the block and all its parents
pub total_difficulty: U256,
/// Parent block hash
pub parent: H256,
/// List of children block hashes
pub children: Vec<H256>
}
impl HeapSizeOf for BlockDetails {
fn heap_size_of_children(&self) -> usize {
self.children.heap_size_of_children()
}
}
impl Decodable for BlockDetails {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let d = decoder.as_rlp();
let details = BlockDetails {
number: try!(d.val_at(0)),
total_difficulty: try!(d.val_at(1)),
parent: try!(d.val_at(2)),
children: try!(d.val_at(3)),
};
Ok(details)
}
}
impl Encodable for BlockDetails {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(4);
s.append(&self.number);
s.append(&self.total_difficulty);
s.append(&self.parent);
s.append(&self.children);
}
}
/// Represents address of certain transaction within block
#[derive(Debug, PartialEq, Clone)]
pub struct TransactionAddress {
/// Block hash
pub block_hash: H256,
/// Transaction index within the block
pub index: usize
}
impl HeapSizeOf for TransactionAddress {
fn heap_size_of_children(&self) -> usize { 0 }
}
impl Decodable for TransactionAddress {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let d = decoder.as_rlp();
let tx_address = TransactionAddress {
block_hash: try!(d.val_at(0)),
index: try!(d.val_at(1)),
};
Ok(tx_address)
}
}
impl Encodable for TransactionAddress {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(2);
s.append(&self.block_hash);
s.append(&self.index);
}
}
/// Contains all block receipts.
#[derive(Clone)]
pub struct BlockReceipts {
pub receipts: Vec<Receipt>,
}
impl BlockReceipts {
pub fn new(receipts: Vec<Receipt>) -> Self {
BlockReceipts {
receipts: receipts
}
}
}
impl Decodable for BlockReceipts {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
Ok(BlockReceipts {
receipts: try!(Decodable::decode(decoder))
})
}
}
impl Encodable for BlockReceipts {
fn rlp_append(&self, s: &mut RlpStream) {
s.append(&self.receipts);
}
}
impl HeapSizeOf for BlockReceipts {
fn heap_size_of_children(&self) -> usize {
self.receipts.heap_size_of_children()
}
}

View File

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

View File

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

View File

@@ -14,14 +14,11 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Blockchain generator for tests.
mod bloom; mod bloom;
mod block; mod block;
mod complete; mod complete;
mod fork; mod fork;
pub mod generator; pub mod generator;
mod transaction;
pub use self::complete::BlockFinalizer; pub use self::complete::BlockFinalizer;
pub use self::generator::{ChainIterator, ChainGenerator}; pub use self::generator::{ChainIterator, ChainGenerator};

View File

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

View File

@@ -26,8 +26,6 @@ pub struct ImportRoute {
pub retracted: Vec<H256>, pub retracted: Vec<H256>,
/// Blocks that were validated by new block. /// Blocks that were validated by new block.
pub enacted: Vec<H256>, pub enacted: Vec<H256>,
/// Blocks which are neither retracted nor enacted.
pub omitted: Vec<H256>,
} }
impl ImportRoute { impl ImportRoute {
@@ -35,7 +33,6 @@ impl ImportRoute {
ImportRoute { ImportRoute {
retracted: vec![], retracted: vec![],
enacted: vec![], enacted: vec![],
omitted: vec![],
} }
} }
} }
@@ -46,19 +43,13 @@ impl From<BlockInfo> for ImportRoute {
BlockLocation::CanonChain => ImportRoute { BlockLocation::CanonChain => ImportRoute {
retracted: vec![], retracted: vec![],
enacted: vec![info.hash], enacted: vec![info.hash],
omitted: vec![],
}, },
BlockLocation::Branch => ImportRoute { BlockLocation::Branch => ImportRoute::none(),
retracted: vec![], BlockLocation::BranchBecomingCanonChain { mut enacted, retracted, .. } => {
enacted: vec![], enacted.push(info.hash);
omitted: vec![info.hash],
},
BlockLocation::BranchBecomingCanonChain(mut data) => {
data.enacted.push(info.hash);
ImportRoute { ImportRoute {
retracted: data.retracted, retracted: retracted,
enacted: data.enacted, enacted: enacted,
omitted: vec![],
} }
} }
} }
@@ -69,7 +60,7 @@ impl From<BlockInfo> for ImportRoute {
mod tests { mod tests {
use util::hash::H256; use util::hash::H256;
use util::numbers::U256; use util::numbers::U256;
use blockchain::block_info::{BlockInfo, BlockLocation, BranchBecomingCanonChainData}; use blockchain::block_info::{BlockInfo, BlockLocation};
use blockchain::ImportRoute; use blockchain::ImportRoute;
#[test] #[test]
@@ -77,7 +68,6 @@ mod tests {
assert_eq!(ImportRoute::none(), ImportRoute { assert_eq!(ImportRoute::none(), ImportRoute {
enacted: vec![], enacted: vec![],
retracted: vec![], retracted: vec![],
omitted: vec![],
}); });
} }
@@ -90,11 +80,7 @@ mod tests {
location: BlockLocation::Branch, location: BlockLocation::Branch,
}; };
assert_eq!(ImportRoute::from(info), ImportRoute { assert_eq!(ImportRoute::from(info), ImportRoute::none());
retracted: vec![],
enacted: vec![],
omitted: vec![H256::from(U256::from(1))],
});
} }
#[test] #[test]
@@ -109,7 +95,6 @@ mod tests {
assert_eq!(ImportRoute::from(info), ImportRoute { assert_eq!(ImportRoute::from(info), ImportRoute {
retracted: vec![], retracted: vec![],
enacted: vec![H256::from(U256::from(1))], enacted: vec![H256::from(U256::from(1))],
omitted: vec![],
}); });
} }
@@ -119,17 +104,16 @@ mod tests {
hash: H256::from(U256::from(2)), hash: H256::from(U256::from(2)),
number: 0, number: 0,
total_difficulty: U256::from(0), total_difficulty: U256::from(0),
location: BlockLocation::BranchBecomingCanonChain(BranchBecomingCanonChainData { location: BlockLocation::BranchBecomingCanonChain {
ancestor: H256::from(U256::from(0)), ancestor: H256::from(U256::from(0)),
enacted: vec![H256::from(U256::from(1))], enacted: vec![H256::from(U256::from(1))],
retracted: vec![H256::from(U256::from(3)), H256::from(U256::from(4))], retracted: vec![H256::from(U256::from(3)), H256::from(U256::from(4))],
}) }
}; };
assert_eq!(ImportRoute::from(info), ImportRoute { assert_eq!(ImportRoute::from(info), ImportRoute {
retracted: vec![H256::from(U256::from(3)), H256::from(U256::from(4))], retracted: vec![H256::from(U256::from(3)), H256::from(U256::from(4))],
enacted: vec![H256::from(U256::from(1)), H256::from(U256::from(2))], enacted: vec![H256::from(U256::from(1)), H256::from(U256::from(2))],
omitted: vec![],
}); });
} }
} }

View File

@@ -16,20 +16,18 @@
//! Blockchain database. //! Blockchain database.
pub mod blockchain;
mod best_block; mod best_block;
mod block_info; mod block_info;
pub mod blockchain; mod bloom_indexer;
mod cache; mod cache;
mod config; mod tree_route;
pub mod extras;
mod import_route;
mod update; mod update;
mod import_route;
#[cfg(test)] #[cfg(test)]
pub mod generator; mod generator;
pub use self::blockchain::{BlockProvider, BlockChain}; pub use self::blockchain::{BlockProvider, BlockChain, BlockChainConfig};
pub use self::cache::CacheSize; pub use self::cache::CacheSize;
pub use self::config::Config; pub use self::tree_route::TreeRoute;
pub use types::tree_route::TreeRoute;
pub use self::import_route::ImportRoute; pub use self::import_route::ImportRoute;

View File

@@ -14,15 +14,10 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Tree route info type definition
use util::numbers::H256; use util::numbers::H256;
use ipc::BinaryConvertError;
use std::collections::VecDeque;
use std::mem;
/// Represents a tree route between `from` block and `to` block: /// Represents a tree route between `from` block and `to` block:
#[derive(Debug, Binary)] #[derive(Debug)]
pub struct TreeRoute { pub struct TreeRoute {
/// A vector of hashes of all blocks, ordered from `from` to `to`. /// A vector of hashes of all blocks, ordered from `from` to `to`.
pub blocks: Vec<H256>, pub blocks: Vec<H256>,

View File

@@ -2,23 +2,20 @@ use std::collections::HashMap;
use util::numbers::H256; use util::numbers::H256;
use header::BlockNumber; use header::BlockNumber;
use blockchain::block_info::BlockInfo; use blockchain::block_info::BlockInfo;
use blooms::BloomGroup; use extras::{BlockDetails, BlockReceipts, TransactionAddress, BlocksBlooms};
use super::extras::{BlockDetails, BlockReceipts, TransactionAddress, LogGroupPosition};
/// Block extras update info. /// Block extras update info.
pub struct ExtrasUpdate<'a> { pub struct ExtrasUpdate {
/// Block info. /// Block info.
pub info: BlockInfo, pub info: BlockInfo,
/// Current block uncompressed rlp bytes
pub block: &'a [u8],
/// Modified block hashes. /// Modified block hashes.
pub block_hashes: HashMap<BlockNumber, H256>, pub block_hashes: HashMap<BlockNumber, H256>,
/// Modified block details. /// Modified block details.
pub block_details: HashMap<H256, BlockDetails>, pub block_details: HashMap<H256, BlockDetails>,
/// Modified block receipts. /// Modified block receipts.
pub block_receipts: HashMap<H256, BlockReceipts>, pub block_receipts: HashMap<H256, BlockReceipts>,
/// Modified transaction addresses.
pub transactions_addresses: HashMap<H256, TransactionAddress>,
/// Modified blocks blooms. /// Modified blocks blooms.
pub blocks_blooms: HashMap<LogGroupPosition, BloomGroup>, pub blocks_blooms: HashMap<H256, BlocksBlooms>,
/// Modified transaction addresses (None signifies removed transactions).
pub transactions_addresses: HashMap<H256, Option<TransactionAddress>>,
} }

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