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
619 changed files with 24289 additions and 91204 deletions

View File

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

View File

@@ -1,310 +0,0 @@
stages:
- build
- test
variables:
GIT_DEPTH: "3"
SIMPLECOV: "true"
RUST_BACKTRACE: "1"
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
- 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
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
- 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
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
- 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
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
- 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
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
- 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
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
- 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% -Zorbit=off -D warnings
- rustup default stable-x86_64-pc-windows-msvc
- cargo build --release --verbose
- curl -sL --url "https://github.com/ethcore/win-build/raw/master/SimpleFC.dll" -o nsis\SimpleFC.dll
- curl -sL --url "https://github.com/ethcore/win-build/raw/master/vc_redist.x64.exe" -o nsis\vc_redist.x64.exe
- signtool sign /f %keyfile% /p %certpass% target\release\parity.exe
- cd nsis
- makensis.exe installer.nsi
- copy installer.exe InstallParity.exe
- signtool sign /f %keyfile% /p %certpass% InstallParity.exe
- md5sums InstallParity.exe > InstallParity.exe.md5
- zip win-installer.zip InstallParity.exe InstallParity.exe.md5
- md5sums win-installer.zip > win-installer.zip.md5
- cd ..\target\release\
- md5sums parity.exe parity.pdb > parity.md5
- md5sums parity.exe > parity.exe.md5
- zip parity.zip parity.exe parity.pdb parity.md5
- md5sums parity.zip > parity.zip.md5
- cd ..\..
- aws configure set aws_access_key_id %s3_key%
- aws configure set aws_secret_access_key %s3_secret%
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.exe --body target\release\parity.exe
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.exe.md5 --body target\release\parity.exe.md5
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.zip --body target\release\parity.zip
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.zip.md5 --body target\release\parity.zip.md5
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/InstallParity.exe --body nsis\InstallParity.exe
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/InstallParity.exe.md5 --body nsis\InstallParity.exe.md5
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/win-installer.zip --body nsis\win-installer.zip
- aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/win-installer.zip.md5 --body nsis\win-installer.zip.md5
tags:
- rust-windows
artifacts:
paths:
- target/release/parity.exe
- target/release/parity.pdb
- 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
dist: trusty
language: rust
branches:
only:
- master
@@ -9,69 +8,96 @@ branches:
- /^stable-.*$/
- /^beta$/
- /^stable$/
git:
depth: 3
matrix:
fast_finish: true
allow_failures:
- rust: nightly
include:
- rust: stable
env: RUN_TESTS="true"
- rust: beta
env: RUN_COVERAGE="true"
env: FEATURES="--features travis-beta" RUN_TESTS="true"
# - rust: beta
# env: FEATURES="--features travis-beta" RUN_TESTS="true"
- 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:
global:
- CXX="g++-4.8"
- CC="gcc-4.8"
- RUST_BACKTRACE="1"
# GH_TOKEN
- 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=
- 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_COVERAGE="false"
- RUN_DOCS="false"
# GH_TOKEN for documentation
- 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"
- RUN_BUILD="false"
- RUN_BENCHES="false"
cache:
apt: true
directories:
- $TRAVIS_BUILD_DIR/target
- $TRAVIS_BUILD_DIR/kcov-master
- $HOME/.cargo
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- libcurl4-openssl-dev
- libelf-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:
- if [ "$RUN_TESTS" = "true" ]; then ./test.sh --verbose; fi
- if [ "$RUN_COVERAGE" = "true" ]; then ./scripts/cov.sh "$KCOV_CMD"; fi
- echo "$TRAVIS_BUILD_DIR/target"
- 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: |
[ "$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_PULL_REQUEST = false ] &&
[ "$RUN_DOCS" = "true" ] &&
./scripts/doc.sh &&
[ $TRAVIS_RUST_VERSION = stable ] &&
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 &&
/home/travis/.local/bin/ghp-import -n target/doc &&
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

1389
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,13 @@
[package]
description = "Ethcore client."
name = "parity"
version = "1.3.7"
version = "1.0.2"
license = "GPL-3.0"
authors = ["Ethcore <admin@ethcore.io>"]
build = "build.rs"
[build-dependencies]
rustc_version = "0.1"
syntex = "*"
ethcore-ipc-codegen = { path = "ipc/codegen" }
ethcore-ipc-tests = { path = "ipc/tests" }
[dependencies]
log = "0.3"
@@ -18,50 +15,26 @@ env_logger = "0.3"
rustc-serialize = "0.3"
docopt = "0.6"
time = "0.1"
ctrlc = { git = "https://github.com/tomusdrw/rust-ctrlc.git" }
fdlimit = { path = "util/fdlimit" }
daemonize = "0.2"
num_cpus = "0.2"
number_prefix = "0.2"
rpassword = "0.2.1"
semver = "0.2"
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" }
rpassword = "0.1"
clippy = { version = "0.0.54", optional = true }
ethcore = { path = "ethcore" }
ethcore-util = { path = "util" }
ethsync = { path = "sync" }
ethcore-io = { path = "util/io" }
ethminer = { path = "miner" }
ethcore-devtools = { path = "devtools" }
ethcore-rpc = { path = "rpc" }
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
ethcore-rpc = { path = "rpc", optional = true }
[features]
default = ["ui", "use-precompiled-js"]
ui = ["dapps", "ethcore-signer/ui"]
use-precompiled-js = ["ethcore-dapps/use-precompiled-js", "ethcore-signer/use-precompiled-js"]
dapps = ["ethcore-dapps"]
ipc = ["ethcore/ipc"]
jit = ["ethcore/jit"]
dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethcore-dapps/dev", "ethcore-signer/dev"]
json-tests = ["ethcore/json-tests"]
default = ["rpc"]
rpc = ["ethcore-rpc"]
dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethminer/dev"]
travis-beta = ["ethcore/json-tests"]
travis-nightly = ["ethcore/json-tests", "dev"]
[[bin]]
path = "parity/main.rs"
@@ -70,4 +43,3 @@ name = "parity"
[profile.release]
debug = false
lto = false

View File

@@ -1,11 +1,6 @@
# [Parity](https://ethcore.io/parity.html)
### Fast, light, and robust Ethereum implementation
# ethcore
[![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]
[Internal Documentation][doc-url]
Be sure to check out [our wiki][wiki-url] for more information.
[![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]
[travis-image]: https://travis-ci.org/ethcore/parity.svg?branch=master
[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
[license-image]: https://img.shields.io/badge/license-GPL%20v3-green.svg
[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
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
First (if you don't already have it) get multirust:
- Linux:
```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
# download Parity code
$ git clone https://github.com/ethcore/parity
$ cd parity
git clone https://github.com/ethcore/parity
cd parity
# 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" }
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"
license = "GPL-3.0"
name = "ethcore-devtools"
version = "1.3.0"
version = "1.0.0"
authors = ["Ethcore <admin@ethcore.io>"]
[dependencies]

1
devtools/README.md Normal file
View File

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

View File

@@ -19,10 +19,6 @@
extern crate rand;
mod random_path;
mod test_socket;
mod stop_guard;
pub mod 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::fs;
use std::env;
use std::ops::{Deref, DerefMut};
use rand::random;
pub struct RandomTempPath {
@@ -27,11 +26,7 @@ pub struct RandomTempPath {
}
pub fn random_filename() -> String {
random_str(8)
}
pub fn random_str(len: usize) -> String {
(0..len).map(|_| ((random::<f32>() * 26.0) as u8 + 97) as char).collect()
(0..8).map(|_| ((random::<f32>() * 26.0) as u8 + 97) as char).collect()
}
impl RandomTempPath {
@@ -59,51 +54,16 @@ impl RandomTempPath {
pub fn as_str(&self) -> &str {
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 {
fn drop(&mut self) {
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]
fn creates_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 && \
cmake .. && make && make install && cd
# install rustup
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
# install multirust
RUN curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes
# rustup directory
ENV PATH /root/.cargo/bin:$PATH
# export rust LIBRARY_PATH
ENV LIBRARY_PATH /usr/local/lib
# show backtraces
ENV RUST_BACKTRACE 1

View File

@@ -1,55 +1,42 @@
FROM ubuntu:14.04
WORKDIR /build
# install tools and dependencies
RUN apt-get update && \
apt-get install -y \
# make
build-essential \
# add-apt-repository
software-properties-common \
curl \
wget \
git \
g++ \
binutils \
file \
# evmjit dependencies
zlib1g-dev \
libedit-dev
apt-get install -y \
# make
build-essential \
# add-apt-repository
software-properties-common \
curl \
wget \
git \
g++ \
# evmjit dependencies
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" && \
add-apt-repository "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main" && \
apt-get update && \
apt-get install -y --force-yes cmake llvm-3.7-dev
add-apt-repository "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main" && \
apt-get update && \
apt-get install -y --force-yes cmake llvm-3.7-dev
# install evmjit
RUN git clone https://github.com/debris/evmjit && \
cd evmjit && \
mkdir build && cd build && \
cmake .. && make && make install && cd
cd evmjit && \
mkdir build && cd build && \
cmake .. && make && make install && cd
# install rustup
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
# install multirust
RUN curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes
# rustup directory
ENV PATH /root/.cargo/bin:$PATH
# export rust LIBRARY_PATH
ENV LIBRARY_PATH /usr/local/lib
# 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 beta && \
git pull && \
cargo build --release --features ethcore/jit --verbose && \
ls /build/parity/target/release/parity && \
strip /build/parity/target/release/parity
RUN file /build/parity/target/release/parity
cd parity && \
cargo build --release --features ethcore/jit

View File

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

View File

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

View File

@@ -20,17 +20,14 @@
// TODO: fix endianess for big endian
use primal::is_prime;
use std::cell::Cell;
use std::mem;
use std::ptr;
use sha3;
use std::slice;
use std::path::PathBuf;
use std::io::{self, Read, Write};
use std::io::{Read, Write, self};
use std::fs::{self, File};
use parking_lot::Mutex;
pub const ETHASH_EPOCH_LENGTH: u64 = 30000;
pub const ETHASH_CACHE_ROUNDS: usize = 3;
pub const ETHASH_MIX_BYTES: usize = 128;
@@ -45,14 +42,14 @@ const NODE_WORDS: usize = 64 / 4;
const NODE_BYTES: usize = 64;
const MIX_WORDS: usize = ETHASH_MIX_BYTES / 4;
const MIX_NODES: usize = MIX_WORDS / NODE_WORDS;
const FNV_PRIME: u32 = 0x01000193;
const FNV_PRIME: u32 = 0x01000193;
/// Computation result
pub struct ProofOfWork {
/// Difficulty boundary
pub value: H256,
/// Mix
pub mix_hash: H256,
pub mix_hash: H256
}
struct Node {
@@ -88,7 +85,6 @@ pub type H256 = [u8; 32];
pub struct Light {
block_number: u64,
cache: Vec<Node>,
seed_compute: Mutex<SeedHashCompute>,
}
/// Light cache structur
@@ -105,17 +101,17 @@ impl Light {
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();
home.push(".ethash");
home.push("light");
let seed_hash = get_seedhash(block_number);
home.push(to_hex(&seed_hash));
home
}
pub fn from_file(block_number: u64) -> io::Result<Light> {
let seed_compute = SeedHashCompute::new();
let path = Light::file_path(seed_compute.get_seedhash(block_number));
let path = Light::file_path(block_number);
let mut file = try!(File::open(path));
let cache_size = get_cache_size(block_number);
@@ -130,13 +126,11 @@ impl Light {
Ok(Light {
cache: nodes,
block_number: block_number,
seed_compute: Mutex::new(seed_compute),
})
}
pub fn to_file(&self) -> io::Result<()> {
let seed_compute = self.seed_compute.lock();
let path = Light::file_path(seed_compute.get_seedhash(self.block_number));
let path = Light::file_path(self.block_number);
try!(fs::create_dir_all(path.parent().unwrap()));
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]
fn fnv_hash(x: u32, y: u32) -> u32 {
return x.wrapping_mul(FNV_PRIME) ^ y;
@@ -204,24 +153,34 @@ fn sha3_512(input: &[u8], output: &mut [u8]) {
#[inline]
fn get_cache_size(block_number: u64) -> usize {
let mut sz: u64 = CACHE_BYTES_INIT + CACHE_BYTES_GROWTH * (block_number / ETHASH_EPOCH_LENGTH);
sz = sz - NODE_BYTES as u64;
while !is_prime(sz / NODE_BYTES as u64) {
sz = sz - 2 * NODE_BYTES as u64;
}
sz as usize
let mut sz: u64 = CACHE_BYTES_INIT + CACHE_BYTES_GROWTH * (block_number / ETHASH_EPOCH_LENGTH);
sz = sz - NODE_BYTES as u64;
while !is_prime(sz / NODE_BYTES as u64) {
sz = sz - 2 * NODE_BYTES as u64;
}
sz as usize
}
#[inline]
fn get_data_size(block_number: u64) -> usize {
let mut sz: u64 = DATASET_BYTES_INIT + DATASET_BYTES_GROWTH * (block_number / ETHASH_EPOCH_LENGTH);
sz = sz - ETHASH_MIX_BYTES as u64;
while !is_prime(sz / ETHASH_MIX_BYTES as u64) {
sz = sz - 2 * ETHASH_MIX_BYTES as u64;
}
sz as usize
let mut sz: u64 = DATASET_BYTES_INIT + DATASET_BYTES_GROWTH * (block_number / ETHASH_EPOCH_LENGTH);
sz = sz - ETHASH_MIX_BYTES as u64;
while !is_prime(sz / ETHASH_MIX_BYTES as u64) {
sz = sz - 2 * ETHASH_MIX_BYTES as u64;
}
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
///
@@ -252,12 +211,12 @@ pub fn light_compute(light: &Light, header_hash: &H256, nonce: u64) -> ProofOfWo
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 {
panic!("Unaligned full size");
}
// 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(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 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) {
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 {
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 {
*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(), mix_hash.as_mut_ptr(), 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 {
mix_hash: mix_hash,
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 {
let num_parent_nodes = cache.len();
let init = cache.get_unchecked(node_index as usize % num_parent_nodes);
let num_parent_nodes = light.cache.len();
let cache_nodes = &light.cache;
let init = cache_nodes.get_unchecked(node_index as usize % num_parent_nodes);
let mut ret = init.clone();
*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());
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 = cache.get_unchecked(parent_index as usize);
let parent = cache_nodes.get_unchecked(parent_index as usize);
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));
}
@@ -328,9 +287,7 @@ fn calculate_dag_item(node_index: u32, cache: &[Node]) -> Node {
}
fn light_new(block_number: u64) -> Light {
let seed_compute = SeedHashCompute::new();
let seedhash = seed_compute.get_seedhash(block_number);
let seedhash = get_seedhash(block_number);
let cache_size = get_cache_size(block_number);
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 mut data = nodes.get_unchecked((num_nodes - 1 + i) % num_nodes).clone();
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);
}
@@ -361,11 +318,10 @@ fn light_new(block_number: u64) -> Light {
Light {
cache: nodes,
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 {
let mut v = Vec::with_capacity(bytes.len() * 2);
for &byte in bytes.iter() {
@@ -373,7 +329,9 @@ fn to_hex(bytes: &[u8]) -> String {
v.push(CHARS[(byte & 0xf) as usize]);
}
unsafe { String::from_utf8_unchecked(v) }
unsafe {
String::from_utf8_unchecked(v)
}
}
#[test]
@@ -403,8 +361,8 @@ fn test_get_data_size() {
#[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 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 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 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];
assert_eq!(quick_get_difficulty(&hash, nonce, &mix_hash)[..], boundary_good[..]);
@@ -414,8 +372,8 @@ fn test_difficulty_test() {
#[test]
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 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 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 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;
// difficulty = 0x085657254bd9u64;
@@ -424,34 +382,3 @@ fn test_light_compute() {
assert_eq!(result.mix_hash[..], mix_hash[..]);
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
extern crate primal;
extern crate sha3;
extern crate parking_lot;
#[macro_use]
extern crate log;
mod compute;
use std::mem;
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 parking_lot::Mutex;
use std::sync::{Arc, Mutex};
struct LightCache {
recent_epoch: Option<u64>,
@@ -64,7 +61,7 @@ impl EthashManager {
pub fn compute_light(&self, block_number: u64, header_hash: &H256, nonce: u64) -> ProofOfWork {
let epoch = block_number / ETHASH_EPOCH_LENGTH;
let light = {
let mut lights = self.cache.lock();
let mut lights = self.cache.lock().unwrap();
let light = match lights.recent_epoch.clone() {
Some(ref e) if *e == epoch => lights.recent.clone(),
_ => match lights.prev_epoch.clone() {
@@ -79,7 +76,7 @@ impl EthashManager {
lights.recent.clone()
}
_ => None,
},
}
};
match light {
None => {
@@ -98,7 +95,7 @@ impl EthashManager {
lights.prev = mem::replace(&mut lights.recent, Some(light.clone()));
light
}
Some(light) => light,
Some(light) => light
}
};
light.compute(header_hash, nonce)
@@ -111,12 +108,12 @@ fn test_lru() {
let hash = [0u8; 32];
ethash.compute_light(1, &hash, 1);
ethash.compute_light(50000, &hash, 1);
assert_eq!(ethash.cache.lock().recent_epoch.unwrap(), 1);
assert_eq!(ethash.cache.lock().prev_epoch.unwrap(), 0);
assert_eq!(ethash.cache.lock().unwrap().recent_epoch.unwrap(), 1);
assert_eq!(ethash.cache.lock().unwrap().prev_epoch.unwrap(), 0);
ethash.compute_light(1, &hash, 1);
assert_eq!(ethash.cache.lock().recent_epoch.unwrap(), 0);
assert_eq!(ethash.cache.lock().prev_epoch.unwrap(), 1);
assert_eq!(ethash.cache.lock().unwrap().recent_epoch.unwrap(), 0);
assert_eq!(ethash.cache.lock().unwrap().prev_epoch.unwrap(), 1);
ethash.compute_light(70000, &hash, 1);
assert_eq!(ethash.cache.lock().recent_epoch.unwrap(), 2);
assert_eq!(ethash.cache.lock().prev_epoch.unwrap(), 0);
assert_eq!(ethash.cache.lock().unwrap().recent_epoch.unwrap(), 2);
assert_eq!(ethash.cache.lock().unwrap().prev_epoch.unwrap(), 0);
}

View File

@@ -3,12 +3,8 @@ description = "Ethcore library"
homepage = "http://ethcore.io"
license = "GPL-3.0"
name = "ethcore"
version = "1.3.0"
version = "1.0.2"
authors = ["Ethcore <admin@ethcore.io>"]
build = "build.rs"
[build-dependencies]
"ethcore-ipc-codegen" = { path = "../ipc/codegen" }
[dependencies]
log = "0.3"
@@ -16,32 +12,16 @@ env_logger = "0.3"
rustc-serialize = "0.3"
heapsize = "0.3"
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"
evmjit = { path = "../evmjit", optional = true }
clippy = { version = "0.0.80", optional = true}
ethash = { path = "../ethash" }
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" }
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]
jit = ["evmjit"]
@@ -50,5 +30,3 @@ json-tests = []
test-heavy = []
dev = ["clippy"]
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("src/client/traits.rs").unwrap();
ethcore_ipc_codegen::derive_ipc("src/client/chain_notify.rs").unwrap();
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,162 +0,0 @@
{
"name": "DAO hard-fork consensus test",
"engine": {
"Ethash": {
"params": {
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0x5",
"daoHardforkTransition": "0x8",
"daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754",
"daoHardforkAccounts": [
"0xd4fe7bc31cedb7bfb8a345f31e668033056b2728",
"0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425",
"0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f",
"0xecd135fa4f61a655311e86238c92adcd779555d2",
"0x1975bd06d486162d5dc297798dfc41edd5d160a7",
"0xa3acf3a1e16b1d7c315e23510fdd7847b48234f6",
"0x319f70bab6845585f412ec7724b744fec6095c85",
"0x06706dd3f2c9abf0a21ddcc6941d9b86f0596936",
"0x5c8536898fbb74fc7445814902fd08422eac56d0",
"0x6966ab0d485353095148a2155858910e0965b6f9",
"0x779543a0491a837ca36ce8c635d6154e3c4911a6",
"0x2a5ed960395e2a49b1c758cef4aa15213cfd874c",
"0x5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5",
"0x9c50426be05db97f5d64fc54bf89eff947f0a321",
"0x200450f06520bdd6c527622a273333384d870efb",
"0xbe8539bfe837b67d1282b2b1d61c3f723966f049",
"0x6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb",
"0xf1385fb24aad0cd7432824085e42aff90886fef5",
"0xd1ac8b1ef1b69ff51d1d401a476e7e612414f091",
"0x8163e7fb499e90f8544ea62bbf80d21cd26d9efd",
"0x51e0ddd9998364a2eb38588679f0d2c42653e4a6",
"0x627a0a960c079c21c34f7612d5d230e01b4ad4c7",
"0xf0b1aa0eb660754448a7937c022e30aa692fe0c5",
"0x24c4d950dfd4dd1902bbed3508144a54542bba94",
"0x9f27daea7aca0aa0446220b98d028715e3bc803d",
"0xa5dc5acd6a7968a4554d89d65e59b7fd3bff0f90",
"0xd9aef3a1e38a39c16b31d1ace71bca8ef58d315b",
"0x63ed5a272de2f6d968408b4acb9024f4cc208ebf",
"0x6f6704e5a10332af6672e50b3d9754dc460dfa4d",
"0x77ca7b50b6cd7e2f3fa008e24ab793fd56cb15f6",
"0x492ea3bb0f3315521c31f273e565b868fc090f17",
"0x0ff30d6de14a8224aa97b78aea5388d1c51c1f00",
"0x9ea779f907f0b315b364b0cfc39a0fde5b02a416",
"0xceaeb481747ca6c540a000c1f3641f8cef161fa7",
"0xcc34673c6c40e791051898567a1222daf90be287",
"0x579a80d909f346fbfb1189493f521d7f48d52238",
"0xe308bd1ac5fda103967359b2712dd89deffb7973",
"0x4cb31628079fb14e4bc3cd5e30c2f7489b00960c",
"0xac1ecab32727358dba8962a0f3b261731aad9723",
"0x4fd6ace747f06ece9c49699c7cabc62d02211f75",
"0x440c59b325d2997a134c2c7c60a8c61611212bad",
"0x4486a3d68fac6967006d7a517b889fd3f98c102b",
"0x9c15b54878ba618f494b38f0ae7443db6af648ba",
"0x27b137a85656544b1ccb5a0f2e561a5703c6a68f",
"0x21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241",
"0x23b75c2f6791eef49c69684db4c6c1f93bf49a50",
"0x1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b",
"0xb9637156d330c0d605a791f1c31ba5890582fe1c",
"0x6131c42fa982e56929107413a9d526fd99405560",
"0x1591fc0f688c81fbeb17f5426a162a7024d430c2",
"0x542a9515200d14b68e934e9830d91645a980dd7a",
"0xc4bbd073882dd2add2424cf47d35213405b01324",
"0x782495b7b3355efb2833d56ecb34dc22ad7dfcc4",
"0x58b95c9a9d5d26825e70a82b6adb139d3fd829eb",
"0x3ba4d81db016dc2890c81f3acec2454bff5aada5",
"0xb52042c8ca3f8aa246fa79c3feaa3d959347c0ab",
"0xe4ae1efdfc53b73893af49113d8694a057b9c0d1",
"0x3c02a7bc0391e86d91b7d144e61c2c01a25a79c5",
"0x0737a6b837f97f46ebade41b9bc3e1c509c85c53",
"0x97f43a37f595ab5dd318fb46e7a155eae057317a",
"0x52c5317c848ba20c7504cb2c8052abd1fde29d03",
"0x4863226780fe7c0356454236d3b1c8792785748d",
"0x5d2b2e6fcbe3b11d26b525e085ff818dae332479",
"0x5f9f3392e9f62f63b8eac0beb55541fc8627f42c",
"0x057b56736d32b86616a10f619859c6cd6f59092a",
"0x9aa008f65de0b923a2a4f02012ad034a5e2e2192",
"0x304a554a310c7e546dfe434669c62820b7d83490",
"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79",
"0x4deb0033bb26bc534b197e61d19e0733e5679784",
"0x07f5c1e1bc2c93e0402f23341973a0e043f7bf8a",
"0x35a051a0010aba705c9008d7a7eff6fb88f6ea7b",
"0x4fa802324e929786dbda3b8820dc7834e9134a2a",
"0x9da397b9e80755301a3b32173283a91c0ef6c87e",
"0x8d9edb3054ce5c5774a420ac37ebae0ac02343c6",
"0x0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9",
"0x5dc28b15dffed94048d73806ce4b7a4612a1d48f",
"0xbcf899e6c7d9d5a215ab1e3444c86806fa854c76",
"0x12e626b0eebfe86a56d633b9864e389b45dcb260",
"0xa2f1ccba9395d7fcb155bba8bc92db9bafaeade7",
"0xec8e57756626fdc07c63ad2eafbd28d08e7b0ca5",
"0xd164b088bd9108b60d0ca3751da4bceb207b0782",
"0x6231b6d0d5e77fe001c2a460bd9584fee60d409b",
"0x1cba23d343a983e9b5cfd19496b9a9701ada385f",
"0xa82f360a8d3455c5c41366975bde739c37bfeb8a",
"0x9fcd2deaff372a39cc679d5c5e4de7bafb0b1339",
"0x005f5cee7a43331d5a3d3eec71305925a62f34b6",
"0x0e0da70933f4c7849fc0d203f5d1d43b9ae4532d",
"0xd131637d5275fd1a68a3200f4ad25c71a2a9522e",
"0xbc07118b9ac290e4622f5e77a0853539789effbe",
"0x47e7aa56d6bdf3f36be34619660de61275420af8",
"0xacd87e28b0c9d1254e868b81cba4cc20d9a32225",
"0xadf80daec7ba8dcf15392f1ac611fff65d94f880",
"0x5524c55fb03cf21f549444ccbecb664d0acad706",
"0x40b803a9abce16f50f36a77ba41180eb90023925",
"0xfe24cdd8648121a43a7c86d289be4dd2951ed49f",
"0x17802f43a0137c506ba92291391a8a8f207f487d",
"0x253488078a4edf4d6f42f113d1e62836a942cf1a",
"0x86af3e9626fce1957c82e88cbf04ddf3a2ed7915",
"0xb136707642a4ea12fb4bae820f03d2562ebff487",
"0xdbe9b615a3ae8709af8b93336ce9b477e4ac0940",
"0xf14c14075d6c4ed84b86798af0956deef67365b5",
"0xca544e5c4687d109611d0f8f928b53a25af72448",
"0xaeeb8ff27288bdabc0fa5ebb731b6f409507516c",
"0xcbb9d3703e651b0d496cdefb8b92c25aeb2171f7",
"0x6d87578288b6cb5549d5076a207456a1f6a63dc0",
"0xb2c6f0dfbb716ac562e2d85d6cb2f8d5ee87603e",
"0xaccc230e8a6e5be9160b8cdf2864dd2a001c28b6",
"0x2b3455ec7fedf16e646268bf88846bd7a2319bb2",
"0x4613f3bca5c44ea06337a9e439fbc6d42e501d0a",
"0xd343b217de44030afaa275f54d31a9317c7f441e",
"0x84ef4b2357079cd7a7c69fd7a37cd0609a679106",
"0xda2fef9e4a3230988ff17df2165440f37e8b1708",
"0xf4c64518ea10f995918a454158c6b61407ea345c",
"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97",
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
]
}
}
},
"params": {
"accountStartNonce": "0x00",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x1"
},
"genesis": {
"seal": {
"ethereum": {
"nonce": "0x0000000000000042",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x400000000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"gasLimit": "0x1388"
},
"accounts": {
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }
}
}

View File

@@ -1,154 +1,24 @@
{
"name": "Frontier/Homestead",
"engine": {
"Ethash": {
"params": {
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "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"
]
}
}
},
"engineName": "Ethash",
"params": {
"accountStartNonce": "0x00",
"frontierCompatibilityModeLimit": "0x118c30",
"maximumExtraDataSize": "0x20",
"tieBreakingGas": false,
"minGasLimit": "0x1388",
"networkID" : "0x1",
"forkBlock": "0x1d4c00",
"forkCanonHash": "0x4985f5ca3d2afbec36529aa96f74de3cc10a2a4a6c44f2157a57d2c6059a11bb"
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"networkID" : "0x1"
},
"genesis": {
"seal": {
"ethereum": {
"nonce": "0x0000000000000042",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"nonce": "0x0000000000000042",
"difficulty": "0x400000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",

View File

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

View File

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

View File

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

View File

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

View File

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

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",
"engine": {
"Null": null
},
"engineName": "NullEngine",
"params": {
"accountStartNonce": "0x0",
"accountStartNonce": "0x0100000",
"frontierCompatibilityModeLimit": "0xfffa2990",
"maximumExtraDataSize": "0x20",
"tieBreakingGas": false,
"minGasLimit": "0x1388",
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar": "",
"networkID" : "0x2"
},
"genesis": {
"seal": {
"ethereum": {
"nonce": "0x00006d6f7264656e",
"mixHash": "0x00000000000000000000000000000000000000647572616c65787365646c6578"
}
},
"nonce": "0x00006d6f7264656e",
"difficulty": "0x20000",
"mixHash": "0x00000000000000000000000000000000000000647572616c65787365646c6578",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"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 pod_account::*;
use account_db::*;
use lru_cache::LruCache;
use std::cell::{RefCell, Cell};
const STORAGE_CACHE_ITEMS: usize = 8192;
/// Single account in the system.
/// Keeps track of changes to the code and storage.
/// The changes are applied in `commit_storage` and `commit_code`
#[derive(Clone)]
pub struct Account {
// Balance of the account.
balance: U256,
@@ -35,22 +29,12 @@ pub struct Account {
nonce: U256,
// Trie-backed storage.
storage_root: H256,
// LRU Cache of the trie-backed storage.
// This is limited to `STORAGE_CACHE_ITEMS` recent queries
storage_cache: RefCell<LruCache<H256, H256>>,
// Modified storage. Accumulates changes to storage made in `set_storage`
// Takes precedence over `storage_cache`.
storage_changes: HashMap<H256, H256>,
// Code hash of the account.
code_hash: H256,
// Size of the accoun code.
code_size: Option<u64>,
// Overlay on trie-backed storage - tuple is (<clean>, <value>).
storage_overlay: RefCell<HashMap<H256, (Filth, H256)>>,
// Code hash of the account. If None, means that it's a contract whose code has not yet been set.
code_hash: Option<H256>,
// Code cache of the account.
code_cache: Arc<Bytes>,
// Account code new or has been modified.
code_filth: Filth,
// Cached address hash.
address_hash: Cell<Option<H256>>,
code_cache: Bytes,
}
impl Account {
@@ -61,33 +45,23 @@ impl Account {
balance: balance,
nonce: nonce,
storage_root: SHA3_NULL_RLP,
storage_cache: Self::empty_storage_cache(),
storage_changes: storage,
code_hash: code.sha3(),
code_size: Some(code.len() as u64),
code_cache: Arc::new(code),
code_filth: Filth::Dirty,
address_hash: Cell::new(None),
storage_overlay: RefCell::new(storage.into_iter().map(|(k, v)| (k, (Filth::Dirty, v))).collect()),
code_hash: Some(code.sha3()),
code_cache: code
}
}
fn empty_storage_cache() -> RefCell<LruCache<H256, H256>> {
RefCell::new(LruCache::new(STORAGE_CACHE_ITEMS))
}
#[cfg(test)]
#[cfg(feature = "json-tests")]
/// General constructor.
pub fn from_pod(pod: PodAccount) -> Account {
Account {
balance: pod.balance,
nonce: pod.nonce,
storage_root: SHA3_NULL_RLP,
storage_cache: Self::empty_storage_cache(),
storage_changes: pod.storage.into_iter().collect(),
code_hash: pod.code.as_ref().map_or(SHA3_EMPTY, |c| c.sha3()),
code_filth: Filth::Dirty,
code_size: Some(pod.code.as_ref().map_or(0, |c| c.len() as u64)),
code_cache: Arc::new(pod.code.map_or_else(|| { warn!("POD account with unknown code is being created! Assuming no code."); vec![] }, |c| c)),
address_hash: Cell::new(None),
storage_overlay: RefCell::new(pod.storage.into_iter().map(|(k, v)| (k, (Filth::Dirty, v))).collect()),
code_hash: Some(pod.code.sha3()),
code_cache: pod.code
}
}
@@ -97,13 +71,9 @@ impl Account {
balance: balance,
nonce: nonce,
storage_root: SHA3_NULL_RLP,
storage_cache: Self::empty_storage_cache(),
storage_changes: HashMap::new(),
code_hash: SHA3_EMPTY,
code_cache: Arc::new(vec![]),
code_size: Some(0),
code_filth: Filth::Clean,
address_hash: Cell::new(None),
storage_overlay: RefCell::new(HashMap::new()),
code_hash: Some(SHA3_EMPTY),
code_cache: vec![],
}
}
@@ -114,13 +84,9 @@ impl Account {
nonce: r.val_at(0),
balance: r.val_at(1),
storage_root: r.val_at(2),
storage_cache: Self::empty_storage_cache(),
storage_changes: HashMap::new(),
code_hash: r.val_at(3),
code_cache: Arc::new(vec![]),
code_size: None,
code_filth: Filth::Clean,
address_hash: Cell::new(None),
storage_overlay: RefCell::new(HashMap::new()),
code_hash: Some(r.val_at(3)),
code_cache: vec![],
}
}
@@ -131,65 +97,29 @@ impl Account {
balance: balance,
nonce: nonce,
storage_root: SHA3_NULL_RLP,
storage_cache: Self::empty_storage_cache(),
storage_changes: HashMap::new(),
code_hash: SHA3_EMPTY,
code_cache: Arc::new(vec![]),
code_size: None,
code_filth: Filth::Clean,
address_hash: Cell::new(None),
storage_overlay: RefCell::new(HashMap::new()),
code_hash: None,
code_cache: vec![],
}
}
/// Set this account's code to the given code.
/// NOTE: Account should have been created with `new_contract()`
pub fn init_code(&mut self, code: Bytes) {
self.code_hash = code.sha3();
self.code_cache = Arc::new(code);
self.code_size = Some(self.code_cache.len() as u64);
self.code_filth = Filth::Dirty;
}
/// Reset this account's code to the given code.
pub fn reset_code(&mut self, code: Bytes) {
self.init_code(code);
assert!(self.code_hash.is_none());
self.code_cache = code;
}
/// Set (and cache) the contents of the trie's storage at `key` to `value`.
pub fn set_storage(&mut self, key: H256, value: H256) {
self.storage_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`.
/// Takes modifed storage into account.
pub fn storage_at(&self, db: &AccountDB, key: &H256) -> H256 {
if let Some(value) = self.cached_storage_at(key) {
return value;
}
let db = SecTrieDB::new(db, &self.storage_root)
.expect("Account storage_root initially set to zero (valid) and only altered by SecTrieDBMut. \
SecTrieDBMut would not set it to an invalid state root. Therefore the root is valid and DB creation \
using it will not fail.");
let item: U256 = match db.get(key){
Ok(x) => x.map_or_else(U256::zero, decode),
Err(e) => panic!("Encountered potential DB corruption: {}", e),
};
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
self.storage_overlay.borrow_mut().entry(key.clone()).or_insert_with(||{
(Filth::Clean, H256::from(SecTrieDB::new(db, &self.storage_root).get(key.bytes()).map_or(U256::zero(), |v| -> U256 {decode(v)})))
}).1.clone()
}
/// return the balance associated with this account.
@@ -198,153 +128,105 @@ impl Account {
/// return the nonce associated with this account.
pub fn nonce(&self) -> &U256 { &self.nonce }
#[cfg(test)]
/// return the code hash associated with this account.
pub fn code_hash(&self) -> H256 {
self.code_hash.clone()
}
/// 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
})
self.code_hash.clone().unwrap_or(SHA3_EMPTY)
}
/// returns the account's code. If `None` then the code cache isn't available -
/// get someone who knows to call `note_code`.
pub fn code(&self) -> Option<Arc<Bytes>> {
if self.code_hash != SHA3_EMPTY && self.code_cache.is_empty() {
return None;
pub fn code(&self) -> Option<&[u8]> {
match self.code_hash {
Some(c) if c == SHA3_EMPTY && self.code_cache.is_empty() => Some(&self.code_cache),
Some(_) if !self.code_cache.is_empty() => Some(&self.code_cache),
None => Some(&self.code_cache),
_ => None,
}
Some(self.code_cache.clone())
}
/// returns the account's code size. If `None` then the code cache or code size cache isn't available -
/// get someone who knows to call `note_code`.
pub fn code_size(&self) -> Option<u64> {
self.code_size.clone()
}
#[cfg(test)]
/// Provide a byte array which hashes to the `code_hash`. returns the hash as a result.
pub fn note_code(&mut self, code: Bytes) -> Result<(), H256> {
let h = code.sha3();
if self.code_hash == h {
self.code_cache = Arc::new(code);
self.code_size = Some(self.code_cache.len() as u64);
Ok(())
} else {
Err(h)
match self.code_hash {
Some(ref i) if h == *i => {
self.code_cache = code;
Ok(())
},
_ => Err(h)
}
}
/// Is `code_cache` valid; such that code is going to return Some?
pub fn is_cached(&self) -> bool {
!self.code_cache.is_empty() || (self.code_cache.is_empty() && self.code_hash == 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 {
// TODO: fill out self.code_cache;
trace!("Account::cache_code: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty());
self.is_cached() ||
match db.get(&self.code_hash) {
Some(x) => {
self.code_cache = Arc::new(x.to_vec());
self.code_size = Some(x.len() as u64);
true
},
_ => {
warn!("Failed reverse get of {}", self.code_hash);
false
},
}
}
/// Provide a database to get `code_size`. Should not be called if it is a contract without code.
pub fn cache_code_size(&mut self, db: &AccountDB) -> bool {
// TODO: fill out self.code_cache;
trace!("Account::cache_code_size: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty());
self.code_size.is_some() ||
if self.code_hash != SHA3_EMPTY {
match db.get(&self.code_hash) {
Some(x) => {
self.code_size = Some(x.len() as u64);
true
},
match self.code_hash {
Some(ref h) => match db.lookup(h) {
Some(x) => { self.code_cache = x.to_vec(); true },
_ => {
warn!("Failed reverse get of {}", self.code_hash);
warn!("Failed reverse lookup of {}", h);
false
},
}
} else {
false
},
_ => false,
}
}
#[cfg(test)]
/// 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() }
#[cfg(test)]
/// return the storage root associated with this account or None if it has been altered via the overlay.
pub fn storage_root(&self) -> Option<&H256> { if self.storage_is_clean() {Some(&self.storage_root)} else {None} }
/// return the storage overlay.
pub fn storage_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.
pub fn inc_nonce(&mut self) {
self.nonce = self.nonce + U256::from(1u8);
}
pub fn inc_nonce(&mut self) { self.nonce = self.nonce + U256::from(1u8); }
/// Increase account balance.
pub fn add_balance(&mut self, x: &U256) {
self.balance = self.balance + *x;
}
/// Increment the nonce of the account by one.
pub fn add_balance(&mut self, x: &U256) { self.balance = self.balance + *x; }
/// Decrease account balance.
/// Increment the nonce of the account by one.
/// Panics if balance is less than `x`
pub fn sub_balance(&mut self, x: &U256) {
assert!(self.balance >= *x);
self.balance = self.balance - *x;
}
/// Commit the `storage_changes` to the backing DB and update `storage_root`.
pub fn commit_storage(&mut self, trie_factory: &TrieFactory, db: &mut AccountDBMut) {
let mut t = trie_factory.from_existing(db, &mut self.storage_root)
.expect("Account storage_root initially set to zero (valid) and only altered by SecTrieDBMut. \
SecTrieDBMut would not set it to an invalid state root. Therefore the root is valid and DB creation \
using it will not fail.");
for (k, v) in self.storage_changes.drain() {
// cast key and value to trait type,
// so we can call overloaded `to_bytes` method
let res = match v.is_zero() {
true => t.remove(k.as_slice()),
false => t.insert(k.as_slice(), &encode(&U256::from(v.as_slice()))),
};
if let Err(e) = res {
warn!("Encountered potential DB corruption: {}", e);
/// Commit the `storage_overlay` to the backing DB and update `storage_root`.
pub fn commit_storage(&mut self, db: &mut AccountDBMut) {
let mut t = SecTrieDBMut::from_existing(db, &mut self.storage_root);
for (k, &mut (ref mut f, ref mut v)) in self.storage_overlay.borrow_mut().iter_mut() {
if f == &Filth::Dirty {
// cast key and value to trait type,
// so we can call overloaded `to_bytes` method
match v.is_zero() {
true => { t.remove(k); },
false => { t.insert(k, &encode(&U256::from(v.as_slice()))); },
}
*f = Filth::Clean;
}
self.storage_cache.borrow_mut().insert(k, v);
}
}
/// Commit any unsaved code. `code_hash` will always return the hash of the `code_cache` after this.
pub fn commit_code(&mut self, db: &mut AccountDBMut) {
trace!("Commiting code of {:?} - {:?}, {:?}", self, self.code_filth == Filth::Dirty, self.code_cache.is_empty());
match (self.code_filth == Filth::Dirty, self.code_cache.is_empty()) {
(true, true) => {
self.code_size = Some(0);
self.code_filth = Filth::Clean;
},
trace!("Commiting code of {:?} - {:?}, {:?}", self, self.code_hash.is_none(), self.code_cache.is_empty());
match (self.code_hash.is_none(), self.code_cache.is_empty()) {
(true, true) => self.code_hash = Some(SHA3_EMPTY),
(true, false) => {
db.emplace(self.code_hash.clone(), (*self.code_cache).clone());
self.code_size = Some(self.code_cache.len() as u64);
self.code_filth = Filth::Clean;
self.code_hash = Some(db.insert(&self.code_cache));
},
(false, _) => {},
}
@@ -356,59 +238,9 @@ impl Account {
stream.append(&self.nonce);
stream.append(&self.balance);
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()
}
/// 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 {
@@ -424,24 +256,14 @@ mod tests {
use super::*;
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]
fn storage_at() {
let mut db = MemoryDB::new();
let mut db = AccountDBMut::new(&mut db, &Address::new());
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.commit_storage(&Default::default(), &mut db);
a.commit_storage(&mut db);
a.init_code(vec![]);
a.commit_code(&mut db);
a.rlp()
@@ -459,7 +281,7 @@ mod tests {
let mut db = AccountDBMut::new(&mut db, &Address::new());
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.commit_code(&mut db);
a.rlp()
@@ -474,57 +296,40 @@ mod tests {
#[test]
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 = 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);
a.commit_storage(&Default::default(), &mut db);
a.commit_storage(&mut db);
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
}
#[test]
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 = AccountDBMut::new(&mut db, &Address::new());
a.set_storage(0.into(), 0x1234.into());
a.commit_storage(&Default::default(), &mut db);
a.set_storage(1.into(), 0x1234.into());
a.commit_storage(&Default::default(), &mut db);
a.set_storage(1.into(), 0.into());
a.commit_storage(&Default::default(), &mut db);
a.set_storage(x!(0), x!(0x1234));
a.commit_storage(&mut db);
a.set_storage(x!(1), x!(0x1234));
a.commit_storage(&mut db);
a.set_storage(x!(1), x!(0));
a.commit_storage(&mut db);
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
}
#[test]
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 = AccountDBMut::new(&mut db, &Address::new());
a.init_code(vec![0x55, 0x44, 0xffu8]);
assert_eq!(a.code_filth, Filth::Dirty);
assert_eq!(a.code_size(), Some(3));
assert_eq!(a.code_hash(), SHA3_EMPTY);
a.commit_code(&mut db);
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]
fn rlpio() {
let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new());
@@ -537,6 +342,8 @@ mod tests {
#[test]
fn new_account() {
use rustc_serialize::hex::ToHex;
let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new());
assert_eq!(a.rlp().to_hex(), "f8448045a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
assert_eq!(a.balance(), &U256::from(69u8));
@@ -547,6 +354,8 @@ mod tests {
#[test]
fn create_account() {
use rustc_serialize::hex::ToHex;
let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new());
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
use util::*;
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?
/// DB backend wrapper for Account trie
/// Transforms trie node keys for the database
pub struct AccountDB<'db> {
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> {
/// Create a new AccountDB from an address.
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 {
pub fn new(db: &'db HashDB, address: &Address) -> AccountDB<'db> {
AccountDB {
db: db,
address_hash: address_hash,
address: x!(address),
}
}
}
@@ -63,18 +30,18 @@ impl<'db> HashDB for AccountDB<'db>{
unimplemented!()
}
fn get(&self, key: &H256) -> Option<&[u8]> {
fn lookup(&self, key: &H256) -> Option<&[u8]> {
if key == &SHA3_NULL_RLP {
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 {
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 {
@@ -85,7 +52,7 @@ impl<'db> HashDB for AccountDB<'db>{
unimplemented!()
}
fn remove(&mut self, _key: &H256) {
fn kill(&mut self, _key: &H256) {
unimplemented!()
}
}
@@ -93,26 +60,20 @@ impl<'db> HashDB for AccountDB<'db>{
/// DB backend wrapper for Account trie
pub struct AccountDBMut<'db> {
db: &'db mut HashDB,
address_hash: H256,
address: H256,
}
impl<'db> AccountDBMut<'db> {
/// Create a new AccountDB from an address.
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 {
pub fn new(db: &'db mut HashDB, address: &Address) -> AccountDBMut<'db> {
AccountDBMut {
db: db,
address_hash: address_hash,
address: x!(address),
}
}
#[allow(dead_code)]
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!()
}
fn get(&self, key: &H256) -> Option<&[u8]> {
fn lookup(&self, key: &H256) -> Option<&[u8]> {
if key == &SHA3_NULL_RLP {
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 {
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 {
@@ -140,7 +101,7 @@ impl<'db> HashDB for AccountDBMut<'db>{
return SHA3_NULL_RLP.clone();
}
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());
k
}
@@ -149,16 +110,16 @@ impl<'db> HashDB for AccountDBMut<'db>{
if key == SHA3_NULL_RLP {
return;
}
let key = combine_key(&self.address_hash, &key);
let key = combine_key(&self.address, &key);
self.db.emplace(key, value.to_vec())
}
fn remove(&mut self, key: &H256) {
fn kill(&mut self, key: &H256) {
if key == &SHA3_NULL_RLP {
return;
}
let key = combine_key(&self.address_hash, key);
self.db.remove(&key)
let key = combine_key(&self.address, key);
self.db.kill(&key)
}
}

View File

@@ -16,56 +16,12 @@
//! Diff between two accounts.
use util::numbers::*;
use std::cmp::*;
use std::fmt;
use ipc::binary::{BinaryConvertError, BinaryConvertable};
use util::Bytes;
use std::collections::{VecDeque, BTreeMap};
use std::mem;
use util::*;
#[cfg(test)]
use pod_account::*;
#[derive(Debug, PartialEq, Eq, Clone, Binary)]
/// Diff type for specifying a change (or not).
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.
#[derive(Debug,Clone,PartialEq,Eq)]
/// Change in existance type.
// TODO: include other types of change.
pub enum 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 {
/// Get `Existance` projection.
pub fn existance(&self) -> Existance {
@@ -96,12 +65,51 @@ impl AccountDiff {
_ => 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.
fn interpreted_hash(u: &H256) -> String {
use util::bytes::*;
if u <= &H256::from(0xffffffff) {
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()) {
@@ -115,8 +123,6 @@ fn interpreted_hash(u: &H256) -> String {
impl fmt::Display for AccountDiff {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use util::bytes::*;
match self.nonce {
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))),

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.
use common::*;
use ethjson;
use types::executed::CallType;
/// Transaction value
#[derive(Clone, Debug)]
@@ -28,23 +26,12 @@ pub enum ActionValue {
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).
/// Action (call/create) input params. Everything else should be specified in Externalities.
#[derive(Clone, Debug)]
pub struct ActionParams {
/// Address of currently executed code.
pub code_address: Address,
/// Hash of currently executed code.
pub code_hash: H256,
/// Receive address. Usually equal to code_address,
/// except when called using CALLCODE.
pub address: Address,
@@ -59,12 +46,9 @@ pub struct ActionParams {
/// Transaction value.
pub value: ActionValue,
/// Code being executed.
pub code: Option<Arc<Bytes>>,
pub code: Option<Bytes>,
/// Input data.
pub data: Option<Bytes>,
/// Type of call
pub call_type: CallType,
pub data: Option<Bytes>
}
impl Default for ActionParams {
@@ -72,7 +56,6 @@ impl Default for ActionParams {
fn default() -> ActionParams {
ActionParams {
code_address: Address::new(),
code_hash: SHA3_EMPTY,
address: Address::new(),
sender: Address::new(),
origin: Address::new(),
@@ -80,27 +63,7 @@ impl Default for ActionParams {
gas_price: U256::zero(),
value: ActionValue::Transfer(U256::zero()),
code: 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?
data: None
}
}
}

View File

@@ -16,16 +16,16 @@
//! Blockchain block.
#![cfg_attr(feature="dev", allow(ptr_arg))] // Because of &LastHashes -> &Vec<_>
use common::*;
use engines::Engine;
use engine::*;
use state::*;
use state_db::StateDB;
use verification::PreverifiedBlock;
use trace::FlatTrace;
use evm::Factory as EvmFactory;
/// 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 {
/// The header of this block.
pub header: Header,
@@ -37,21 +37,27 @@ pub struct Block {
impl Block {
/// 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 {
/*
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()
}
/// 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 {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
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.
#[derive(Clone)]
// TODO: rename to ExecutedBlock
// TODO: use BareBlock
#[derive(Debug)]
pub struct ExecutedBlock {
base: Block,
receipts: Vec<Receipt>,
transactions_set: HashSet<H256>,
state: State,
traces: Option<Vec<Vec<FlatTrace>>>,
}
/// A set of references to `ExecutedBlock` fields that are publicly accessible.
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.
pub header: &'a Header,
/// Block transactions.
pub transactions: &'a [SignedTransaction],
pub transactions: &'a Vec<SignedTransaction>,
/// Block uncles.
pub uncles: &'a [Header],
pub uncles: &'a Vec<Header>,
/// Transaction receipts.
pub receipts: &'a [Receipt],
pub receipts: &'a Vec<Receipt>,
/// State.
pub state: &'a State,
/// Traces.
pub traces: &'a Option<Vec<Vec<FlatTrace>>>,
pub state: &'a mut State,
}
impl ExecutedBlock {
/// Create a new block from the given `state`.
fn new(state: State, tracing: bool) -> ExecutedBlock {
ExecutedBlock {
base: Default::default(),
receipts: Default::default(),
transactions_set: Default::default(),
state: state,
traces: if tracing {Some(Vec::new())} else {None},
}
}
fn new(state: State) -> ExecutedBlock { ExecutedBlock { base: Default::default(), receipts: Default::default(), transactions_set: Default::default(), state: state } }
/// Get a structure containing individual references to all public fields.
pub fn fields_mut(&mut self) -> BlockRefMut {
pub fn fields(&mut self) -> BlockRefMut {
BlockRefMut {
header: &mut self.base.header,
header: &self.base.header,
transactions: &self.base.transactions,
uncles: &self.base.uncles,
state: &mut self.state,
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 {
/// Get the `ExecutedBlock` associated with this object.
/// Get the block associated with this object.
fn block(&self) -> &ExecutedBlock;
/// Get the base `Block` object associated with this.
fn base(&self) -> &Block { &self.block().base }
/// Get the header associated with this object's block.
fn header(&self) -> &Header { &self.block().base.header }
@@ -164,22 +129,13 @@ pub trait IsBlock {
fn state(&self) -> &State { &self.block().state }
/// 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.
fn receipts(&self) -> &[Receipt] { &self.block().receipts }
/// Get all information concerning transaction tracing in this block.
fn traces(&self) -> &Option<Vec<Vec<FlatTrace>>> { &self.block().traces }
fn receipts(&self) -> &Vec<Receipt> { &self.block().receipts }
/// Get all uncles in this block.
fn uncles(&self) -> &[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;
fn uncles(&self) -> &Vec<Header> { &self.block().base.uncles }
}
impl IsBlock for ExecutedBlock {
@@ -193,59 +149,32 @@ impl IsBlock for ExecutedBlock {
pub struct OpenBlock<'x> {
block: ExecutedBlock,
engine: &'x Engine,
vm_factory: &'x EvmFactory,
last_hashes: Arc<LastHashes>,
last_hashes: 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.
///
/// There is no function available to push a transaction.
#[derive(Clone)]
pub struct ClosedBlock {
block: ExecutedBlock,
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.
///
/// 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 {
block: ExecutedBlock,
uncle_bytes: Bytes,
}
impl<'x> OpenBlock<'x> {
#[cfg_attr(feature="dev", allow(too_many_arguments))]
/// Create a new `OpenBlock` ready for transaction pushing.
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));
/// 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 {
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,
vm_factory: vm_factory,
last_hashes: last_hashes,
};
@@ -256,9 +185,9 @@ impl<'x> OpenBlock<'x> {
r.block.base.header.extra_data = extra_data;
r.block.base.header.note_dirty();
engine.populate_from_parent(&mut r.block.base.header, parent, gas_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);
Ok(r)
r
}
/// Alter the author for the block.
@@ -276,15 +205,6 @@ impl<'x> OpenBlock<'x> {
/// Alter the gas limit for the block.
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.
pub fn set_extra_data(&mut self, extra_data: Bytes) -> Result<(), BlockError> {
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(),
timestamp: self.block.base.header.timestamp,
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_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.
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();
// 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()) {
Ok(outcome) => {
match self.block.state.apply(&env_info, self.engine, &t) {
Ok(receipt) => {
self.block.transactions_set.insert(h.unwrap_or_else(||t.hash()));
self.block.base.transactions.push(t);
let t = outcome.trace;
self.block.traces.as_mut().map(|traces| traces.push(t));
self.block.receipts.push(outcome.receipt);
Ok(self.block.receipts.last().unwrap())
self.block.receipts.push(receipt);
Ok(&self.block.receipts.last().unwrap())
}
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 {
let mut s = self;
let unclosed_state = s.block.state.clone();
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());
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 {
block: s.block,
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> {
@@ -409,40 +288,10 @@ impl<'x> IsBlock for ClosedBlock {
fn block(&self) -> &ExecutedBlock { &self.block }
}
impl<'x> IsBlock for LockedBlock {
fn block(&self) -> &ExecutedBlock { &self.block }
}
impl ClosedBlock {
/// Get the hash of the header without seal arguments.
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`.
///
/// 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`.
/// This does check the validity of `seal` with the engine.
/// 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;
s.block.base.header.set_seal(seal);
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 }),
}
}
}
impl Drain for LockedBlock {
/// Drop this object and return the underlieing database.
fn drain(self) -> StateDB {
self.block.state.drop().1
}
pub fn drain(self) -> Box<JournalDB> { self.block.state.drop().1 }
}
impl SealedBlock {
@@ -484,13 +329,9 @@ impl SealedBlock {
block_rlp.append_raw(&self.uncle_bytes, 1);
block_rlp.out()
}
}
impl Drain for SealedBlock {
/// Drop this object and return the underlieing database.
fn drain(self) -> StateDB {
self.block.state.drop().1
}
pub fn drain(self) -> Box<JournalDB> { self.block.state.drop().1 }
}
impl IsBlock for SealedBlock {
@@ -498,87 +339,40 @@ impl IsBlock for SealedBlock {
}
/// 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,
tracing: bool,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
vm_factory: &EvmFactory,
trie_factory: TrieFactory,
) -> Result<LockedBlock, Error> {
pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes) -> Result<ClosedBlock, Error> {
{
if ::log::max_log_level() >= ::log::LogLevel::Trace {
let s = try!(State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce(), trie_factory.clone()));
trace!(target: "enact", "num={}, root={}, author={}, author_balance={}\n", header.number(), s.root(), header.author(), s.balance(&header.author()));
let s = State::from_existing(db.spawn(), parent.state_root().clone(), engine.account_start_nonce());
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_gas_limit(*header.gas_limit());
b.set_timestamp(header.timestamp());
b.set_author(header.author().clone());
b.set_extra_data(header.extra_data().clone()).unwrap_or_else(|e| warn!("Couldn't set extradata: {}. Ignoring.", e));
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 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
#[cfg_attr(feature="dev", allow(too_many_arguments))]
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> {
pub fn enact_bytes(block_bytes: &[u8], engine: &Engine, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes) -> Result<ClosedBlock, Error> {
let block = BlockView::new(block_bytes);
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
#[cfg_attr(feature="dev", allow(too_many_arguments))]
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> {
pub fn enact_verified(block: &PreverifiedBlock, engine: &Engine, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes) -> Result<ClosedBlock, Error> {
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
#[cfg_attr(feature="dev", allow(too_many_arguments))]
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> {
pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes) -> Result<SealedBlock, Error> {
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)]
@@ -586,79 +380,72 @@ mod tests {
use tests::helpers::*;
use super::*;
use common::*;
use engine::*;
#[test]
fn open_block() {
use spec::*;
let spec = Spec::new_test();
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_state_db();
let engine = Spec::new_test().to_engine().unwrap();
let genesis_header = engine.spec().genesis_header();
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(&mut db).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let vm_factory = Default::default();
let b = OpenBlock::new(&*spec.engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close_and_lock();
let _ = b.seal(&*spec.engine, vec![]);
engine.spec().ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
let b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]);
let b = b.close();
let _ = b.seal(engine.deref(), vec![]);
}
#[test]
fn enact_block() {
use spec::*;
let spec = Spec::new_test();
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();
let engine = Spec::new_test().to_engine().unwrap();
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();
spec.ensure_db_good(&mut db).unwrap();
let vm_factory = Default::default();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let b = OpenBlock::new(engine, &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();
engine.spec().ensure_db_good(db.as_hashdb_mut());
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 orig_bytes = b.rlp_bytes();
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();
spec.ensure_db_good(&mut db).unwrap();
let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, &Default::default(), Default::default()).unwrap();
engine.spec().ensure_db_good(db.as_hashdb_mut());
let e = enact_and_seal(&orig_bytes, engine.deref(), db, &genesis_header, vec![genesis_header.hash()]).unwrap();
assert_eq!(e.rlp_bytes(), orig_bytes);
let db = e.drain();
assert_eq!(orig_db.journal_db().keys(), db.journal_db().keys());
assert!(orig_db.journal_db().keys().iter().filter(|k| orig_db.journal_db().get(k.0) != db.journal_db().get(k.0)).next() == None);
assert_eq!(orig_db.keys(), db.keys());
assert!(orig_db.keys().iter().filter(|k| orig_db.get(k.0) != db.get(k.0)).next() == None);
}
#[test]
fn enact_block_with_uncle() {
use spec::*;
let spec = Spec::new_test();
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();
let engine = Spec::new_test().to_engine().unwrap();
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();
spec.ensure_db_good(&mut db).unwrap();
let vm_factory = Default::default();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let mut open_block = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
engine.spec().ensure_db_good(db.as_hashdb_mut());
let mut open_block = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()], Address::zero(), x!(3141562), vec![]);
let mut uncle1_header = Header::new();
uncle1_header.extra_data = b"uncle1".to_vec();
let mut uncle2_header = Header::new();
uncle2_header.extra_data = b"uncle2".to_vec();
open_block.push_uncle(uncle1_header).unwrap();
open_block.push_uncle(uncle2_header).unwrap();
let b = open_block.close_and_lock().seal(engine, vec![]).unwrap();
let b = open_block.close().seal(engine.deref(), vec![]).unwrap();
let orig_bytes = b.rlp_bytes();
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();
spec.ensure_db_good(&mut db).unwrap();
let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, &Default::default(), Default::default()).unwrap();
engine.spec().ensure_db_good(db.as_hashdb_mut());
let e = enact_and_seal(&orig_bytes, engine.deref(), db, &genesis_header, vec![genesis_header.hash()]).unwrap();
let bytes = e.rlp_bytes();
assert_eq!(bytes, orig_bytes);
@@ -666,7 +453,7 @@ mod tests {
assert_eq!(uncles[1].extra_data, b"uncle2");
let db = e.drain();
assert_eq!(orig_db.journal_db().keys(), db.journal_db().keys());
assert!(orig_db.journal_db().keys().iter().filter(|k| orig_db.journal_db().get(k.0) != db.journal_db().get(k.0)).next() == None);
assert_eq!(orig_db.keys(), db.keys());
assert!(orig_db.keys().iter().filter(|k| orig_db.get(k.0) != db.get(k.0)).next() == None);
}
}

View File

@@ -14,22 +14,19 @@
// You should have received a copy of the GNU General Public License
// 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.
use std::thread::{JoinHandle, self};
use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering};
use std::sync::{Condvar as SCondvar, Mutex as SMutex};
use util::*;
use io::*;
use verification::*;
use error::*;
use engines::Engine;
use engine::Engine;
use views::*;
use header::*;
use service::*;
use client::BlockStatus;
pub use types::block_queue_info::BlockQueueInfo;
use util::panics::*;
known_heap_size!(0, UnverifiedBlock, VerifyingBlock, PreverifiedBlock);
@@ -37,7 +34,7 @@ const MIN_MEM_LIMIT: usize = 16384;
const MIN_QUEUE_LIMIT: usize = 512;
/// Block queue configuration
#[derive(Debug, PartialEq)]
#[derive(Debug)]
pub struct BlockQueueConfig {
/// Maximum number of blocks to keep in unverified queue.
/// 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 {
/// The total size of the queues.
@@ -76,17 +89,17 @@ impl BlockQueueInfo {
}
}
/// 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.
pub struct BlockQueue {
panic_handler: Arc<PanicHandler>,
engine: Arc<Engine>,
more_to_verify: Arc<SCondvar>,
engine: Arc<Box<Engine>>,
more_to_verify: Arc<Condvar>,
verification: Arc<Verification>,
verifiers: Vec<JoinHandle<()>>,
deleting: Arc<AtomicBool>,
ready_signal: Arc<QueueSignal>,
empty: Arc<SCondvar>,
empty: Arc<Condvar>,
processing: RwLock<HashSet<H256>>,
max_queue_size: usize,
max_mem_use: usize,
@@ -105,7 +118,7 @@ struct VerifyingBlock {
struct QueueSignal {
deleting: Arc<AtomicBool>,
signalled: AtomicBool,
message_channel: IoChannel<ClientIoMessage>,
message_channel: IoChannel<NetSyncMessage>,
}
impl QueueSignal {
@@ -117,9 +130,7 @@ impl QueueSignal {
}
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);
}
self.message_channel.send(UserMessage(SyncMessage::BlockVerified)).expect("Error sending BlockVerified message");
}
}
@@ -134,30 +145,25 @@ struct Verification {
verified: Mutex<VecDeque<PreverifiedBlock>>,
verifying: Mutex<VecDeque<VerifyingBlock>>,
bad: Mutex<HashSet<H256>>,
more_to_verify: SMutex<()>,
empty: SMutex<()>,
}
impl BlockQueue {
/// 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 {
unverified: Mutex::new(VecDeque::new()),
verified: Mutex::new(VecDeque::new()),
verifying: Mutex::new(VecDeque::new()),
bad: Mutex::new(HashSet::new()),
more_to_verify: SMutex::new(()),
empty: SMutex::new(()),
});
let more_to_verify = Arc::new(SCondvar::new());
let more_to_verify = Arc::new(Condvar::new());
let deleting = Arc::new(AtomicBool::new(false));
let ready_signal = Arc::new(QueueSignal {
deleting: deleting.clone(),
signalled: AtomicBool::new(false),
message_channel: message_channel
});
let empty = Arc::new(SCondvar::new());
let empty = Arc::new(Condvar::new());
let panic_handler = PanicHandler::new_in_arc();
let mut verifiers: Vec<JoinHandle<()>> = Vec::new();
@@ -196,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) {
{
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();
}
while verification.unverified.lock().is_empty() && !deleting.load(AtomicOrdering::Acquire) {
more_to_verify = wait.wait(more_to_verify).unwrap();
while unverified.is_empty() && !deleting.load(AtomicOrdering::Acquire) {
unverified = wait.wait(unverified).unwrap();
}
if deleting.load(AtomicOrdering::Acquire) {
@@ -215,20 +221,20 @@ impl BlockQueue {
}
let block = {
let mut unverified = verification.unverified.lock();
let mut unverified = verification.unverified.lock().unwrap();
if unverified.is_empty() {
continue;
}
let mut verifying = verification.verifying.lock();
let mut verifying = verification.verifying.lock().unwrap();
let block = unverified.pop_front().unwrap();
verifying.push_back(VerifyingBlock{ hash: block.header.hash(), block: None });
block
};
let block_hash = block.header.hash();
match verify_block_unordered(block.header, block.bytes, &*engine) {
match verify_block_unordered(block.header, block.bytes, engine.deref().deref()) {
Ok(verified) => {
let mut verifying = verification.verifying.lock();
let mut verifying = verification.verifying.lock().unwrap();
for e in verifying.iter_mut() {
if e.hash == block_hash {
e.block = Some(verified);
@@ -237,16 +243,16 @@ impl BlockQueue {
}
if !verifying.is_empty() && verifying.front().unwrap().hash == block_hash {
// we're next!
let mut verified = verification.verified.lock();
let mut bad = verification.bad.lock();
let mut verified = verification.verified.lock().unwrap();
let mut bad = verification.bad.lock().unwrap();
BlockQueue::drain_verifying(&mut verifying, &mut verified, &mut bad);
ready.set();
}
},
Err(err) => {
let mut verifying = verification.verifying.lock();
let mut verified = verification.verified.lock();
let mut bad = verification.bad.lock();
let mut verifying = verification.verifying.lock().unwrap();
let mut verified = verification.verified.lock().unwrap();
let mut bad = verification.bad.lock().unwrap();
warn!(target: "client", "Stage 2 block verification failed for {}\nError: {:?}", block_hash, err);
bad.insert(block_hash.clone());
verifying.retain(|e| e.hash != block_hash);
@@ -271,29 +277,29 @@ impl BlockQueue {
/// Clear the queue and stop verification activity.
pub fn clear(&self) {
let mut unverified = self.verification.unverified.lock();
let mut verifying = self.verification.verifying.lock();
let mut verified = self.verification.verified.lock();
let mut unverified = self.verification.unverified.lock().unwrap();
let mut verifying = self.verification.verifying.lock().unwrap();
let mut verified = self.verification.verified.lock().unwrap();
unverified.clear();
verifying.clear();
verified.clear();
self.processing.write().clear();
self.processing.write().unwrap().clear();
}
/// Wait for unverified queue to be empty
pub fn flush(&self) {
let mut lock = self.verification.empty.lock().unwrap();
while !self.verification.unverified.lock().is_empty() || !self.verification.verifying.lock().is_empty() {
lock = self.empty.wait(lock).unwrap();
let mut unverified = self.verification.unverified.lock().unwrap();
while !unverified.is_empty() || !self.verification.verifying.lock().unwrap().is_empty() {
unverified = self.empty.wait(unverified).unwrap();
}
}
/// Check if the block is currently in the queue
pub fn block_status(&self, hash: &H256) -> BlockStatus {
if self.processing.read().contains(hash) {
if self.processing.read().unwrap().contains(&hash) {
return BlockStatus::Queued;
}
if self.verification.bad.lock().contains(hash) {
if self.verification.bad.lock().unwrap().contains(&hash) {
return BlockStatus::Bad;
}
BlockStatus::Unknown
@@ -304,31 +310,31 @@ impl BlockQueue {
let header = BlockView::new(&bytes).header();
let h = header.hash();
{
if self.processing.read().contains(&h) {
return Err(ImportError::AlreadyQueued.into());
if self.processing.read().unwrap().contains(&h) {
return Err(x!(ImportError::AlreadyQueued));
}
let mut bad = self.verification.bad.lock();
let mut bad = self.verification.bad.lock().unwrap();
if bad.contains(&h) {
return Err(ImportError::KnownBad.into());
return Err(x!(ImportError::KnownBad));
}
if bad.contains(&header.parent_hash) {
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(()) => {
self.processing.write().insert(h.clone());
self.verification.unverified.lock().push_back(UnverifiedBlock { header: header, bytes: bytes });
self.processing.write().unwrap().insert(h.clone());
self.verification.unverified.lock().unwrap().push_back(UnverifiedBlock { header: header, bytes: bytes });
self.more_to_verify.notify_all();
Ok(h)
},
Err(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)
}
}
@@ -339,14 +345,14 @@ impl BlockQueue {
if block_hashes.is_empty() {
return;
}
let mut verified_lock = self.verification.verified.lock();
let mut verified = &mut *verified_lock;
let mut bad = self.verification.bad.lock();
let mut processing = self.processing.write();
let mut verified_lock = self.verification.verified.lock().unwrap();
let mut verified = verified_lock.deref_mut();
let mut bad = self.verification.bad.lock().unwrap();
let mut processing = self.processing.write().unwrap();
bad.reserve(block_hashes.len());
for hash in block_hashes {
bad.insert(hash.clone());
processing.remove(hash);
processing.remove(&hash);
}
let mut new_verified = VecDeque::new();
@@ -366,15 +372,15 @@ impl BlockQueue {
if block_hashes.is_empty() {
return;
}
let mut processing = self.processing.write();
let mut processing = self.processing.write().unwrap();
for hash in block_hashes {
processing.remove(hash);
processing.remove(&hash);
}
}
/// Removes up to `max` verified blocks from the queue
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 mut result = Vec::with_capacity(count);
for _ in 0..count {
@@ -391,15 +397,15 @@ impl BlockQueue {
/// Get queue status.
pub fn queue_info(&self) -> BlockQueueInfo {
let (unverified_len, unverified_bytes) = {
let v = self.verification.unverified.lock();
let v = self.verification.unverified.lock().unwrap();
(v.len(), v.heap_size_of_children())
};
let (verifying_len, verifying_bytes) = {
let v = self.verification.verifying.lock();
let v = self.verification.verifying.lock().unwrap();
(v.len(), v.heap_size_of_children())
};
let (verified_len, verified_bytes) = {
let v = self.verification.verified.lock();
let v = self.verification.verified.lock().unwrap();
(v.len(), v.heap_size_of_children())
};
BlockQueueInfo {
@@ -413,18 +419,18 @@ impl BlockQueue {
+ verifying_bytes
+ verified_bytes
// TODO: https://github.com/servo/heapsize/pull/50
//+ self.processing.read().heap_size_of_children(),
//+ self.processing.read().unwrap().heap_size_of_children(),
}
}
/// Optimise memory footprint of the heap fields.
pub fn collect_garbage(&self) {
{
self.verification.unverified.lock().shrink_to_fit();
self.verification.verifying.lock().shrink_to_fit();
self.verification.verified.lock().shrink_to_fit();
self.verification.unverified.lock().unwrap().shrink_to_fit();
self.verification.verifying.lock().unwrap().shrink_to_fit();
self.verification.verified.lock().unwrap().shrink_to_fit();
}
self.processing.write().shrink_to_fit();
self.processing.write().unwrap().shrink_to_fit();
}
}
@@ -450,7 +456,6 @@ impl Drop for BlockQueue {
#[cfg(test)]
mod tests {
use util::*;
use io::*;
use spec::*;
use block_queue::*;
use tests::helpers::*;
@@ -459,16 +464,16 @@ mod tests {
fn get_test_queue() -> BlockQueue {
let spec = get_test_spec();
let engine = spec.engine;
BlockQueue::new(BlockQueueConfig::default(), engine, IoChannel::disconnected())
let engine = spec.to_engine().unwrap();
BlockQueue::new(BlockQueueConfig::default(), Arc::new(engine), IoChannel::disconnected())
}
#[test]
fn can_be_created() {
// TODO better test
let spec = Spec::new_test();
let engine = spec.engine;
let _ = BlockQueue::new(BlockQueueConfig::default(), engine, IoChannel::disconnected());
let engine = spec.to_engine().unwrap();
let _ = BlockQueue::new(BlockQueueConfig::default(), Arc::new(engine), IoChannel::disconnected());
}
#[test]
@@ -528,10 +533,10 @@ mod tests {
#[test]
fn test_mem_limit() {
let spec = get_test_spec();
let engine = spec.engine;
let engine = spec.to_engine().unwrap();
let mut config = BlockQueueConfig::default();
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());
let mut blocks = get_good_dummy_block_seq(50);
for b in blocks.drain(..) {

View File

@@ -14,7 +14,6 @@
// 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::bytes::Bytes;
use util::numbers::{U256,H256};
use header::BlockNumber;
@@ -26,7 +25,5 @@ pub struct BestBlock {
/// Best block number.
pub number: BlockNumber,
/// Best block total difficulty.
pub total_difficulty: U256,
/// Best block uncompressed bytes
pub block: Bytes,
pub total_difficulty: U256
}

View File

@@ -31,24 +31,21 @@ pub struct BlockInfo {
}
/// Describes location of newly inserted block.
#[derive(Debug, Clone)]
#[derive(Clone)]
pub enum BlockLocation {
/// It's part of the canon chain.
CanonChain,
/// It's not a part of the canon chain.
Branch,
/// 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.
BranchBecomingCanonChain(BranchBecomingCanonChainData),
}
#[derive(Debug, Clone)]
pub struct BranchBecomingCanonChainData {
/// Hash of the newest common ancestor with old canon chain.
pub ancestor: 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>,
BranchBecomingCanonChain {
/// Hash of the newest common ancestor with old canon chain.
ancestor: H256,
/// Hashes of the blocks between ancestor and this block.
enacted: Vec<H256>,
/// Hashes of the blocks which were invalidated.
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,
/// Transaction addresses cache size.
pub transaction_addresses: usize,
/// Logs cache size.
pub block_logs: usize,
/// Blooms cache size.
pub blocks_blooms: usize,
/// Block receipts size.
@@ -31,7 +33,5 @@ pub struct CacheSize {
impl CacheSize {
/// Total amount used by the cache.
pub fn total(&self) -> usize {
self.blocks + self.block_details + self.transaction_addresses + self.blocks_blooms + self.block_receipts
}
pub fn total(&self) -> usize { self.blocks + self.block_details + self.transaction_addresses + self.block_logs + self.blocks_blooms }
}

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

View File

@@ -18,12 +18,10 @@ use util::hash::H2048;
use util::numbers::U256;
use util::bytes::Bytes;
use header::BlockNumber;
use transaction::SignedTransaction;
use super::fork::Fork;
use super::bloom::Bloom;
use super::complete::{BlockFinalizer, CompleteBlock, Complete};
use super::block::Block;
use super::transaction::Transaction;
/// Chain iterator interface.
pub trait ChainIterator: Iterator + Sized {
@@ -32,8 +30,6 @@ pub trait ChainIterator: Iterator + Sized {
fn fork(&self, fork_number: usize) -> Fork<Self> where Self: Clone;
/// Should be called to make every consecutive block have given bloom.
fn with_bloom(&mut self, bloom: H2048) -> Bloom<Self>;
/// Should be called to make every consecutive block have given transaction.
fn with_transaction(&mut self, transaction: SignedTransaction) -> Transaction<Self>;
/// Should be called to complete block. Without complete, block may have incorrect hash.
fn complete<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Complete<'a, Self>;
/// Completes and generates block.
@@ -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> {
Complete {
iter: self,
@@ -96,7 +85,7 @@ impl Default for ChainGenerator {
fn default() -> Self {
ChainGenerator {
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
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Blockchain generator for tests.
mod bloom;
mod block;
mod complete;
mod fork;
pub mod generator;
mod transaction;
pub use self::complete::BlockFinalizer;
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>,
/// Blocks that were validated by new block.
pub enacted: Vec<H256>,
/// Blocks which are neither retracted nor enacted.
pub omitted: Vec<H256>,
}
impl ImportRoute {
@@ -35,7 +33,6 @@ impl ImportRoute {
ImportRoute {
retracted: vec![],
enacted: vec![],
omitted: vec![],
}
}
}
@@ -46,19 +43,13 @@ impl From<BlockInfo> for ImportRoute {
BlockLocation::CanonChain => ImportRoute {
retracted: vec![],
enacted: vec![info.hash],
omitted: vec![],
},
BlockLocation::Branch => ImportRoute {
retracted: vec![],
enacted: vec![],
omitted: vec![info.hash],
},
BlockLocation::BranchBecomingCanonChain(mut data) => {
data.enacted.push(info.hash);
BlockLocation::Branch => ImportRoute::none(),
BlockLocation::BranchBecomingCanonChain { mut enacted, retracted, .. } => {
enacted.push(info.hash);
ImportRoute {
retracted: data.retracted,
enacted: data.enacted,
omitted: vec![],
retracted: retracted,
enacted: enacted,
}
}
}
@@ -69,7 +60,7 @@ impl From<BlockInfo> for ImportRoute {
mod tests {
use util::hash::H256;
use util::numbers::U256;
use blockchain::block_info::{BlockInfo, BlockLocation, BranchBecomingCanonChainData};
use blockchain::block_info::{BlockInfo, BlockLocation};
use blockchain::ImportRoute;
#[test]
@@ -77,7 +68,6 @@ mod tests {
assert_eq!(ImportRoute::none(), ImportRoute {
enacted: vec![],
retracted: vec![],
omitted: vec![],
});
}
@@ -90,11 +80,7 @@ mod tests {
location: BlockLocation::Branch,
};
assert_eq!(ImportRoute::from(info), ImportRoute {
retracted: vec![],
enacted: vec![],
omitted: vec![H256::from(U256::from(1))],
});
assert_eq!(ImportRoute::from(info), ImportRoute::none());
}
#[test]
@@ -109,7 +95,6 @@ mod tests {
assert_eq!(ImportRoute::from(info), ImportRoute {
retracted: vec![],
enacted: vec![H256::from(U256::from(1))],
omitted: vec![],
});
}
@@ -119,17 +104,16 @@ mod tests {
hash: H256::from(U256::from(2)),
number: 0,
total_difficulty: U256::from(0),
location: BlockLocation::BranchBecomingCanonChain(BranchBecomingCanonChainData {
ancestor: H256::from(U256::from(0)),
location: BlockLocation::BranchBecomingCanonChain {
ancestor: H256::from(U256::from(0)),
enacted: vec![H256::from(U256::from(1))],
retracted: vec![H256::from(U256::from(3)), H256::from(U256::from(4))],
})
}
};
assert_eq!(ImportRoute::from(info), ImportRoute {
retracted: vec![H256::from(U256::from(3)), H256::from(U256::from(4))],
enacted: vec![H256::from(U256::from(1)), H256::from(U256::from(2))],
omitted: vec![],
});
}
}

View File

@@ -16,20 +16,18 @@
//! Blockchain database.
pub mod blockchain;
mod best_block;
mod block_info;
pub mod blockchain;
mod bloom_indexer;
mod cache;
mod config;
pub mod extras;
mod import_route;
mod tree_route;
mod update;
mod import_route;
#[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::config::Config;
pub use types::tree_route::TreeRoute;
pub use self::tree_route::TreeRoute;
pub use self::import_route::ImportRoute;

View File

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

View File

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

View File

@@ -1,62 +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 bloomchain as bc;
use util::rlp::*;
use util::HeapSizeOf;
use basic_types::LogBloom;
/// Helper structure representing bloom of the trace.
#[derive(Debug, Clone)]
pub struct Bloom(LogBloom);
impl From<LogBloom> for Bloom {
fn from(bloom: LogBloom) -> Self {
Bloom(bloom)
}
}
impl From<bc::Bloom> for Bloom {
fn from(bloom: bc::Bloom) -> Self {
let bytes: [u8; 256] = bloom.into();
Bloom(LogBloom::from(bytes))
}
}
impl Into<bc::Bloom> for Bloom {
fn into(self) -> bc::Bloom {
let log = self.0;
bc::Bloom::from(log.0)
}
}
impl Decodable for Bloom {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
Decodable::decode(decoder).map(Bloom)
}
}
impl Encodable for Bloom {
fn rlp_append(&self, s: &mut RlpStream) {
Encodable::rlp_append(&self.0, s)
}
}
impl HeapSizeOf for Bloom {
fn heap_size_of_children(&self) -> usize {
0
}
}

View File

@@ -1,74 +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 bloomchain::group as bc;
use util::rlp::*;
use util::HeapSizeOf;
use super::Bloom;
/// Represents group of X consecutive blooms.
#[derive(Debug, Clone)]
pub struct BloomGroup {
blooms: Vec<Bloom>,
}
impl From<bc::BloomGroup> for BloomGroup {
fn from(group: bc::BloomGroup) -> Self {
let blooms = group.blooms
.into_iter()
.map(From::from)
.collect();
BloomGroup {
blooms: blooms
}
}
}
impl Into<bc::BloomGroup> for BloomGroup {
fn into(self) -> bc::BloomGroup {
let blooms = self.blooms
.into_iter()
.map(Into::into)
.collect();
bc::BloomGroup {
blooms: blooms
}
}
}
impl Decodable for BloomGroup {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let blooms = try!(Decodable::decode(decoder));
let group = BloomGroup {
blooms: blooms
};
Ok(group)
}
}
impl Encodable for BloomGroup {
fn rlp_append(&self, s: &mut RlpStream) {
Encodable::rlp_append(&self.blooms, s)
}
}
impl HeapSizeOf for BloomGroup {
fn heap_size_of_children(&self) -> usize {
self.blooms.heap_size_of_children()
}
}

View File

@@ -1,25 +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/>.
//! Bridge between bloomchain crate types and ethcore.
mod bloom;
mod bloom_group;
mod group_position;
pub use self::bloom::Bloom;
pub use self::bloom_group::BloomGroup;
pub use self::group_position::GroupPosition;

View File

@@ -18,7 +18,6 @@ use util::*;
use crypto::sha2::Sha256;
use crypto::ripemd160::Ripemd160;
use crypto::digest::Digest;
use ethjson;
/// Definition of a contract whose implementation is built-in.
pub struct Builtin {
@@ -47,12 +46,13 @@ impl Builtin {
}
/// Create a new object from a builtin-function name with a linear cost associated with input size.
pub fn from_named_linear(name: &str, base_cost: usize, word_cost: usize) -> Builtin {
let cost = Box::new(move|s: usize| -> U256 {
U256::from(base_cost) + U256::from(word_cost) * U256::from((s + 31) / 32)
});
Self::new(cost, new_builtin_exec(name))
pub fn from_named_linear(name: &str, base_cost: usize, word_cost: usize) -> Option<Builtin> {
new_builtin_exec(name).map(|b| {
let cost = Box::new(move|s: usize| -> U256 {
U256::from(base_cost) + U256::from(word_cost) * U256::from((s + 31) / 32)
});
Self::new(cost, b)
})
}
/// Simple forwarder for cost.
@@ -60,15 +60,24 @@ impl Builtin {
/// Simple forwarder for execute.
pub fn execute(&self, input: &[u8], output: &mut[u8]) { (*self.execute)(input, output); }
}
impl From<ethjson::spec::Builtin> for Builtin {
fn from(b: ethjson::spec::Builtin) -> Self {
match b.pricing {
ethjson::spec::Pricing::Linear(linear) => {
Self::from_named_linear(b.name.as_ref(), linear.base, linear.word)
/// Create a builtin from JSON.
///
/// JSON must be of the form `{ "name": "identity", "pricing": {"base": 10, "word": 20} }`.
pub fn from_json(json: &Json) -> Option<Builtin> {
// NICE: figure out a more convenient means of handing errors here.
if let Json::String(ref name) = json["name"] {
if let Json::Object(ref o) = json["pricing"] {
if let Json::Object(ref o) = o["linear"] {
if let Json::U64(ref word) = o["word"] {
if let Json::U64(ref base) = o["base"] {
return Self::from_named_linear(&name[..], *base as usize, *word as usize);
}
}
}
}
}
None
}
}
@@ -83,14 +92,14 @@ pub fn copy_to(src: &[u8], dest: &mut[u8]) {
/// Create a new builtin executor according to `name`.
/// TODO: turn in to a factory with dynamic registration.
pub fn new_builtin_exec(name: &str) -> Box<Fn(&[u8], &mut [u8])> {
pub fn new_builtin_exec(name: &str) -> Option<Box<Fn(&[u8], &mut [u8])>> {
match name {
"identity" => Box::new(move|input: &[u8], output: &mut[u8]| {
"identity" => Some(Box::new(move|input: &[u8], output: &mut[u8]| {
for i in 0..min(input.len(), output.len()) {
output[i] = input[i];
}
}),
"ecrecover" => Box::new(move|input: &[u8], output: &mut[u8]| {
})),
"ecrecover" => Some(Box::new(move|input: &[u8], output: &mut[u8]| {
#[repr(packed)]
#[derive(Debug)]
struct InType {
@@ -113,8 +122,8 @@ pub fn new_builtin_exec(name: &str) -> Box<Fn(&[u8], &mut [u8])> {
}
}
}
}),
"sha256" => Box::new(move|input: &[u8], output: &mut[u8]| {
})),
"sha256" => Some(Box::new(move|input: &[u8], output: &mut[u8]| {
let mut sha = Sha256::new();
sha.input(input);
if output.len() >= 32 {
@@ -124,23 +133,21 @@ pub fn new_builtin_exec(name: &str) -> Box<Fn(&[u8], &mut [u8])> {
sha.result(ret.as_slice_mut());
copy_to(&ret, output);
}
}),
"ripemd160" => Box::new(move|input: &[u8], output: &mut[u8]| {
})),
"ripemd160" => Some(Box::new(move|input: &[u8], output: &mut[u8]| {
let mut sha = Ripemd160::new();
sha.input(input);
let mut ret = H256::new();
sha.result(&mut ret.as_slice_mut()[12..32]);
copy_to(&ret, output);
}),
_ => {
panic!("invalid builtin name {}", name);
}
})),
_ => None
}
}
#[test]
fn identity() {
let f = new_builtin_exec("identity");
let f = new_builtin_exec("identity").unwrap();
let i = [0u8, 1, 2, 3];
let mut o2 = [255u8; 2];
@@ -160,7 +167,7 @@ fn identity() {
#[test]
fn sha256() {
use rustc_serialize::hex::FromHex;
let f = new_builtin_exec("sha256");
let f = new_builtin_exec("sha256").unwrap();
let i = [0u8; 0];
let mut o = [255u8; 32];
@@ -179,7 +186,7 @@ fn sha256() {
#[test]
fn ripemd160() {
use rustc_serialize::hex::FromHex;
let f = new_builtin_exec("ripemd160");
let f = new_builtin_exec("ripemd160").unwrap();
let i = [0u8; 0];
let mut o = [255u8; 32];
@@ -206,7 +213,7 @@ fn ecrecover() {
let s = k.sign(&m).unwrap();
println!("Signed: {}", s);*/
let f = new_builtin_exec("ecrecover");
let f = new_builtin_exec("ecrecover").unwrap();
let i = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap();
let mut o = [255u8; 32];
@@ -253,15 +260,9 @@ fn ecrecover() {
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);*/
}
#[test]
#[should_panic]
fn from_unknown_linear() {
let _ = Builtin::from_named_linear("dw", 10, 20);
}
#[test]
fn from_named_linear() {
let b = Builtin::from_named_linear("identity", 10, 20);
let b = Builtin::from_named_linear("identity", 10, 20).unwrap();
assert_eq!((*b.cost)(0), U256::from(10));
assert_eq!((*b.cost)(1), U256::from(30));
assert_eq!((*b.cost)(32), U256::from(30));
@@ -275,14 +276,9 @@ fn from_named_linear() {
#[test]
fn from_json() {
let b = Builtin::from(ethjson::spec::Builtin {
name: "identity".to_owned(),
pricing: ethjson::spec::Pricing::Linear(ethjson::spec::Linear {
base: 10,
word: 20,
})
});
let text = r#"{"name": "identity", "pricing": {"linear": {"base": 10, "word": 20}}}"#;
let json = Json::from_str(text).unwrap();
let b = Builtin::from_json(&json).unwrap();
assert_eq!((*b.cost)(0), U256::from(10));
assert_eq!((*b.cost)(1), U256::from(30));
assert_eq!((*b.cost)(32), U256::from(30));

View File

@@ -1,72 +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::collections::{VecDeque, HashSet};
use std::hash::Hash;
const COLLECTION_QUEUE_SIZE: usize = 8;
pub struct CacheManager<T> where T: Eq + Hash {
pref_cache_size: usize,
max_cache_size: usize,
bytes_per_cache_entry: usize,
cache_usage: VecDeque<HashSet<T>>
}
impl<T> CacheManager<T> where T: Eq + Hash {
pub fn new(pref_cache_size: usize, max_cache_size: usize, bytes_per_cache_entry: usize) -> Self {
CacheManager {
pref_cache_size: pref_cache_size,
max_cache_size: max_cache_size,
bytes_per_cache_entry: bytes_per_cache_entry,
cache_usage: (0..COLLECTION_QUEUE_SIZE).into_iter().map(|_| Default::default()).collect(),
}
}
pub fn note_used(&mut self, id: T) {
if !self.cache_usage[0].contains(&id) {
if let Some(c) = self.cache_usage.iter_mut().skip(1).find(|e| e.contains(&id)) {
c.remove(&id);
}
self.cache_usage[0].insert(id);
}
}
/// Collects unused objects from cache.
/// First params is the current size of the cache.
/// Second one is an with objects to remove. It should also return new size of the cache.
pub fn collect_garbage<F>(&mut self, current_size: usize, mut notify_unused: F) where F: FnMut(HashSet<T>) -> usize {
if current_size < self.pref_cache_size {
self.rotate_cache_if_needed();
return;
}
for _ in 0..COLLECTION_QUEUE_SIZE {
let current_size = notify_unused(self.cache_usage.pop_back().unwrap());
self.cache_usage.push_front(Default::default());
if current_size < self.max_cache_size {
break;
}
}
}
fn rotate_cache_if_needed(&mut self) {
if self.cache_usage[0].len() * self.bytes_per_cache_entry > self.pref_cache_size / COLLECTION_QUEUE_SIZE {
let cache = self.cache_usage.pop_back().unwrap();
self.cache_usage.push_front(cache);
}
}
}

View File

@@ -14,29 +14,27 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use bloomchain::group as bc;
use util::HeapSizeOf;
//! Represents bloom index in cache
/// Represents `BloomGroup` position in database.
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
pub struct GroupPosition {
/// Bloom level.
/// Represents bloom index in cache
///
/// On cache level 0, every block bloom is represented by different index.
/// On higher cache levels, multiple block blooms are represented by one
/// index. Their `BloomIndex` can be created from block number and given level.
#[derive(Eq, PartialEq, Hash, Clone, Debug)]
pub struct BloomIndex {
/// Bloom level
pub level: u8,
/// Group index.
pub index: u32,
/// Filter Index
pub index: usize,
}
impl From<bc::GroupPosition> for GroupPosition {
fn from(p: bc::GroupPosition) -> Self {
GroupPosition {
level: p.level as u8,
index: p.index as u32,
impl BloomIndex {
/// Default constructor for `BloomIndex`
pub fn new(level: u8, index: usize) -> BloomIndex {
BloomIndex {
level: level,
index: index,
}
}
}
impl HeapSizeOf for GroupPosition {
fn heap_size_of_children(&self) -> usize {
0
}
}

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