Compare commits

...

109 Commits
v3.2.4 ... main

Author SHA1 Message Date
POA 6e06824c23 Bump to v3.3.3 2022-01-13 12:34:02 +03:00
Rim Rakhimov 43d6da6b52
Made nodes data concatenate as RLP sequences instead of bytes (#598)
* Made nodes data concatenate as RLP sequences instead of bytes

* Add test for getNodeData dispatch

* Update getNodeData to return data for non-aura networks
2022-01-13 12:26:33 +03:00
Rim Rakhimov 412d797a3b
Implements eip-3607 (#593)
* implements eip-3607

* Tests fixed

* Added tests for eip3607 functionality

* rast fmt
2022-01-10 18:01:46 +03:00
Rim Rakhimov 63bab44e3c
Makes eth_mining to return False if not is not allowed to seal (#581) 2021-12-10 14:25:39 +03:00
Rim Rakhimov f703d01f23
Add type field for legacy transactions in RPC calls (#580)
* Added type field for legacy transactions when returned as rpc call response

* Remove invalid test
2021-12-09 11:17:42 +03:00
POA f13fa10b8a Bump to v3.3.2, London on Sokol, effective_gas_price function enhancement 2021-12-07 14:03:48 +03:00
POA 657100cebc Bump to v3.3.1 2021-11-30 10:55:54 +03:00
POA d2d19ec8c2 Merge branch 'dev' of https://github.com/openethereum/openethereum into dev 2021-11-30 10:39:06 +03:00
POA 0f872aff78 Add a bootnode for Kovan 2021-11-30 10:38:55 +03:00
Rim Rakhimov 405738c791
Fix for modexp overflow in debug mode (#578)
* fix modexp overflow panic in debug mode

* Added one more unit test for modexp

* Remove redundant bytes from modexp unit test

Co-authored-by: POA <33550681+poa@users.noreply.github.com>
2021-11-30 10:33:40 +03:00
Rim Rakhimov 3b19a79c37
Adds eth_maxPriorityFeePerGas implementaiton (#570)
* added eth_maxPriorityFeePerGas rpc call

* cargo fmt

* moved block_base_fee implementation into the trait

* added basic test for eth_maxPriorityFeePerGas

* added test for eth_maxPriorityFeePerGas calculation

* Added support for zero-cost transactions

* Added 'eip1559_not_activated' error

* Fixes 'chain::supplier::test::return_nodes' test

* cargo fmt

* cargo fmt

* made calculation of fallback priority fee to ignore zero-cost transactions

* cargo fmt

* made use of 'saturating_sub' instead of minus
2021-11-25 10:43:00 +03:00
POA 64a1614769 Bump to v3.3.0 2021-11-17 12:05:58 +03:00
POA b981f7beef Add validateServiceTransactionsTransition spec option 2021-11-12 13:06:19 +03:00
POA caa210107e Add additional service transactions checking to block verifier 2021-11-10 16:36:17 +03:00
POA 88eb7d3257 Revert eip1559BaseFeeMinValue activation on xDai 2021-11-04 15:50:48 +03:00
POA 73895aae88 Set eip1559BaseFeeMinValue for POA Core 2021-11-02 10:29:54 +03:00
POA c5719983b2 Set eip1559BaseFeeInitialValue equal to eip1559BaseFeeMinValue for xDai 2021-11-02 09:34:53 +03:00
POA f9b2db206a Replace eip1559BaseFeeFixedValue* spec options with eip1559BaseFeeMinValue and eip1559BaseFeeMinValueTransition 2021-11-01 13:20:58 +03:00
POA 437ba9b044 Add eip1559BaseFeeFixedValue and eip1559BaseFeeFixedValueTransition spec options and bump to v3.3.0-rc.14 2021-11-01 10:53:50 +03:00
uink45 98873fc0c0
EIP-4345 enabled (#561)
* EIP-4345 enabled

Co-authored-by: varasev <33550681+varasev@users.noreply.github.com>
2021-11-01 07:14:52 +03:00
POA 415a522429 POA Core London hard fork and bump to v3.3.0-rc.13 2021-10-29 16:37:12 +03:00
POA 646f49fdd0 xDai London hard fork and bump to v3.3.0-rc.12 2021-10-22 09:44:16 +03:00
POA 25ce4b2ec8 Enable GetNodeData for AuRa chains and bump to v3.3.0-rc.11 2021-10-19 11:25:32 +03:00
POA ac30783c82 Add eip1559FeeCollector and eip1559FeeCollectorTransition spec options and bump to v3.3.0-rc.10 2021-10-14 16:14:38 +03:00
POA 5e9b4c58ae Bump to v3.3.0-rc.9 2021-10-04 10:43:30 +03:00
POA 74e709fd55 Fix MinGasPrice config option 2021-09-29 10:30:28 +03:00
POA 3413343caa Add service transactions support for EIP-1559 2021-09-29 10:30:28 +03:00
sunce86 8bb02dd479 small fixes 2021-09-29 10:30:27 +03:00
sunce86 79be8f1ab8 min_gas_price becomes min_effective_priority_fee (effective_gas_price - base_fee) 2021-09-29 10:30:27 +03:00
sunce86 a049baf6b2 added version 4 for TxPermission contract 2021-09-29 10:30:27 +03:00
sunce86 d8305c52ea Bump to v3.3.0-rc.8 2021-09-03 17:07:40 +02:00
Jochen Müller 239d790df1
Ignore GetNodeData requests (#519) 2021-09-03 16:43:33 +02:00
Jochen Müller 298a1a0ecc Bump to v3.3.0-rc.7 2021-08-23 14:03:36 +02:00
Jochen Müller 36b3f125a4
Fix wrong sync packet id (#514) 2021-08-23 13:54:25 +02:00
sunce86 5d9ff63043 Bump to v3.3.0-rc.6 2021-08-04 18:15:06 +02:00
sunce86 01996c8867 Merge branch 'dev' 2021-08-04 18:05:31 +02:00
varasev 2ae294990a
London HF on Kovan (#502)
* London HF on Kovan

Block number 26741100

* Set wasmDisableTransition for Kovan

Co-authored-by: Dusan Stanivukovic <dusan.stanivukovic@gmail.com>
2021-08-03 14:02:37 +02:00
sunce86 745c4bd00c Revert "Sunce86/eip1559 for x dai (#499)"
This reverts commit 87ae05d99e.
2021-08-03 11:49:51 +02:00
sunce86 ecae5f1c47 Revert "Sunce86/eip1559 for x dai (#499)"
This reverts commit 87ae05d99e.
2021-08-03 11:47:01 +02:00
Dusan Stanivukovic 87ae05d99e
Sunce86/eip1559 for x dai (#499)
* added version 4 for TxPermission contract
* min_gas_price becomes min_effective_priority_fee (effective_gas_price - base_fee)
2021-08-02 19:47:39 +02:00
sunce86 a92e5e761b Bump to v3.3.0-rc.4 2021-07-14 21:46:58 +02:00
Dusan Stanivukovic 87603926b5
feeHistory implementation (#484)
* feeHistory implementation

* code review fix
2021-07-14 21:21:28 +02:00
Dusan Stanivukovic eb42f0c5d9
gasPrice is required field for Transaction object (#481) 2021-07-12 15:22:27 +02:00
Dusan Stanivukovic 33908e8361
fix state test for openethereum-evm (#480)
* fix state test for openethereum-evm
2021-07-10 08:53:53 +02:00
Dusan Stanivukovic aa09846200
bump ethereum tests 9.0.3 (#478) 2021-07-09 16:47:02 +02:00
Dusan Stanivukovic 67ab600bc9
Sunce86/effective gas price not omitting (#477)
* no omit effectiveGasPrice in receipts
2021-07-09 14:56:37 +02:00
Dusan Stanivukovic 4b437428bd
define london block at 12965000 (#476)
* define london block at 12965000
2021-07-08 22:55:53 +02:00
Jochen Müller 38e40f649c
Restore GetNodeData (#469)
* Accept GetNodeData requests

* Implement blockchain client method for node data requests

* Reuse old database read methods for node data

* fmt

* Copy & paste old tests...

* ... and make them work

* fmt
2021-07-05 17:06:35 +02:00
Jochen Müller 43ee520904
Implement eth/66 (#467)
* Allow eth/66

* Add eth/66 request ids

* fmt

* Remove some leftovers

* fmt

* Change behaviour in case of missing peer info

- Assume eth/66 protocol, not earlier one
- Log just a trace, not an error
2021-07-05 15:59:22 +02:00
sunce86 fdaee51ca0 Bump to v3.3.0-rc.3 2021-06-29 22:56:40 +02:00
Dusan Stanivukovic eec38b30e3
forcing base fee to zero if gas pricing is omitted (#460)
* forcing base fee to zero if gas pricing is omitted

* force base fee to zero for estimate_gas
2021-06-29 22:17:00 +02:00
Dusan Stanivukovic 287409f9f5
gasPrice substituted with effective_gas_price (#458) 2021-06-28 19:15:37 +02:00
Dusan Stanivukovic e5ae846de4
added effectiveGasPrice to eth_getTransactionReceipt return structure (#450) 2021-06-28 19:04:52 +02:00
Dusan Stanivukovic e6f3794dd4
rust version reverted to 1.52.1 (#454) 2021-06-28 16:39:18 +02:00
sunce86 5920f232d0 Bump to v3.3.0-rc.2 2021-06-17 11:32:11 +02:00
sunce86 3bce814090 Update changelog 2021-06-17 11:31:33 +02:00
sunce86 118051696e Merge branch 'dev' 2021-06-16 21:18:02 +02:00
Dusan Stanivukovic 17057eeedc
bump ethereum tests 9.0.2, revert london mainnet block (#435)
* bump ethereum tests 9.0.2
* london mainnet block removed
2021-06-16 20:48:23 +02:00
Dusan Stanivukovic 7aa1e987de
Update CHANGELOG.md 2021-06-16 09:33:16 +02:00
Jochen Müller 193b25a22d Bump to v3.3.0-rc.1 2021-06-15 13:25:26 +02:00
Jochen Müller 99a8ddae41 Update changelog 2021-06-15 13:00:45 +02:00
Dusan Stanivukovic 93b39df02d
Eip 3554 enabled, London blocks defined (#433)
* Eip 3554 enabled
* london hard fork blocks
2021-06-15 11:18:56 +02:00
Dusan Stanivukovic 5dec58ba9f
Sunce86/fix tx pool locals for 1559 (#431)
* fixed handling of local txs after 1559 activation
2021-06-11 10:19:08 +02:00
Dusan Stanivukovic b928380b64
test update (#429)
support for 9.0.1 ethereum tests
2021-06-10 15:01:48 +02:00
Dusan Stanivukovic 5e7086d54c
Sunce86/eip 1559 (#393)
* eip1559 hard fork activation

* eip1559 hard fork activation 2

* added new transaction type for eip1559

* added base fee field to block header

* fmt fix

* added base fee calculation. added block header validation against base fee

* fmt

* temporarily added modified transaction pool

* tx pool fix of PendingIterator

* tx pool fix of UnorderedIterator

* tx pool added test for set_scoring

* transaction pool changes

* added tests for eip1559 transaction and eip1559 receipt

* added test for eip1559 transaction execution

* block gas limit / block gas target handling

* base fee verification moved out of engine

* calculate_base_fee moved to EthereumMachine

* handling of base_fee_per_gas as part of seal

* handling of base_fee_per_gas changed. Different encoding/decoding of block header

* eip1559 transaction execution - gas price handling

* eip1559 transaction execution - verification, fee burning

* effectiveGasPrice removed from the receipt payload (specs)

* added support for 1559 txs in tx pool verification

* added Aleut test network configuration

* effective_tip_scaled replaced by typed_gas_price

* eip 3198 - Basefee opcode

* rpc - updated structs Block and Header

* rpc changes for 1559

* variable renaming according to spec

* - typed_gas_price renamed to effective_gas_price
- elasticity_multiplier definition moved to update_schedule()

* calculate_base_fee simplified

* Evm environment context temporary fix for gas limit

* fmt fix

* fixed fake_sign::sign_call

* temporary fix for GASLIMIT opcode to provide gas_target actually

* gas_target removed from block header according to spec change: https://github.com/ethereum/EIPs/pull/3566

* tx pool verification fix

* env_info base fee changed to Option

* fmt fix

* pretty format

* updated ethereum tests

* cache_pending refresh on each update of score

* code review fixes

* fmt fix

* code review fix - changed handling of eip1559_base_fee_max_change_denominator

* code review fix - modification.gas_price

* Skip gas_limit_bump for Aura

* gas_limit calculation changed to target ceil

* gas_limit calculation will target ceil on 1559 activation block

* transaction verification updated according spec: https://github.com/ethereum/EIPs/pull/3594

* updated json tests

* ethereum json tests fix for base_fee
2021-06-04 12:12:24 +02:00
Jochen Müller 144b2293a2
EIP 3541 (#422)
* Add EIP-3541 transition block parameter

* Implement EIP-3541

* Add a unit test for EIP-3541

* Add error type for attempt to deploy invalid code

* fmt
2021-05-31 14:37:23 +02:00
Jochen Müller f14d3e5a5c
EIP-3529: Reduction in gas refunds (#406)
* Implement changed gas refund rules according to EIP-3529

* Add a unit test for changed gas refunds

* Add missing comment

* Add fork block to spec.hard_forks
2021-05-19 17:18:01 +02:00
Jochen Müller f9f492638c Bump to v3.2.6 2021-05-14 09:39:01 +02:00
varasev fe198ddf7d
Berlin HF on POA Core and Sokol (#398)
Co-authored-by: POA <33550681+poa@users.noreply.github.com>
2021-05-11 11:10:51 +02:00
Jochen Müller 32d8b5487a Bump to v3.2.5 2021-05-05 15:14:10 +02:00
rakita 6835ec53ad
Remove windows build artifacts (#385)
Remove windows build artifacts that were added by mistake
2021-05-05 13:33:48 +02:00
Jochen Müller 09ab40b956
Mention v3.2.2 changes in v3.2.5 changelog (#386)
Since the two hotfix releases, v3.2.3 and v3.2.4, did not include the
changes from v3.2.2-rc.1, they should be mentioned in the changelog for
v3.2.5-rc.1 again.
2021-05-05 12:19:45 +02:00
Jochen Müller 2df74c26dd Bump to v3.2.5-rc.1 2021-04-28 15:08:33 +02:00
varasev ed12fffeef
Berlin HF on xDai (#384)
* Berlin HF on xDai

* Update enodes for xDai

Co-authored-by: rakita <rakita@users.noreply.github.com>
2021-04-28 14:07:24 +02:00
Jochen Müller c03cc15468
Implement eth/65 (#352)
* EIP-2464: eth/65: transaction announcements and retrievals

* Updates to eth-65 implementatiom

- Replace deprecated syntax and method name
- Replace call to removed method
- Reimplement rlp::Encodable for SignedTransaction

* fmt

* More updates

- Replace calls to removed methods
- More dyns

* Apply requested changes

- Avoid unused variable warnings
- Avoid implementing Encodable trait for Transaction
- Update message encoding to EIP-2718 transaction format

* Update sync stats of eth-65 peers properly

* fmt & fix error propagation

* Fix: Add correct subset of transactions to stats.

* Update list of last sent transactions correctly.

Co-authored-by: Artem Vorotnikov <artem@vorotnikov.me>
Co-authored-by: Karim Agha <karim.dev@gmail.com>
Co-authored-by: rakita <rakita@users.noreply.github.com>
2021-04-27 15:33:40 +02:00
rakita 3b3ecf6676
Bump eth tests to 8.0.3 (#349) 2021-04-27 14:36:50 +02:00
rakita be9b16ab67
Bump parking_lot to 0.11.1. Revert std mutex from #277 (#350) 2021-04-27 13:12:19 +02:00
varasev 392a909cb7
Berlin HF in Kovan (#380)
* Berlin HF in Kovan

According to https://github.com/poanetwork/poa-chain-spec/pull/171

* Update nodes for Kovan
2021-04-26 10:21:01 +02:00
Jochen Müller 6f5a00a642 Merge branch 'main' into dev 2021-04-21 15:42:43 +02:00
Jochen Müller 2453f1a803 Merge branch 'release/v3.2.x' into main 2021-04-21 15:27:39 +02:00
Wei Tang 6ce6666cbb
EIP-2929: add tx sender and address into the access list (#360) 2021-04-15 17:41:33 +02:00
rakita 582bca385f Bump to v3.2.2-rc.1. Changelog 2021-03-31 15:07:27 +02:00
rakita 9037ad0ea7 Bump eth/tests to v8.0.2 2021-03-31 13:44:14 +02:00
rakita c9190a39ed
Executable queue for ancient blocks inclusion (#208)
* Executable queue for ancient blocks inclusion
* Add drop trait for client
* Added shutdown to tests
* Remove doubled call
* Use reth-util from reth repo
2021-03-25 16:04:32 +01:00
rakita 85391f99ac
Backport AuRa commits for xdai (#330)
* Add SealingState; don't prepare block when not ready. (#10529)
* Fix a few typos and unused warnings. #10803
* Configuration map of block reward contract addresses (#10875)
* Step duration map configuration parameter ported from the POA Network fork (#10902)
* Add a 2/3 quorum option to Authority Round. (#10909)
* Additional arithmetic EVM opcode benchmarks (#10916)
* RPC method for clearing the engine signer (#10920)
* authority_round: Fix next_step_time_duration. (#11379)
* Aura: Report malice on sibling blocks from the same validator (#11160)
* TxPermissions ver 3: gas price & data (#11170)
* Add randomness contract support to AuthorityRound. (#10946)
* Set the block gas limit to the value returned by a contract call (#10928)
* AuthorityEngine: Minor cleanups. (#11408)
* Add POSDAO transition and malice report queue. (#11245)
* PoA call validators on_close_block
* Actualize spec files for POA Networks
* Some fixes after merge
* Crypto error desc
* AuRa on_close_block Error::Old fix

Co-authored-by: POA <33550681+poa@users.noreply.github.com>
2021-03-25 14:37:01 +01:00
rakita 561ed8df3c fix miner_author by adding dummy msg 2021-03-24 17:50:36 +01:00
rakita 5eacff59e8 Revert "Remove eth/63 protocol version (#252)"
This reverts commit bbecb0415e.
2021-03-23 11:59:33 +01:00
rakita d030870220 Merge remote-tracking branch 'origin/main' into dev 2021-03-21 21:58:13 +01:00
Karim Agha ee88247e71 Fixing outdated readme links (#322) 2021-03-21 21:58:02 +01:00
Jochen Müller 37f5291538
Add Nethermind to clients that accept service transactions (#324)
* Add Nethermind to clients that accept service transactions

* fmt
2021-03-18 14:00:05 +01:00
Jochen Müller 504777e879
Implement the filter argument in parity_pendingTransactions (#295)
* Add filters for pending transactions to RPC API

Allow filtering results in the parity_pendingTransaction endpoint as described in the API docs.

* Make arguments in parity_pendingTransactions work together

filter and limit

* fmt

* Requested changes

- filter in ethcore to avoid unneccessary copying
- rename gas_price to gasPrice
- implement requesting contract creation txs with "action"

* Some beautifying

Remove missing import and unneccessary dependency entry, add a comment
and set right lint level on new module

* fixed broken build after merge

* fmt

* fixing CI errors: type conversion

Co-authored-by: Karim Agha <karim.dev@gmail.com>
2021-03-16 13:39:42 +01:00
rakita 33a3a9deec
Initial sync block stuck. Block import logs (#318)
Co-authored-by: Karim Agha <karim.dev@gmail.com>
2021-03-14 11:18:38 +01:00
Karim Agha b6b5129058
Following up on PR #316, removing unused conversions that are now deadcode (#321) 2021-03-14 10:25:14 +01:00
Karim Agha 29dc10c446
Updating ethcore and ethjson crates to Rust Edition 2018 (#316)
* Migrating use crate::Type imports to Rust 2018 edition

* import name fixes

* fmt

* removing diff leftover

* catching up with latest developments on dev

* fmt

* removing another diff leftover
2021-03-12 14:55:49 +01:00
Simon KP 48e7d6cee4
Send SIGTERM instead of SIGHUP to OE daemon (#317)
* Send SIGTERM instead of SIGHUP to OE daemon

* Address comments
2021-03-12 13:00:09 +01:00
rakita a0f406e26b
Ethereum-types and various libs upgrade (#315)
* Upgrade Eth types

ethereum-types -> 0.9.2
rlp -> 0.4.6
keccak-hash -> 0.5.0
parity-crypto -> 0.6.2
ethabi -> 0.12.0
ethabi-derive -> 0.12.0
ethabi-contract -> 0.11.0
ethbloom -> 0.9.1
rand -> 0.7.3
trie-standardmap -> 0.15.2
triehash -> 0.5.0

* backport #10714. Small changes, merge fixes

Co-authored-by: mdben1247 <mdben1247@users.noreply.github.com>
2021-03-12 10:12:42 +01:00
rakita 3f8e0cfec4 Merge remote-tracking branch 'origin/main' into dev 2021-03-11 16:30:47 +01:00
rakita 32fd2b484c Merge remote-tracking branch 'origin/main' into dev 2021-03-10 17:23:00 +01:00
rakita d7a958129f
[evmbin] Omit storage output, now for std-json (#311)
* [evmbin] Omit storage output, now for std-json
* fix tests
2021-03-10 16:39:32 +01:00
rakita eca8fb74ae
Strict memory order (#306)
* Make MemoryOrdering more strict

* fmt

* Strict mem order for priority_tasks_gate
2021-03-10 12:36:23 +01:00
Karim Agha e2024c4b81
Fixing a compilation warning (#308)
* Fixing a compilation warning
2021-03-10 09:46:34 +01:00
rakita 5b904476cd
Backport: Block sync stopped without any errors. #277 (#286)
* Backport: Block sync stopped without any errors. #277
* fmt
2021-03-09 11:20:32 +01:00
rakita 7ea5707904
Freeze pruning while creating snapshot (#205)
* Freeze pruning while creating snapshot
* Use scopeguard for snapshot generation
* Snapshot 1k blocks
* Snapshot number correction
2021-03-09 09:47:49 +01:00
rakita 6f50061f0c
AuRa multi block reward (#290)
* Multi block reward for AuRa
* Added test
* Better error on wrong config
2021-03-08 11:59:04 +01:00
gakada dbc5f94241
Migrate compare_and_swap to compare_exchange (#291) 2021-03-06 11:30:52 +01:00
adria0.eth 0fcb102f03
Improved metrics (#240)
Added db metrics (kvdb_bytes_read, kvdb_bytes_written, kvdb_reads, kvdb_writes)
Added --metrics-prefix=[prefix]
2021-03-03 22:44:35 +01:00
rakita ba011eba15
Send RLPx auth in EIP-8 format (#287) 2021-03-03 12:58:10 +01:00
Anonymous 7c9eed8d65 ethcore/snapshot: fix double-lock in Service::feed_chunk (#289) 2021-03-02 14:44:58 +01:00
Dusan Stanivukovic 0947261cf2
Sunce86/rpc module reverted for RPC JSON api (#284)
* rpc module reverted for RPC JSON api

Co-authored-by: Dusan Stanivukovic <dusan.stanivukovic@gnosis.pm>
2021-02-26 15:23:29 +01:00
461 changed files with 19287 additions and 7001 deletions

View File

@ -13,7 +13,7 @@ jobs:
platform: platform:
- windows2019 # custom runner - windows2019 # custom runner
toolchain: toolchain:
- stable - 1.52.1
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
steps: steps:
- name: Checkout sources - name: Checkout sources

View File

@ -15,7 +15,7 @@ jobs:
- ubuntu-16.04 - ubuntu-16.04
- macos-latest - macos-latest
toolchain: toolchain:
- stable - 1.52.1
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
steps: steps:
- name: Checkout sources - name: Checkout sources

View File

@ -20,7 +20,7 @@ jobs:
- ubuntu-16.04 - ubuntu-16.04
- macos-latest - macos-latest
toolchain: toolchain:
- stable - 1.52.1
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
steps: steps:
- name: Checkout sources - name: Checkout sources

View File

@ -15,10 +15,10 @@ jobs:
uses: actions/checkout@main uses: actions/checkout@main
with: with:
submodules: true submodules: true
- name: Install stable toolchain - name: Install 1.52.1 toolchain
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: 1.52.1
profile: minimal profile: minimal
override: true override: true
- name: Run cargo check 1/3 - name: Run cargo check 1/3

View File

@ -16,7 +16,7 @@ jobs:
- name: Install toolchain - name: Install toolchain
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: 1.52.1
profile: minimal profile: minimal
override: true override: true
- name: Deploy to docker hub - name: Deploy to docker hub

View File

@ -17,7 +17,7 @@ jobs:
- name: Install toolchain - name: Install toolchain
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: 1.52.1
profile: minimal profile: minimal
override: true override: true
- name: Deploy to docker hub - name: Deploy to docker hub

View File

@ -17,7 +17,7 @@ jobs:
- name: Install toolchain - name: Install toolchain
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: 1.52.1
profile: minimal profile: minimal
override: true override: true
- name: Deploy to docker hub - name: Deploy to docker hub

View File

@ -11,7 +11,7 @@ jobs:
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
profile: minimal profile: minimal
toolchain: stable toolchain: 1.52.1
override: true override: true
- run: rustup component add rustfmt - run: rustup component add rustfmt
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1

View File

@ -1,3 +1,157 @@
## OpenEthereum v3.3.3
Enhancements:
* Implement eip-3607 (#593)
Bug fixes:
* Add type field for legacy transactions in RPC calls (#580)
* Makes eth_mining to return False if not is not allowed to seal (#581)
* Made nodes data concatenate as RLP sequences instead of bytes (#598)
## OpenEthereum v3.3.2
Enhancements:
* London hardfork block: Sokol (24114400)
Bug fixes:
* Fix for maxPriorityFeePerGas overflow
## OpenEthereum v3.3.1
Enhancements:
* Add eth_maxPriorityFeePerGas implementation (#570)
* Add a bootnode for Kovan
Bug fixes:
* Fix for modexp overflow in debug mode (#578)
## OpenEthereum v3.3.0
Enhancements:
* Add `validateServiceTransactionsTransition` spec option to be able to enable additional checking of zero gas price transactions by block verifier
## OpenEthereum v3.3.0-rc.15
* Revert eip1559BaseFeeMinValue activation on xDai at London hardfork block
## OpenEthereum v3.3.0-rc.14
Enhancements:
* Add eip1559BaseFeeMinValue and eip1559BaseFeeMinValueTransition spec options
* Activate eip1559BaseFeeMinValue on xDai at London hardfork block (19040000), set it to 20 GWei
* Activate eip1559BaseFeeMinValue on POA Core at block 24199500 (November 8, 2021), set it to 10 GWei
* Delay difficulty bomb to June 2022 for Ethereum Mainnet (EIP-4345)
## OpenEthereum v3.3.0-rc.13
Enhancements:
* London hardfork block: POA Core (24090200)
## OpenEthereum v3.3.0-rc.12
Enhancements:
* London hardfork block: xDai (19040000)
## OpenEthereum v3.3.0-rc.11
Bug fixes:
* Ignore GetNodeData requests only for non-AuRa chains
## OpenEthereum v3.3.0-rc.10
Enhancements:
* Add eip1559FeeCollector and eip1559FeeCollectorTransition spec options
## OpenEthereum v3.3.0-rc.9
Bug fixes:
* Add service transactions support for EIP-1559
* Fix MinGasPrice config option for POSDAO and EIP-1559
Enhancements:
* min_gas_price becomes min_effective_priority_fee
* added version 4 for TxPermission contract
## OpenEthereum v3.3.0-rc.8
Bug fixes:
* Ignore GetNodeData requests (#519)
## OpenEthereum v3.3.0-rc.7
Bug fixes:
* GetPooledTransactions is sent in invalid form (wrong packet id)
## OpenEthereum v3.3.0-rc.6
Enhancements:
* London hardfork block: kovan (26741100) (#502)
## OpenEthereum v3.3.0-rc.4
Enhancements:
* London hardfork block: mainnet (12,965,000) (#475)
* Support for eth/66 protocol version (#465)
* Bump ethereum/tests to v9.0.3
* Add eth_feeHistory
Bug fixes:
* GetNodeData from eth63 is missing (#466)
* Effective gas price not omitting (#477)
* London support in openethereum-evm (#479)
* gasPrice is required field for Transaction object (#481)
## OpenEthereum v3.3.0-rc.3
Bug fixes:
* Add effective_gas_price to eth_getTransactionReceipt #445 (#450)
* Update eth_gasPrice to support EIP-1559 #449 (#458)
* eth_estimateGas returns "Requires higher than upper limit of X" after London Ropsten Hard Fork #459 (#460)
## OpenEthereum v3.3.0-rc.2
Enhancements:
* EIP-1559: Fee market change for ETH 1.0 chain
* EIP-3198: BASEFEE opcode
* EIP-3529: Reduction in gas refunds
* EIP-3541: Reject new contracts starting with the 0xEF byte
* Delay difficulty bomb to December 2021 (EIP-3554)
* London hardfork blocks: goerli (5,062,605), rinkeby (8,897,988), ropsten (10,499,401)
* Add chainspecs for aleut and baikal
* Bump ethereum/tests to v9.0.2
## OpenEthereum v3.2.6
Enhancement:
* Berlin hardfork blocks: poacore (21,364,900), poasokol (21,050,600)
## OpenEthereum v3.2.5
Bug fixes:
* Backport: Block sync stopped without any errors. #277 (#286)
* Strict memory order (#306)
Enhancements:
* Executable queue for ancient blocks inclusion (#208)
* Backport AuRa commits for xdai (#330)
* Add Nethermind to clients that accept service transactions (#324)
* Implement the filter argument in parity_pendingTransactions (#295)
* Ethereum-types and various libs upgraded (#315)
* [evmbin] Omit storage output, now for std-json (#311)
* Freeze pruning while creating snapshot (#205)
* AuRa multi block reward (#290)
* Improved metrics. DB read/write. prometheus prefix config (#240)
* Send RLPx auth in EIP-8 format (#287)
* rpc module reverted for RPC JSON api (#284)
* Revert "Remove eth/63 protocol version (#252)"
* Support for eth/65 protocol version (#366)
* Berlin hardfork blocks: kovan (24,770,900), xdai (16,101,500)
* Bump ethereum/tests to v8.0.3
devops:
* Upgrade docker alpine to `v1.13.2`. for rust `v1.47`.
* Send SIGTERM instead of SIGHUP to OE daemon (#317)
## OpenEthereum v3.2.4 ## OpenEthereum v3.2.4
* Fix for Typed transaction broadcast. * Fix for Typed transaction broadcast.
@ -6,10 +160,36 @@
* Hotfix for berlin consensus error. * Hotfix for berlin consensus error.
## OpenEthereum v3.2.2-rc.1
Bug fixes:
* Backport: Block sync stopped without any errors. #277 (#286)
* Strict memory order (#306)
Enhancements:
* Executable queue for ancient blocks inclusion (#208)
* Backport AuRa commits for xdai (#330)
* Add Nethermind to clients that accept service transactions (#324)
* Implement the filter argument in parity_pendingTransactions (#295)
* Ethereum-types and various libs upgraded (#315)
* Bump ethereum/tests to v8.0.2
* [evmbin] Omit storage output, now for std-json (#311)
* Freeze pruning while creating snapshot (#205)
* AuRa multi block reward (#290)
* Improved metrics. DB read/write. prometheus prefix config (#240)
* Send RLPx auth in EIP-8 format (#287)
* rpc module reverted for RPC JSON api (#284)
* Revert "Remove eth/63 protocol version (#252)"
devops:
* Upgrade docker alpine to `v1.13.2`. for rust `v1.47`.
* Send SIGTERM instead of SIGHUP to OE daemon (#317)
## OpenEthereum v3.2.1 ## OpenEthereum v3.2.1
Hot fix issue, related to initial sync: Hot fix issue, related to initial sync:
* Initial sync gets stuck. (#318) * Initial sync gets stuck. (#318)
## OpenEthereum v3.2.0 ## OpenEthereum v3.2.0
Bug fixes: Bug fixes:
@ -25,4 +205,4 @@ Enhancements:
* Snapshot manifest block added to prometheus (#232) * Snapshot manifest block added to prometheus (#232)
* EIP-1898: Allow default block parameter to be blockHash * EIP-1898: Allow default block parameter to be blockHash
* Change ProtocolId to U64 * Change ProtocolId to U64
* Update ethereum/tests * Update ethereum/tests

1161
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
description = "OpenEthereum" description = "OpenEthereum"
name = "openethereum" name = "openethereum"
# NOTE Make sure to update util/version/Cargo.toml as well # NOTE Make sure to update util/version/Cargo.toml as well
version = "3.2.4" version = "3.3.3"
license = "GPL-3.0" license = "GPL-3.0"
authors = [ authors = [
"OpenEthereum developers", "OpenEthereum developers",
@ -22,7 +22,7 @@ number_prefix = "0.2"
rpassword = "1.0" rpassword = "1.0"
semver = "0.9" semver = "0.9"
ansi_term = "0.10" ansi_term = "0.10"
parking_lot = "0.7" parking_lot = "0.11.1"
regex = "1.0" regex = "1.0"
atty = "0.2.8" atty = "0.2.8"
toml = "0.4" toml = "0.4"
@ -47,12 +47,13 @@ ethcore-miner = { path = "crates/concensus/miner" }
ethcore-network = { path = "crates/net/network" } ethcore-network = { path = "crates/net/network" }
ethcore-service = { path = "crates/ethcore/service" } ethcore-service = { path = "crates/ethcore/service" }
ethcore-sync = { path = "crates/ethcore/sync" } ethcore-sync = { path = "crates/ethcore/sync" }
ethereum-types = "0.4" ethereum-types = "0.9.2"
ethkey = { path = "crates/accounts/ethkey" } ethkey = { path = "crates/accounts/ethkey" }
ethstore = { path = "crates/accounts/ethstore" } ethstore = { path = "crates/accounts/ethstore" }
fetch = { path = "crates/net/fetch" } fetch = { path = "crates/net/fetch" }
node-filter = { path = "crates/net/node-filter" } node-filter = { path = "crates/net/node-filter" }
rlp = { version = "0.3.0", features = ["ethereum"] } parity-crypto = { version = "0.6.2", features = [ "publickey" ] }
rlp = { version = "0.4.6" }
cli-signer= { path = "crates/util/cli-signer" } cli-signer= { path = "crates/util/cli-signer" }
parity-daemonize = "0.3" parity-daemonize = "0.3"
parity-local-store = { path = "crates/concensus/miner/local-store" } parity-local-store = { path = "crates/concensus/miner/local-store" }
@ -62,7 +63,7 @@ parity-version = { path = "crates/util/version" }
parity-path = "0.1" parity-path = "0.1"
dir = { path = "crates/util/dir" } dir = { path = "crates/util/dir" }
panic_hook = { path = "crates/util/panic-hook" } panic_hook = { path = "crates/util/panic-hook" }
keccak-hash = "0.1" keccak-hash = "0.5.0"
migration-rocksdb = { path = "crates/db/migration-rocksdb" } migration-rocksdb = { path = "crates/db/migration-rocksdb" }
kvdb = "0.1" kvdb = "0.1"
kvdb-rocksdb = "0.1.3" kvdb-rocksdb = "0.1.3"
@ -130,6 +131,3 @@ members = [
"bin/evmbin", "bin/evmbin",
"bin/chainspec" "bin/chainspec"
] ]
[patch.crates-io]
heapsize = { git = "https://github.com/cheme/heapsize.git", branch = "ec-macfix" }

View File

@ -9,6 +9,7 @@ docopt = "1.0"
env_logger = "0.5" env_logger = "0.5"
ethkey = { path = "../../crates/accounts/ethkey" } ethkey = { path = "../../crates/accounts/ethkey" }
panic_hook = { path = "../../crates/util/panic-hook" } panic_hook = { path = "../../crates/util/panic-hook" }
parity-crypto = { version = "0.6.2", features = [ "publickey" ] }
parity-wordlist="1.3" parity-wordlist="1.3"
rustc-hex = "1.0" rustc-hex = "1.0"
serde = "1.0" serde = "1.0"

View File

@ -18,6 +18,7 @@ extern crate docopt;
extern crate env_logger; extern crate env_logger;
extern crate ethkey; extern crate ethkey;
extern crate panic_hook; extern crate panic_hook;
extern crate parity_crypto as crypto;
extern crate parity_wordlist; extern crate parity_wordlist;
extern crate rustc_hex; extern crate rustc_hex;
extern crate serde; extern crate serde;
@ -28,11 +29,11 @@ extern crate serde_derive;
use std::{env, fmt, io, num::ParseIntError, process, sync}; use std::{env, fmt, io, num::ParseIntError, process, sync};
use docopt::Docopt; use crypto::publickey::{
use ethkey::{ sign, verify_address, verify_public, Error as EthkeyError, Generator, KeyPair, Random,
brain_recover, sign, verify_address, verify_public, Brain, BrainPrefix, Error as EthkeyError,
Generator, KeyPair, Prefix, Random,
}; };
use docopt::Docopt;
use ethkey::{brain_recover, Brain, BrainPrefix, Prefix};
use rustc_hex::{FromHex, FromHexError}; use rustc_hex::{FromHex, FromHexError};
const USAGE: &'static str = r#" const USAGE: &'static str = r#"
@ -202,15 +203,13 @@ where
let result = if args.flag_brain { let result = if args.flag_brain {
let phrase = args.arg_secret_or_phrase; let phrase = args.arg_secret_or_phrase;
let phrase_info = validate_phrase(&phrase); let phrase_info = validate_phrase(&phrase);
let keypair = Brain::new(phrase) let keypair = Brain::new(phrase).generate();
.generate()
.expect("Brain wallet generator is infallible; qed");
(keypair, Some(phrase_info)) (keypair, Some(phrase_info))
} else { } else {
let secret = args let secret = args
.arg_secret_or_phrase .arg_secret_or_phrase
.parse() .parse()
.map_err(|_| EthkeyError::InvalidSecret)?; .map_err(|_| EthkeyError::InvalidSecretKey)?;
(KeyPair::from_secret(secret)?, None) (KeyPair::from_secret(secret)?, None)
}; };
Ok(display(result, display_mode)) Ok(display(result, display_mode))
@ -223,7 +222,7 @@ where
let phrase = format!("recovery phrase: {}", brain.phrase()); let phrase = format!("recovery phrase: {}", brain.phrase());
(keypair, Some(phrase)) (keypair, Some(phrase))
} else { } else {
(Random.generate()?, None) (Random.generate(), None)
} }
} else if args.cmd_prefix { } else if args.cmd_prefix {
let prefix = args.arg_prefix.from_hex()?; let prefix = args.arg_prefix.from_hex()?;
@ -254,7 +253,7 @@ where
let secret = args let secret = args
.arg_secret .arg_secret
.parse() .parse()
.map_err(|_| EthkeyError::InvalidSecret)?; .map_err(|_| EthkeyError::InvalidSecretKey)?;
let message = args let message = args
.arg_message .arg_message
.parse() .parse()
@ -274,7 +273,7 @@ where
let public = args let public = args
.arg_public .arg_public
.parse() .parse()
.map_err(|_| EthkeyError::InvalidPublic)?; .map_err(|_| EthkeyError::InvalidPublicKey)?;
verify_public(&public, &signature, &message)? verify_public(&public, &signature, &message)?
} else if args.cmd_address { } else if args.cmd_address {
let address = args let address = args
@ -301,7 +300,7 @@ where
while let Some(phrase) = it.next() { while let Some(phrase) = it.next() {
i += 1; i += 1;
let keypair = Brain::new(phrase.clone()).generate().unwrap(); let keypair = Brain::new(phrase.clone()).generate();
if keypair.address() == address { if keypair.address() == address {
return Ok(Some((phrase, keypair))); return Ok(Some((phrase, keypair)));
} }

View File

@ -11,7 +11,7 @@ num_cpus = "1.6"
rustc-hex = "1.0" rustc-hex = "1.0"
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
parking_lot = "0.7" parking_lot = "0.11.1"
ethstore = { path = "../../crates/accounts/ethstore" } ethstore = { path = "../../crates/accounts/ethstore" }
dir = { path = '../../crates/util/dir' } dir = { path = '../../crates/util/dir' }
panic_hook = { path = "../../crates/util/panic-hook" } panic_hook = { path = "../../crates/util/panic-hook" }

View File

@ -13,7 +13,7 @@ common-types = { path = "../../crates/ethcore/types", features = ["test-helpers"
docopt = "1.0" docopt = "1.0"
env_logger = "0.5" env_logger = "0.5"
ethcore = { path = "../../crates/ethcore", features = ["test-helpers", "json-tests", "to-pod-full"] } ethcore = { path = "../../crates/ethcore", features = ["test-helpers", "json-tests", "to-pod-full"] }
ethereum-types = "0.4" ethereum-types = "0.9.2"
ethjson = { path = "../../crates/ethjson" } ethjson = { path = "../../crates/ethjson" }
evm = { path = "../../crates/vm/evm" } evm = { path = "../../crates/vm/evm" }
panic_hook = { path = "../../crates/util/panic-hook" } panic_hook = { path = "../../crates/util/panic-hook" }

View File

@ -16,7 +16,7 @@
//! Config used by display informants //! Config used by display informants
#[derive(Default, Copy, Clone)] #[derive(Default, Copy, Clone, Debug)]
pub struct Config { pub struct Config {
omit_storage_output: bool, omit_storage_output: bool,
omit_memory_output: bool, omit_memory_output: bool,

View File

@ -22,7 +22,7 @@ use super::config::Config;
use bytes::ToPretty; use bytes::ToPretty;
use display; use display;
use ethcore::trace; use ethcore::trace;
use ethereum_types::{H256, U256}; use ethereum_types::{BigEndianHash, H256, U256};
use info as vm; use info as vm;
/// JSON formatting informant. /// JSON formatting informant.
@ -208,7 +208,10 @@ impl trace::VMTracer for Informant {
} }
if let Some((pos, val)) = store_diff { if let Some((pos, val)) = store_diff {
informant.storage.insert(pos.into(), val.into()); informant.storage.insert(
BigEndianHash::from_uint(&pos),
BigEndianHash::from_uint(&val),
);
} }
if !informant.subtraces.is_empty() { if !informant.subtraces.is_empty() {
@ -284,7 +287,7 @@ mod tests {
gas_cost: U256, gas_cost: U256,
memory: String, memory: String,
stack: Vec<U256>, stack: Vec<U256>,
storage: HashMap<H256, H256>, storage: Option<HashMap<H256, H256>>,
depth: usize, depth: usize,
} }
@ -399,6 +402,23 @@ mod tests {
{"pc":1,"op":96,"opName":"PUSH1","gas":"0xfffd","gasCost":"0x3","memory":"0x","stack":["0x0"],"storage":{},"depth":1} {"pc":1,"op":96,"opName":"PUSH1","gas":"0xfffd","gasCost":"0x3","memory":"0x","stack":["0x0"],"storage":{},"depth":1}
{"pc":3,"op":85,"opName":"SSTORE","gas":"0xfffa","gasCost":"0x1388","memory":"0x","stack":["0x0","0xd8"],"storage":{},"depth":1} {"pc":3,"op":85,"opName":"SSTORE","gas":"0xfffa","gasCost":"0x1388","memory":"0x","stack":["0x0","0xd8"],"storage":{},"depth":1}
{"pc":4,"op":84,"opName":"SLOAD","gas":"0xec72","gasCost":"0x0","memory":"0x","stack":[],"storage":{"0x00000000000000000000000000000000000000000000000000000000000000d8":"0x0000000000000000000000000000000000000000000000000000000000000000"},"depth":1} {"pc":4,"op":84,"opName":"SLOAD","gas":"0xec72","gasCost":"0x0","memory":"0x","stack":[],"storage":{"0x00000000000000000000000000000000000000000000000000000000000000d8":"0x0000000000000000000000000000000000000000000000000000000000000000"},"depth":1}
"#,
);
}
#[test]
fn should_omit_storage_and_memory_flag() {
// should omit storage
run_test(
Informant::new(Config::new(true, true)),
&compare_json,
"3260D85554",
0xffff,
r#"
{"pc":0,"op":50,"opName":"ORIGIN","gas":"0xffff","gasCost":"0x2","memory":"","stack":[],"storage":null,"depth":1}
{"pc":1,"op":96,"opName":"PUSH1","gas":"0xfffd","gasCost":"0x3","memory":"","stack":["0x0"],"storage":null,"depth":1}
{"pc":3,"op":85,"opName":"SSTORE","gas":"0xfffa","gasCost":"0x1388","memory":"","stack":["0x0","0xd8"],"storage":null,"depth":1}
{"pc":4,"op":84,"opName":"SLOAD","gas":"0xec72","gasCost":"0x0","memory":"","stack":[],"storage":null,"depth":1}
"#, "#,
) )
} }

View File

@ -22,7 +22,7 @@ use super::config::Config;
use bytes::ToPretty; use bytes::ToPretty;
use display; use display;
use ethcore::{pod_state, trace}; use ethcore::{pod_state, trace};
use ethereum_types::{H256, U256}; use ethereum_types::{BigEndianHash, H256, U256};
use info as vm; use info as vm;
pub trait Writer: io::Write + Send + Sized { pub trait Writer: io::Write + Send + Sized {
@ -203,6 +203,11 @@ impl<Trace: Writer, Out: Writer> trace::VMTracer for Informant<Trace, Out> {
fn trace_next_instruction(&mut self, pc: usize, instruction: u8, current_gas: U256) -> bool { fn trace_next_instruction(&mut self, pc: usize, instruction: u8, current_gas: U256) -> bool {
let subdepth = self.subdepth; let subdepth = self.subdepth;
Self::with_informant_in_depth(self, subdepth, |informant: &mut Informant<Trace, Out>| { Self::with_informant_in_depth(self, subdepth, |informant: &mut Informant<Trace, Out>| {
let storage = if informant.config.omit_storage_output() {
None
} else {
Some(&informant.storage)
};
let info = ::evm::Instruction::from_u8(instruction).map(|i| i.info()); let info = ::evm::Instruction::from_u8(instruction).map(|i| i.info());
informant.instruction = instruction; informant.instruction = instruction;
let trace_data = json!({ let trace_data = json!({
@ -211,7 +216,7 @@ impl<Trace: Writer, Out: Writer> trace::VMTracer for Informant<Trace, Out> {
"opName": info.map(|i| i.name).unwrap_or(""), "opName": info.map(|i| i.name).unwrap_or(""),
"gas": format!("{:#x}", current_gas), "gas": format!("{:#x}", current_gas),
"stack": informant.stack, "stack": informant.stack,
"storage": informant.storage, "storage": storage,
"depth": informant.depth, "depth": informant.depth,
}); });
@ -232,7 +237,10 @@ impl<Trace: Writer, Out: Writer> trace::VMTracer for Informant<Trace, Out> {
let subdepth = self.subdepth; let subdepth = self.subdepth;
Self::with_informant_in_depth(self, subdepth, |informant: &mut Informant<Trace, Out>| { Self::with_informant_in_depth(self, subdepth, |informant: &mut Informant<Trace, Out>| {
if let Some((pos, val)) = store_written { if let Some((pos, val)) = store_written {
informant.storage.insert(pos.into(), val.into()); informant.storage.insert(
BigEndianHash::from_uint(&pos),
BigEndianHash::from_uint(&val),
);
} }
}); });
} }
@ -307,19 +315,16 @@ pub mod tests {
} }
} }
pub fn informant() -> (Informant<TestWriter, TestWriter>, Arc<Mutex<Vec<u8>>>) { pub fn informant(config: Config) -> (Informant<TestWriter, TestWriter>, Arc<Mutex<Vec<u8>>>) {
let trace_writer: TestWriter = Default::default(); let trace_writer: TestWriter = Default::default();
let out_writer: TestWriter = Default::default(); let out_writer: TestWriter = Default::default();
let res = trace_writer.0.clone(); let res = trace_writer.0.clone();
( (Informant::new(trace_writer, out_writer, config), res)
Informant::new(trace_writer, out_writer, Config::default()),
res,
)
} }
#[test] #[test]
fn should_trace_failure() { fn should_trace_failure() {
let (inf, res) = informant(); let (inf, res) = informant(Config::default());
run_test( run_test(
inf, inf,
move |_, expected| { move |_, expected| {
@ -333,7 +338,7 @@ pub mod tests {
"#, "#,
); );
let (inf, res) = informant(); let (inf, res) = informant(Config::default());
run_test( run_test(
inf, inf,
move |_, expected| { move |_, expected| {
@ -349,7 +354,7 @@ pub mod tests {
#[test] #[test]
fn should_trace_create_correctly() { fn should_trace_create_correctly() {
let (informant, res) = informant(); let (informant, res) = informant(Config::default());
run_test( run_test(
informant, informant,
move |_, expected| { move |_, expected| {
@ -382,6 +387,26 @@ pub mod tests {
{"depth":2,"gas":"0x2102","op":88,"opName":"PC","pc":5,"stack":["0x0","0x0","0x0","0x0","0x0"],"storage":{}} {"depth":2,"gas":"0x2102","op":88,"opName":"PC","pc":5,"stack":["0x0","0x0","0x0","0x0","0x0"],"storage":{}}
{"depth":2,"gas":"0x2100","op":48,"opName":"ADDRESS","pc":6,"stack":["0x0","0x0","0x0","0x0","0x0","0x5"],"storage":{}} {"depth":2,"gas":"0x2100","op":48,"opName":"ADDRESS","pc":6,"stack":["0x0","0x0","0x0","0x0","0x0","0x5"],"storage":{}}
{"depth":2,"gas":"0x20fe","op":241,"opName":"CALL","pc":7,"stack":["0x0","0x0","0x0","0x0","0x0","0x5","0xbd770416a3345f91e4b34576cb804a576fa48eb1"],"storage":{}} {"depth":2,"gas":"0x20fe","op":241,"opName":"CALL","pc":7,"stack":["0x0","0x0","0x0","0x0","0x0","0x5","0xbd770416a3345f91e4b34576cb804a576fa48eb1"],"storage":{}}
"#,
)
}
#[test]
fn should_omit_storage_and_memory_flag() {
// should omit storage
let (informant, res) = informant(Config::new(true, true));
run_test(
informant,
move |_, expected| {
let bytes = res.lock().unwrap();
assert_eq!(expected, &String::from_utf8_lossy(&**bytes))
},
"3260D85554",
0xffff,
r#"{"depth":1,"gas":"0xffff","op":50,"opName":"ORIGIN","pc":0,"stack":[],"storage":null}
{"depth":1,"gas":"0xfffd","op":96,"opName":"PUSH1","pc":1,"stack":["0x0"],"storage":null}
{"depth":1,"gas":"0xfffa","op":85,"opName":"SSTORE","pc":3,"stack":["0x0","0xd8"],"storage":null}
{"depth":1,"gas":"0xec72","op":84,"opName":"SLOAD","pc":4,"stack":[],"storage":null}
"#, "#,
) )
} }

View File

@ -103,7 +103,7 @@ pub fn run_action<T: Informant>(
Ok(r) => (Ok(r.return_data.to_vec()), Some(r.gas_left)), Ok(r) => (Ok(r.return_data.to_vec()), Some(r.gas_left)),
Err(err) => (Err(err), None), Err(err) => (Err(err), None),
}; };
(result.0, 0.into(), None, result.1, informant.drain()) (result.0, H256::zero(), None, result.1, informant.drain())
}, },
) )
} }
@ -262,6 +262,7 @@ where
#[cfg(test)] #[cfg(test)]
pub mod tests { pub mod tests {
use super::*; use super::*;
use ethereum_types::Address;
use rustc_hex::FromHex; use rustc_hex::FromHex;
use std::sync::Arc; use std::sync::Arc;
use tempdir::TempDir; use tempdir::TempDir;
@ -287,11 +288,11 @@ pub mod tests {
#[test] #[test]
fn should_call_account_from_spec() { fn should_call_account_from_spec() {
use display::std_json::tests::informant; use display::{config::Config, std_json::tests::informant};
let (inf, res) = informant(); let (inf, res) = informant(Config::default());
let mut params = ActionParams::default(); let mut params = ActionParams::default();
params.code_address = 0x20.into(); params.code_address = Address::from_low_u64_be(0x20);
params.gas = 0xffff.into(); params.gas = 0xffff.into();
let spec = ::ethcore::ethereum::load(None, include_bytes!("../res/testchain.json")); let spec = ::ethcore::ethereum::load(None, include_bytes!("../res/testchain.json"));

View File

@ -46,6 +46,8 @@ use bytes::Bytes;
use docopt::Docopt; use docopt::Docopt;
use ethcore::{json_tests, spec, TrieSpec}; use ethcore::{json_tests, spec, TrieSpec};
use ethereum_types::{Address, U256}; use ethereum_types::{Address, U256};
use ethjson::spec::ForkSpec;
use evm::EnvInfo;
use rustc_hex::FromHex; use rustc_hex::FromHex;
use std::{fmt, fs, path::PathBuf, sync::Arc}; use std::{fmt, fs, path::PathBuf, sync::Arc};
use vm::{ActionParams, CallType}; use vm::{ActionParams, CallType};
@ -192,10 +194,18 @@ fn run_state_test(args: Args) {
} }
let multitransaction = test.transaction; let multitransaction = test.transaction;
let env_info = test.env.into(); let env_info: EnvInfo = test.env.into();
let pre = test.pre_state.into(); let pre = test.pre_state.into();
for (spec, states) in test.post_states { for (spec, states) in test.post_states {
//hardcode base fee for part of the london tests, that miss base fee field in env
let mut test_env = env_info.clone();
if spec >= ForkSpec::London {
if test_env.base_fee.is_none() {
test_env.base_fee = Some(0x0a.into());
}
}
if let Some(false) = only_chain if let Some(false) = only_chain
.as_ref() .as_ref()
.map(|only_chain| &format!("{:?}", spec).to_lowercase() == only_chain) .map(|only_chain| &format!("{:?}", spec).to_lowercase() == only_chain)
@ -218,7 +228,7 @@ fn run_state_test(args: Args) {
&spec, &spec,
&pre, &pre,
post_root, post_root,
&env_info, &test_env,
transaction, transaction,
display::json::Informant::new(config), display::json::Informant::new(config),
trie_spec, trie_spec,
@ -231,7 +241,7 @@ fn run_state_test(args: Args) {
&spec, &spec,
&pre, &pre,
post_root, post_root,
&env_info, &test_env,
transaction, transaction,
display::std_json::Informant::err_only(config), display::std_json::Informant::err_only(config),
trie_spec, trie_spec,
@ -243,7 +253,7 @@ fn run_state_test(args: Args) {
&spec, &spec,
&pre, &pre,
post_root, post_root,
&env_info, &test_env,
transaction, transaction,
display::std_json::Informant::out_only(config), display::std_json::Informant::out_only(config),
trie_spec, trie_spec,
@ -255,7 +265,7 @@ fn run_state_test(args: Args) {
&spec, &spec,
&pre, &pre,
post_root, post_root,
&env_info, &test_env,
transaction, transaction,
display::std_json::Informant::new_default(config), display::std_json::Informant::new_default(config),
trie_spec, trie_spec,
@ -268,7 +278,7 @@ fn run_state_test(args: Args) {
&spec, &spec,
&pre, &pre,
post_root, post_root,
&env_info, &test_env,
transaction, transaction,
display::simple::Informant::new(config), display::simple::Informant::new(config),
trie_spec, trie_spec,
@ -429,6 +439,7 @@ fn die<T: fmt::Display>(msg: T) -> ! {
mod tests { mod tests {
use super::{Args, USAGE}; use super::{Args, USAGE};
use docopt::Docopt; use docopt::Docopt;
use ethereum_types::Address;
fn run<T: AsRef<str>>(args: &[T]) -> Args { fn run<T: AsRef<str>>(args: &[T]) -> Args {
Docopt::new(USAGE) Docopt::new(USAGE)
@ -468,8 +479,8 @@ mod tests {
assert_eq!(args.flag_std_out_only, true); assert_eq!(args.flag_std_out_only, true);
assert_eq!(args.gas(), Ok(1.into())); assert_eq!(args.gas(), Ok(1.into()));
assert_eq!(args.gas_price(), Ok(2.into())); assert_eq!(args.gas_price(), Ok(2.into()));
assert_eq!(args.from(), Ok(3.into())); assert_eq!(args.from(), Ok(Address::from_low_u64_be(3)));
assert_eq!(args.to(), Ok(4.into())); assert_eq!(args.to(), Ok(Address::from_low_u64_be(4)));
assert_eq!(args.code(), Ok(Some(vec![05]))); assert_eq!(args.code(), Ok(Some(vec![05])));
assert_eq!(args.data(), Ok(Some(vec![06]))); assert_eq!(args.data(), Ok(Some(vec![06])));
assert_eq!(args.flag_chain, Some("./testfile".to_owned())); assert_eq!(args.flag_chain, Some("./testfile".to_owned()));

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>. // along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use params::SpecType; use crate::params::SpecType;
use std::num::NonZeroU32; use std::num::NonZeroU32;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -53,9 +53,11 @@ pub fn execute(_cmd: AccountCmd) -> Result<String, String> {
#[cfg(feature = "accounts")] #[cfg(feature = "accounts")]
mod command { mod command {
use super::*; use super::*;
use accounts::{AccountProvider, AccountProviderSettings}; use crate::{
accounts::{AccountProvider, AccountProviderSettings},
helpers::{password_from_file, password_prompt},
};
use ethstore::{accounts_dir::RootDiskDirectory, import_account, import_accounts, EthStore}; use ethstore::{accounts_dir::RootDiskDirectory, import_account, import_accounts, EthStore};
use helpers::{password_from_file, password_prompt};
use std::path::PathBuf; use std::path::PathBuf;
pub fn execute(cmd: AccountCmd) -> Result<String, String> { pub fn execute(cmd: AccountCmd) -> Result<String, String> {

View File

@ -16,11 +16,12 @@
use std::sync::Arc; use std::sync::Arc;
use crypto::publickey;
use dir::Directories; use dir::Directories;
use ethereum_types::Address; use ethereum_types::{Address, H160};
use ethkey::Password; use ethkey::Password;
use params::{AccountsConfig, SpecType}; use crate::params::{AccountsConfig, SpecType};
#[cfg(not(feature = "accounts"))] #[cfg(not(feature = "accounts"))]
mod accounts { mod accounts {
@ -70,9 +71,10 @@ mod accounts {
#[cfg(feature = "accounts")] #[cfg(feature = "accounts")]
mod accounts { mod accounts {
use super::*; use super::*;
use upgrade::upgrade_key_location; use crate::{ethereum_types::H256, upgrade::upgrade_key_location};
use std::str::FromStr;
pub use accounts::AccountProvider; pub use crate::accounts::AccountProvider;
/// Pops along with error messages when a password is missing or invalid. /// Pops along with error messages when a password is missing or invalid.
const VERIFY_PASSWORD_HINT: &str = "Make sure valid password is present in files passed using `--password` or in the configuration file."; const VERIFY_PASSWORD_HINT: &str = "Make sure valid password is present in files passed using `--password` or in the configuration file.";
@ -85,7 +87,7 @@ mod accounts {
cfg: AccountsConfig, cfg: AccountsConfig,
passwords: &[Password], passwords: &[Password],
) -> Result<AccountProvider, String> { ) -> Result<AccountProvider, String> {
use accounts::AccountProviderSettings; use crate::accounts::AccountProviderSettings;
use ethstore::{accounts_dir::RootDiskDirectory, EthStore}; use ethstore::{accounts_dir::RootDiskDirectory, EthStore};
let path = dirs.keys_path(data_dir); let path = dirs.keys_path(data_dir);
@ -103,7 +105,8 @@ mod accounts {
| SpecType::Goerli | SpecType::Goerli
| SpecType::Sokol | SpecType::Sokol
| SpecType::Dev => vec![], | SpecType::Dev => vec![],
_ => vec!["00a329c0648769a73afac7f9381e08fb43dbea72".into()], _ => vec![H160::from_str("00a329c0648769a73afac7f9381e08fb43dbea72")
.expect("the string is valid hex; qed")],
}, },
}; };
@ -195,7 +198,8 @@ mod accounts {
engine_signer, engine_signer,
password.clone(), password.clone(),
); );
if signer.sign(Default::default()).is_ok() { // sign dummy msg to check if password and account can be used.
if signer.sign(H256::from_low_u64_be(1)).is_ok() {
author = Some(::ethcore::miner::Author::Sealer(Box::new(signer))); author = Some(::ethcore::miner::Author::Sealer(Box::new(signer)));
} }
} }
@ -216,9 +220,11 @@ mod accounts {
} }
fn insert_dev_account(account_provider: &AccountProvider) { fn insert_dev_account(account_provider: &AccountProvider) {
let secret: ethkey::Secret = let secret = publickey::Secret::from_str(
"4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7".into(); "4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7",
let dev_account = ethkey::KeyPair::from_secret(secret.clone()) )
.expect("Valid account;qed");
let dev_account = publickey::KeyPair::from_secret(secret.clone())
.expect("Valid secret produces valid key;qed"); .expect("Valid secret produces valid key;qed");
if !account_provider.has_account(dev_account.address()) { if !account_provider.has_account(dev_account.address()) {
match account_provider.insert_account(secret, &Password::from(String::new())) { match account_provider.insert_account(secret, &Password::from(String::new())) {

View File

@ -16,10 +16,18 @@
use std::{fs, io, sync::Arc, time::Instant}; use std::{fs, io, sync::Arc, time::Instant};
use crate::{
bytes::ToPretty,
cache::CacheConfig,
db,
hash::{keccak, KECCAK_NULL_RLP},
helpers::{execute_upgrades, to_client_config},
informant::{FullNodeInformantData, Informant, MillisecondDuration},
params::{fatdb_switch_to_bool, tracing_switch_to_bool, Pruning, SpecType, Switch},
types::data_format::DataFormat,
user_defaults::UserDefaults,
};
use ansi_term::Colour; use ansi_term::Colour;
use bytes::ToPretty;
use cache::CacheConfig;
use db;
use dir::Directories; use dir::Directories;
use ethcore::{ use ethcore::{
client::{ client::{
@ -31,12 +39,6 @@ use ethcore::{
}; };
use ethcore_service::ClientService; use ethcore_service::ClientService;
use ethereum_types::{Address, H256, U256}; use ethereum_types::{Address, H256, U256};
use hash::{keccak, KECCAK_NULL_RLP};
use helpers::{execute_upgrades, to_client_config};
use informant::{FullNodeInformantData, Informant, MillisecondDuration};
use params::{fatdb_switch_to_bool, tracing_switch_to_bool, Pruning, SpecType, Switch};
use types::data_format::DataFormat;
use user_defaults::UserDefaults;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum BlockchainCmd { pub enum BlockchainCmd {

View File

@ -409,9 +409,9 @@ usage! {
"--jsonrpc-interface=[IP]", "--jsonrpc-interface=[IP]",
"Specify the hostname portion of the HTTP JSON-RPC API server, IP should be an interface's IP address, or all (all interfaces) or local.", "Specify the hostname portion of the HTTP JSON-RPC API server, IP should be an interface's IP address, or all (all interfaces) or local.",
ARG arg_jsonrpc_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,traces", or |c: &Config| c.rpc.as_ref()?.apis.as_ref().map(|vec| vec.join(",")), ARG arg_jsonrpc_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,traces,rpc", or |c: &Config| c.rpc.as_ref()?.apis.as_ref().map(|vec| vec.join(",")),
"--jsonrpc-apis=[APIS]", "--jsonrpc-apis=[APIS]",
"Specify the APIs available through the HTTP JSON-RPC interface using a comma-delimited list of API names. Possible names are: all, safe, debug, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, secretstore. You can also disable a specific API by putting '-' in the front, example: all,-personal. 'safe' enables the following APIs: web3, net, eth, pubsub, parity, parity_pubsub, traces", "Specify the APIs available through the HTTP JSON-RPC interface using a comma-delimited list of API names. Possible names are: all, safe, debug, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, rpc, secretstore. You can also disable a specific API by putting '-' in the front, example: all,-personal. 'safe' enables the following APIs: web3, net, eth, pubsub, parity, parity_pubsub, traces, rpc",
ARG arg_jsonrpc_hosts: (String) = "none", or |c: &Config| c.rpc.as_ref()?.hosts.as_ref().map(|vec| vec.join(",")), ARG arg_jsonrpc_hosts: (String) = "none", or |c: &Config| c.rpc.as_ref()?.hosts.as_ref().map(|vec| vec.join(",")),
"--jsonrpc-hosts=[HOSTS]", "--jsonrpc-hosts=[HOSTS]",
@ -450,9 +450,9 @@ usage! {
"--ws-interface=[IP]", "--ws-interface=[IP]",
"Specify the hostname portion of the WebSockets JSON-RPC server, IP should be an interface's IP address, or all (all interfaces) or local.", "Specify the hostname portion of the WebSockets JSON-RPC server, IP should be an interface's IP address, or all (all interfaces) or local.",
ARG arg_ws_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,traces", or |c: &Config| c.websockets.as_ref()?.apis.as_ref().map(|vec| vec.join(",")), ARG arg_ws_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,traces,rpc", or |c: &Config| c.websockets.as_ref()?.apis.as_ref().map(|vec| vec.join(",")),
"--ws-apis=[APIS]", "--ws-apis=[APIS]",
"Specify the JSON-RPC APIs available through the WebSockets interface using a comma-delimited list of API names. Possible names are: all, safe, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, secretstore. You can also disable a specific API by putting '-' in the front, example: all,-personal. 'safe' enables the following APIs: web3, net, eth, pubsub, parity, parity_pubsub, traces", "Specify the JSON-RPC APIs available through the WebSockets interface using a comma-delimited list of API names. Possible names are: all, safe, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, rpc, secretstore. You can also disable a specific API by putting '-' in the front, example: all,-personal. 'safe' enables the following APIs: web3, net, eth, pubsub, parity, parity_pubsub, traces, rpc",
ARG arg_ws_origins: (String) = "parity://*,chrome-extension://*,moz-extension://*", or |c: &Config| c.websockets.as_ref()?.origins.as_ref().map(|vec| vec.join(",")), ARG arg_ws_origins: (String) = "parity://*,chrome-extension://*,moz-extension://*", or |c: &Config| c.websockets.as_ref()?.origins.as_ref().map(|vec| vec.join(",")),
"--ws-origins=[URL]", "--ws-origins=[URL]",
@ -475,6 +475,10 @@ usage! {
"--metrics", "--metrics",
"Enable prometheus metrics (only full client).", "Enable prometheus metrics (only full client).",
ARG arg_metrics_prefix: (String) = "", or |c: &Config| c.metrics.as_ref()?.prefix.clone(),
"--metrics-prefix=[prefix]",
"Prepend the specified prefix to the exported metrics names.",
ARG arg_metrics_port: (u16) = 3000u16, or |c: &Config| c.metrics.as_ref()?.port.clone(), ARG arg_metrics_port: (u16) = 3000u16, or |c: &Config| c.metrics.as_ref()?.port.clone(),
"--metrics-port=[PORT]", "--metrics-port=[PORT]",
"Specify the port portion of the metrics server.", "Specify the port portion of the metrics server.",
@ -492,9 +496,9 @@ usage! {
"--ipc-path=[PATH]", "--ipc-path=[PATH]",
"Specify custom path for JSON-RPC over IPC service.", "Specify custom path for JSON-RPC over IPC service.",
ARG arg_ipc_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,parity_accounts,traces", or |c: &Config| c.ipc.as_ref()?.apis.as_ref().map(|vec| vec.join(",")), ARG arg_ipc_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,parity_accounts,traces,rpc", or |c: &Config| c.ipc.as_ref()?.apis.as_ref().map(|vec| vec.join(",")),
"--ipc-apis=[APIS]", "--ipc-apis=[APIS]",
"Specify custom API set available via JSON-RPC over IPC using a comma-delimited list of API names. Possible names are: all, safe, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, secretstore. You can also disable a specific API by putting '-' in the front, example: all,-personal. 'safe' enables the following APIs: web3, net, eth, pubsub, parity, parity_pubsub, traces", "Specify custom API set available via JSON-RPC over IPC using a comma-delimited list of API names. Possible names are: all, safe, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, rpc, secretstore. You can also disable a specific API by putting '-' in the front, example: all,-personal. 'safe' enables the following APIs: web3, net, eth, pubsub, parity, parity_pubsub, traces, rpc",
["Secret Store Options"] ["Secret Store Options"]
FLAG flag_no_secretstore: (bool) = false, or |c: &Config| c.secretstore.as_ref()?.disable.clone(), FLAG flag_no_secretstore: (bool) = false, or |c: &Config| c.secretstore.as_ref()?.disable.clone(),
@ -676,7 +680,7 @@ usage! {
ARG arg_min_gas_price: (Option<u64>) = None, or |c: &Config| c.mining.as_ref()?.min_gas_price.clone(), ARG arg_min_gas_price: (Option<u64>) = None, or |c: &Config| c.mining.as_ref()?.min_gas_price.clone(),
"--min-gas-price=[STRING]", "--min-gas-price=[STRING]",
"Minimum amount of Wei per GAS to be paid for a transaction to be accepted for mining. Overrides --usd-per-tx.", "Minimum amount of Wei per GAS to be paid for a transaction on top of base fee, to be accepted for mining. Overrides --usd-per-tx.",
ARG arg_gas_price_percentile: (usize) = 50usize, or |c: &Config| c.mining.as_ref()?.gas_price_percentile, ARG arg_gas_price_percentile: (usize) = 50usize, or |c: &Config| c.mining.as_ref()?.gas_price_percentile,
"--gas-price-percentile=[PCT]", "--gas-price-percentile=[PCT]",
@ -922,6 +926,7 @@ struct Ipc {
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
struct Metrics { struct Metrics {
enable: Option<bool>, enable: Option<bool>,
prefix: Option<String>,
port: Option<u16>, port: Option<u16>,
interface: Option<String>, interface: Option<String>,
} }
@ -1312,7 +1317,7 @@ mod tests {
arg_jsonrpc_port: 8545u16, arg_jsonrpc_port: 8545u16,
arg_jsonrpc_interface: "local".into(), arg_jsonrpc_interface: "local".into(),
arg_jsonrpc_cors: "null".into(), arg_jsonrpc_cors: "null".into(),
arg_jsonrpc_apis: "web3,eth,net,parity,traces,secretstore".into(), arg_jsonrpc_apis: "web3,eth,net,parity,traces,rpc,secretstore".into(),
arg_jsonrpc_hosts: "none".into(), arg_jsonrpc_hosts: "none".into(),
arg_jsonrpc_server_threads: None, arg_jsonrpc_server_threads: None,
arg_jsonrpc_threads: 4, arg_jsonrpc_threads: 4,
@ -1324,7 +1329,7 @@ mod tests {
flag_no_ws: false, flag_no_ws: false,
arg_ws_port: 8546u16, arg_ws_port: 8546u16,
arg_ws_interface: "local".into(), arg_ws_interface: "local".into(),
arg_ws_apis: "web3,eth,net,parity,traces,secretstore".into(), arg_ws_apis: "web3,eth,net,parity,traces,rpc,secretstore".into(),
arg_ws_origins: "none".into(), arg_ws_origins: "none".into(),
arg_ws_hosts: "none".into(), arg_ws_hosts: "none".into(),
arg_ws_max_connections: 100, arg_ws_max_connections: 100,
@ -1333,11 +1338,12 @@ mod tests {
// IPC // IPC
flag_no_ipc: false, flag_no_ipc: false,
arg_ipc_path: "$HOME/.parity/jsonrpc.ipc".into(), arg_ipc_path: "$HOME/.parity/jsonrpc.ipc".into(),
arg_ipc_apis: "web3,eth,net,parity,parity_accounts,personal,traces,secretstore" arg_ipc_apis: "web3,eth,net,parity,parity_accounts,personal,traces,rpc,secretstore"
.into(), .into(),
// METRICS // METRICS
flag_metrics: false, flag_metrics: false,
arg_metrics_prefix: "".into(),
arg_metrics_port: 3000u16, arg_metrics_port: 3000u16,
arg_metrics_interface: "local".into(), arg_metrics_interface: "local".into(),
@ -1542,6 +1548,7 @@ mod tests {
}), }),
metrics: Some(Metrics { metrics: Some(Metrics {
enable: Some(true), enable: Some(true),
prefix: Some("oe".to_string()),
interface: Some("local".to_string()), interface: Some("local".to_string()),
port: Some(4000), port: Some(4000),
}), }),

View File

@ -39,7 +39,7 @@ disable = false
port = 8545 port = 8545
interface = "local" interface = "local"
cors = ["null"] cors = ["null"]
apis = ["web3", "eth", "net", "parity", "traces", "secretstore"] apis = ["web3", "eth", "net", "parity", "traces", "rpc", "secretstore"]
hosts = ["none"] hosts = ["none"]
allow_missing_blocks = false allow_missing_blocks = false
@ -48,13 +48,13 @@ disable = false
port = 8546 port = 8546
interface = "local" interface = "local"
origins = ["none"] origins = ["none"]
apis = ["web3", "eth", "net", "parity", "traces", "secretstore"] apis = ["web3", "eth", "net", "parity", "traces", "rpc", "secretstore"]
hosts = ["none"] hosts = ["none"]
[ipc] [ipc]
disable = false disable = false
path = "$HOME/.parity/jsonrpc.ipc" path = "$HOME/.parity/jsonrpc.ipc"
apis = ["web3", "eth", "net", "parity", "parity_accounts", "personal", "traces", "secretstore"] apis = ["web3", "eth", "net", "parity", "parity_accounts", "personal", "traces", "rpc", "secretstore"]
[secretstore] [secretstore]
disable = false disable = false

View File

@ -36,7 +36,7 @@ apis = ["rpc", "eth"]
enable = true enable = true
interface = "local" interface = "local"
port = 4000 port = 4000
prefix = "oe"
[secretstore] [secretstore]
http_port = 8082 http_port = 8082

View File

@ -14,9 +14,17 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>. // along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use crate::{
bytes::Bytes,
cli::{Args, ArgsError},
hash::keccak,
metrics::MetricsConfiguration,
miner::pool,
sync::{self, validate_node_url, NetworkConfiguration},
};
use ansi_term::Colour; use ansi_term::Colour;
use bytes::Bytes;
use cli::{Args, ArgsError}; use crypto::publickey::{Public, Secret};
use ethcore::{ use ethcore::{
client::VMType, client::VMType,
miner::{stratum, MinerOptions}, miner::{stratum, MinerOptions},
@ -24,10 +32,7 @@ use ethcore::{
verification::queue::VerifierSettings, verification::queue::VerifierSettings,
}; };
use ethereum_types::{Address, H256, U256}; use ethereum_types::{Address, H256, U256};
use ethkey::{Public, Secret};
use hash::keccak;
use metrics::MetricsConfiguration;
use miner::pool;
use num_cpus; use num_cpus;
use parity_version::{version, version_data}; use parity_version::{version, version_data};
use std::{ use std::{
@ -40,35 +45,37 @@ use std::{
path::PathBuf, path::PathBuf,
time::Duration, time::Duration,
}; };
use sync::{self, validate_node_url, NetworkConfiguration};
use account::{AccountCmd, ImportAccounts, ListAccounts, NewAccount}; use crate::{
use blockchain::{ account::{AccountCmd, ImportAccounts, ListAccounts, NewAccount},
BlockchainCmd, ExportBlockchain, ExportState, ImportBlockchain, KillBlockchain, ResetBlockchain, blockchain::{
BlockchainCmd, ExportBlockchain, ExportState, ImportBlockchain, KillBlockchain,
ResetBlockchain,
},
cache::CacheConfig,
helpers::{
parity_ipc_path, to_address, to_addresses, to_block_id, to_bootnodes, to_duration, to_mode,
to_pending_set, to_price, to_queue_penalization, to_queue_strategy, to_u256,
},
network::IpFilter,
params::{AccountsConfig, GasPricerConfig, MinerExtras, ResealPolicy, SpecType},
presale::ImportWallet,
rpc::{HttpConfiguration, IpcConfiguration, WsConfiguration},
run::RunCmd,
secretstore::{
Configuration as SecretStoreConfiguration, ContractAddress as SecretStoreContractAddress,
NodeSecretKey,
},
snapshot::{self, SnapshotCommand},
types::data_format::DataFormat,
}; };
use cache::CacheConfig;
use dir::{ use dir::{
self, default_data_path, default_local_path, self, default_data_path, default_local_path,
helpers::{replace_home, replace_home_and_local}, helpers::{replace_home, replace_home_and_local},
Directories, Directories,
}; };
use ethcore_logger::Config as LogConfig; use ethcore_logger::Config as LogConfig;
use helpers::{
parity_ipc_path, to_address, to_addresses, to_block_id, to_bootnodes, to_duration, to_mode,
to_pending_set, to_price, to_queue_penalization, to_queue_strategy, to_u256,
};
use network::IpFilter;
use params::{AccountsConfig, GasPricerConfig, MinerExtras, ResealPolicy, SpecType};
use parity_rpc::NetworkSettings; use parity_rpc::NetworkSettings;
use presale::ImportWallet;
use rpc::{HttpConfiguration, IpcConfiguration, WsConfiguration};
use run::RunCmd;
use secretstore::{
Configuration as SecretStoreConfiguration, ContractAddress as SecretStoreContractAddress,
NodeSecretKey,
};
use snapshot::{self, SnapshotCommand};
use types::data_format::DataFormat;
const DEFAULT_MAX_PEERS: u16 = 50; const DEFAULT_MAX_PEERS: u16 = 50;
const DEFAULT_MIN_PEERS: u16 = 25; const DEFAULT_MIN_PEERS: u16 = 25;
@ -166,7 +173,7 @@ impl Configuration {
let cmd = if self.args.flag_version { let cmd = if self.args.flag_version {
Cmd::Version Cmd::Version
} else if self.args.cmd_signer { } else if self.args.cmd_signer {
let authfile = ::signer::codes_path(&ws_conf.signer_path); let authfile = crate::signer::codes_path(&ws_conf.signer_path);
if self.args.cmd_signer_new_token { if self.args.cmd_signer_new_token {
Cmd::SignerToken(ws_conf, logger_config.clone()) Cmd::SignerToken(ws_conf, logger_config.clone())
@ -633,14 +640,16 @@ impl Configuration {
fn pool_verification_options(&self) -> Result<pool::verifier::Options, String> { fn pool_verification_options(&self) -> Result<pool::verifier::Options, String> {
Ok(pool::verifier::Options { Ok(pool::verifier::Options {
// NOTE min_gas_price and block_gas_limit will be overwritten right after start. // NOTE min_gas_price,block_gas_limit block_base_fee, and allow_non_eoa_sender will be overwritten right after start.
minimal_gas_price: U256::from(20_000_000) * 1_000u32, minimal_gas_price: U256::from(20_000_000) * 1_000u32,
block_gas_limit: U256::max_value(), block_gas_limit: U256::max_value(),
block_base_fee: None,
tx_gas_limit: match self.args.arg_tx_gas_limit { tx_gas_limit: match self.args.arg_tx_gas_limit {
Some(ref d) => to_u256(d)?, Some(ref d) => to_u256(d)?,
None => U256::max_value(), None => U256::max_value(),
}, },
no_early_reject: self.args.flag_tx_queue_no_early_reject, no_early_reject: self.args.flag_tx_queue_no_early_reject,
allow_non_eoa_sender: false,
}) })
} }
@ -810,7 +819,7 @@ impl Configuration {
ret.public_address = public.map(|p| format!("{}", p)); ret.public_address = public.map(|p| format!("{}", p));
ret.use_secret = match self.args.arg_node_key.as_ref().map(|s| { ret.use_secret = match self.args.arg_node_key.as_ref().map(|s| {
s.parse::<Secret>() s.parse::<Secret>()
.or_else(|_| Secret::from_unsafe_slice(&keccak(s))) .or_else(|_| Secret::import_key(keccak(s).as_bytes()))
.map_err(|e| format!("Invalid key: {:?}", e)) .map_err(|e| format!("Invalid key: {:?}", e))
}) { }) {
None => None, None => None,
@ -958,6 +967,7 @@ impl Configuration {
fn metrics_config(&self) -> Result<MetricsConfiguration, String> { fn metrics_config(&self) -> Result<MetricsConfiguration, String> {
let conf = MetricsConfiguration { let conf = MetricsConfiguration {
enabled: self.metrics_enabled(), enabled: self.metrics_enabled(),
prefix: self.metrics_prefix(),
interface: self.metrics_interface(), interface: self.metrics_interface(),
port: self.args.arg_ports_shift + self.args.arg_metrics_port, port: self.args.arg_ports_shift + self.args.arg_metrics_port,
}; };
@ -1147,6 +1157,10 @@ impl Configuration {
self.args.flag_metrics self.args.flag_metrics
} }
fn metrics_prefix(&self) -> String {
self.args.arg_metrics_prefix.clone()
}
fn secretstore_enabled(&self) -> bool { fn secretstore_enabled(&self) -> bool {
!self.args.flag_no_secretstore && cfg!(feature = "secretstore") !self.args.flag_no_secretstore && cfg!(feature = "secretstore")
} }
@ -1238,23 +1252,25 @@ fn into_secretstore_service_contract_address(
mod tests { mod tests {
use std::{fs::File, io::Write, str::FromStr}; use std::{fs::File, io::Write, str::FromStr};
use account::{AccountCmd, ImportAccounts, ListAccounts, NewAccount}; use crate::{
use blockchain::{BlockchainCmd, ExportBlockchain, ExportState, ImportBlockchain}; account::{AccountCmd, ImportAccounts, ListAccounts, NewAccount},
use cli::Args; blockchain::{BlockchainCmd, ExportBlockchain, ExportState, ImportBlockchain},
cli::Args,
helpers::default_network_config,
miner::pool::PrioritizationStrategy,
params::SpecType,
presale::ImportWallet,
rpc::WsConfiguration,
rpc_apis::ApiSet,
run::RunCmd,
types::{data_format::DataFormat, ids::BlockId},
};
use dir::Directories; use dir::Directories;
use ethcore::{client::VMType, miner::MinerOptions}; use ethcore::{client::VMType, miner::MinerOptions};
use helpers::default_network_config;
use miner::pool::PrioritizationStrategy;
use params::SpecType;
use parity_rpc::NetworkSettings; use parity_rpc::NetworkSettings;
use presale::ImportWallet;
use rpc::WsConfiguration;
use rpc_apis::ApiSet;
use run::RunCmd;
use tempdir::TempDir; use tempdir::TempDir;
use types::{data_format::DataFormat, ids::BlockId};
use network::{AllowIP, IpFilter}; use crate::network::{AllowIP, IpFilter};
extern crate ipnetwork; extern crate ipnetwork;
use self::ipnetwork::IpNetwork; use self::ipnetwork::IpNetwork;
@ -1741,7 +1757,7 @@ mod tests {
ApiSet::List(set) => assert_eq!(set, ApiSet::All.list_apis()), ApiSet::List(set) => assert_eq!(set, ApiSet::All.list_apis()),
_ => panic!("Incorrect rpc apis"), _ => panic!("Incorrect rpc apis"),
} }
// "web3,eth,net,personal,parity,parity_set,traces,parity_accounts"); // "web3,eth,net,personal,parity,parity_set,traces,rpc,parity_accounts");
assert_eq!(c.http_conf.hosts, None); assert_eq!(c.http_conf.hosts, None);
} }
_ => panic!("Should be Cmd::Run"), _ => panic!("Should be Cmd::Run"),
@ -1762,7 +1778,7 @@ mod tests {
ApiSet::List(set) => assert_eq!(set, ApiSet::All.list_apis()), ApiSet::List(set) => assert_eq!(set, ApiSet::All.list_apis()),
_ => panic!("Incorrect rpc apis"), _ => panic!("Incorrect rpc apis"),
} }
// "web3,eth,net,personal,parity,parity_set,traces,parity_accounts"); // "web3,eth,net,personal,parity,parity_set,traces,rpc,parity_accounts");
assert_eq!(c.http_conf.hosts, None); assert_eq!(c.http_conf.hosts, None);
} }
_ => panic!("Should be Cmd::Run"), _ => panic!("Should be Cmd::Run"),

View File

@ -24,7 +24,8 @@ use self::{
}; };
use blooms_db; use blooms_db;
use ethcore::client::ClientConfig; use ethcore::client::ClientConfig;
use kvdb::KeyValueDB; use ethcore_db::KeyValueDB;
use stats::PrometheusMetrics;
use std::{fs, io, path::Path, sync::Arc}; use std::{fs, io, path::Path, sync::Arc};
mod blooms; mod blooms;
@ -53,6 +54,10 @@ impl BlockChainDB for AppDB {
} }
} }
impl PrometheusMetrics for AppDB {
fn prometheus_metrics(&self, _: &mut stats::PrometheusRegistry) {}
}
/// Open a secret store DB using the given secret store data path. The DB path is one level beneath the data path. /// Open a secret store DB using the given secret store data path. The DB path is one level beneath the data path.
#[cfg(feature = "secretstore")] #[cfg(feature = "secretstore")]
pub fn open_secretstore_db(data_path: &str) -> Result<Arc<dyn KeyValueDB>, String> { pub fn open_secretstore_db(data_path: &str) -> Result<Arc<dyn KeyValueDB>, String> {
@ -101,8 +106,11 @@ pub fn open_database(
fs::create_dir_all(&blooms_path)?; fs::create_dir_all(&blooms_path)?;
fs::create_dir_all(&trace_blooms_path)?; fs::create_dir_all(&trace_blooms_path)?;
let db = Database::open(&config, client_path)?;
let db_with_metrics = ethcore_db::DatabaseWithMetrics::new(db);
let db = AppDB { let db = AppDB {
key_value: Arc::new(Database::open(&config, client_path)?), key_value: Arc::new(db_with_metrics),
blooms: blooms_db::Database::open(blooms_path)?, blooms: blooms_db::Database::open(blooms_path)?,
trace_blooms: blooms_db::Database::open(trace_blooms_path)?, trace_blooms: blooms_db::Database::open(trace_blooms_path)?,
}; };

View File

@ -14,17 +14,21 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>. // along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use cache::CacheConfig; use crate::{
use db::migrate; cache::CacheConfig,
db::migrate,
miner::pool::PrioritizationStrategy,
sync::{self, validate_node_url},
upgrade::{upgrade, upgrade_data_paths},
};
use dir::{helpers::replace_home, DatabaseDirectories}; use dir::{helpers::replace_home, DatabaseDirectories};
use ethcore::{ use ethcore::{
client::{BlockId, ClientConfig, DatabaseCompactionProfile, Mode, VMType, VerifierType}, client::{BlockId, ClientConfig, DatabaseCompactionProfile, Mode, VMType, VerifierType},
miner::{Penalization, PendingSet}, miner::{Penalization, PendingSet},
}; };
use ethereum_types::{clean_0x, Address, U256}; use ethereum_types::{Address, U256};
use ethkey::Password; use ethkey::Password;
use journaldb::Algorithm; use journaldb::Algorithm;
use miner::pool::PrioritizationStrategy;
use std::{ use std::{
collections::HashSet, collections::HashSet,
fs::File, fs::File,
@ -32,13 +36,19 @@ use std::{
io::{BufRead, BufReader, Write}, io::{BufRead, BufReader, Write},
time::Duration, time::Duration,
}; };
use sync::{self, validate_node_url};
use upgrade::{upgrade, upgrade_data_paths};
pub fn to_duration(s: &str) -> Result<Duration, String> { pub fn to_duration(s: &str) -> Result<Duration, String> {
to_seconds(s).map(Duration::from_secs) to_seconds(s).map(Duration::from_secs)
} }
fn clean_0x(s: &str) -> &str {
if s.starts_with("0x") {
&s[2..]
} else {
s
}
}
fn to_seconds(s: &str) -> Result<u64, String> { fn to_seconds(s: &str) -> Result<u64, String> {
let bad = |_| { let bad = |_| {
format!( format!(
@ -215,9 +225,9 @@ pub fn to_bootnodes(bootnodes: &Option<String>) -> Result<Vec<String>, String> {
} }
#[cfg(test)] #[cfg(test)]
pub fn default_network_config() -> ::sync::NetworkConfiguration { pub fn default_network_config() -> crate::sync::NetworkConfiguration {
use super::network::IpFilter; use super::network::IpFilter;
use sync::NetworkConfiguration; use crate::sync::NetworkConfiguration;
NetworkConfiguration { NetworkConfiguration {
config_path: Some(replace_home(&::dir::default_data_path(), "$BASE/network")), config_path: Some(replace_home(&::dir::default_data_path(), "$BASE/network")),
net_config_path: None, net_config_path: None,

View File

@ -29,6 +29,11 @@ use std::{
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use crate::{
io::{IoContext, IoHandler, TimerToken},
sync::{ManageNetwork, SyncProvider},
types::BlockNumber,
};
use atty; use atty;
use ethcore::{ use ethcore::{
client::{ client::{
@ -37,12 +42,9 @@ use ethcore::{
}, },
snapshot::{service::Service as SnapshotService, RestorationStatus, SnapshotService as SS}, snapshot::{service::Service as SnapshotService, RestorationStatus, SnapshotService as SS},
}; };
use io::{IoContext, IoHandler, TimerToken};
use number_prefix::{binary_prefix, Prefixed, Standalone}; use number_prefix::{binary_prefix, Prefixed, Standalone};
use parity_rpc::{informant::RpcStats, is_major_importing_or_waiting}; use parity_rpc::{informant::RpcStats, is_major_importing_or_waiting};
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
use sync::{ManageNetwork, SyncProvider};
use types::BlockNumber;
/// Format byte counts to standard denominations. /// Format byte counts to standard denominations.
pub fn format_bytes(b: usize) -> String { pub fn format_bytes(b: usize) -> String {

View File

@ -61,6 +61,7 @@ extern crate keccak_hash as hash;
extern crate kvdb; extern crate kvdb;
extern crate node_filter; extern crate node_filter;
extern crate parity_bytes as bytes; extern crate parity_bytes as bytes;
extern crate parity_crypto as crypto;
extern crate parity_local_store as local_store; extern crate parity_local_store as local_store;
extern crate parity_path as path; extern crate parity_path as path;
extern crate parity_rpc; extern crate parity_rpc;
@ -113,9 +114,11 @@ mod user_defaults;
use std::{fs::File, io::BufReader, sync::Arc}; use std::{fs::File, io::BufReader, sync::Arc};
use cli::Args; use crate::{
use configuration::{Cmd, Execute}; cli::Args,
use hash::keccak_buffer; configuration::{Cmd, Execute},
hash::keccak_buffer,
};
#[cfg(feature = "memory_profiling")] #[cfg(feature = "memory_profiling")]
use std::alloc::System; use std::alloc::System;

View File

@ -12,6 +12,6 @@ atty = "0.2"
lazy_static = "1.0" lazy_static = "1.0"
regex = "1.0" regex = "1.0"
time = "0.1" time = "0.1"
parking_lot = "0.7" parking_lot = "0.11.1"
arrayvec = "0.4" arrayvec = "0.4"
ansi_term = "0.10" ansi_term = "0.10"

View File

@ -8,13 +8,15 @@ use hyper::{service::service_fn_ok, Body, Method, Request, Response, Server, Sta
use stats::{ use stats::{
prometheus::{self, Encoder}, prometheus::{self, Encoder},
prometheus_gauge, PrometheusMetrics, PrometheusMetrics, PrometheusRegistry,
}; };
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct MetricsConfiguration { pub struct MetricsConfiguration {
/// Are metrics enabled (default is false)? /// Are metrics enabled (default is false)?
pub enabled: bool, pub enabled: bool,
/// Prefix
pub prefix: String,
/// The IP of the network interface used (default is 127.0.0.1). /// The IP of the network interface used (default is 127.0.0.1).
pub interface: String, pub interface: String,
/// The network port (default is 3000). /// The network port (default is 3000).
@ -25,6 +27,7 @@ impl Default for MetricsConfiguration {
fn default() -> Self { fn default() -> Self {
MetricsConfiguration { MetricsConfiguration {
enabled: false, enabled: false,
prefix: "".into(),
interface: "127.0.0.1".into(), interface: "127.0.0.1".into(),
port: 3000, port: 3000,
} }
@ -35,19 +38,22 @@ struct State {
rpc_apis: Arc<rpc_apis::FullDependencies>, rpc_apis: Arc<rpc_apis::FullDependencies>,
} }
fn handle_request(req: Request<Body>, state: Arc<Mutex<State>>) -> Response<Body> { fn handle_request(
req: Request<Body>,
conf: Arc<MetricsConfiguration>,
state: Arc<Mutex<State>>,
) -> Response<Body> {
let (parts, _body) = req.into_parts(); let (parts, _body) = req.into_parts();
match (parts.method, parts.uri.path()) { match (parts.method, parts.uri.path()) {
(Method::GET, "/metrics") => { (Method::GET, "/metrics") => {
let start = Instant::now(); let start = Instant::now();
let mut reg = prometheus::Registry::new(); let mut reg = PrometheusRegistry::new(conf.prefix.clone());
let state = state.lock(); let state = state.lock();
state.rpc_apis.client.prometheus_metrics(&mut reg); state.rpc_apis.client.prometheus_metrics(&mut reg);
state.rpc_apis.sync.prometheus_metrics(&mut reg); state.rpc_apis.sync.prometheus_metrics(&mut reg);
let elapsed = start.elapsed(); let elapsed = start.elapsed();
prometheus_gauge( reg.register_gauge(
&mut reg,
"metrics_time", "metrics_time",
"Time to perform rpc metrics", "Time to perform rpc metrics",
elapsed.as_millis() as i64, elapsed.as_millis() as i64,
@ -55,7 +61,7 @@ fn handle_request(req: Request<Body>, state: Arc<Mutex<State>>) -> Response<Body
let mut buffer = vec![]; let mut buffer = vec![];
let encoder = prometheus::TextEncoder::new(); let encoder = prometheus::TextEncoder::new();
let metric_families = reg.gather(); let metric_families = reg.registry().gather();
encoder encoder
.encode(&metric_families, &mut buffer) .encode(&metric_families, &mut buffer)
@ -90,17 +96,20 @@ pub fn start_prometheus_metrics(
rpc_apis: deps.apis.clone(), rpc_apis: deps.apis.clone(),
}; };
let state = Arc::new(Mutex::new(state)); let state = Arc::new(Mutex::new(state));
let conf = Arc::new(conf.to_owned());
let server = Server::bind(&addr) let server = Server::bind(&addr)
.serve(move || { .serve(move || {
// This is the `Service` that will handle the connection. // This is the `Service` that will handle the connection.
// `service_fn_ok` is a helper to convert a function that // `service_fn_ok` is a helper to convert a function that
// returns a Response into a `Service`. // returns a Response into a `Service`.
let state = state.clone(); let state = state.clone();
service_fn_ok(move |req: Request<Body>| handle_request(req, state.clone())) let conf = conf.clone();
service_fn_ok(move |req: Request<Body>| {
handle_request(req, conf.clone(), state.clone())
})
}) })
.map_err(|e| eprintln!("server error: {}", e)); .map_err(|e| eprintln!("server error: {}", e));
println!("Listening on http://{}", addr); info!("Started prometeus metrics at http://{}/metrics", addr);
deps.executor.spawn(server); deps.executor.spawn(server);

View File

@ -16,14 +16,16 @@
use std::sync::{mpsc, Arc}; use std::sync::{mpsc, Arc};
use crate::{
sync::{self, ConnectionFilter, NetworkConfiguration, Params, SyncConfig},
types::BlockNumber,
};
use ethcore::{client::BlockChainClient, snapshot::SnapshotService}; use ethcore::{client::BlockChainClient, snapshot::SnapshotService};
use std::collections::BTreeSet; use std::collections::BTreeSet;
use sync::{self, ConnectionFilter, NetworkConfiguration, Params, SyncConfig};
use types::BlockNumber;
pub use crate::sync::{EthSync, ManageNetwork, SyncProvider};
pub use ethcore::client::ChainNotify; pub use ethcore::client::ChainNotify;
use ethcore_logger::Config as LogConfig; use ethcore_logger::Config as LogConfig;
pub use sync::{EthSync, ManageNetwork, SyncProvider};
pub type SyncModules = ( pub type SyncModules = (
Arc<dyn SyncProvider>, Arc<dyn SyncProvider>,

View File

@ -16,6 +16,13 @@
use std::{collections::HashSet, fmt, fs, num::NonZeroU32, str, time::Duration}; use std::{collections::HashSet, fmt, fs, num::NonZeroU32, str, time::Duration};
use crate::{
miner::{
gas_price_calibrator::{GasPriceCalibrator, GasPriceCalibratorOptions},
gas_pricer::GasPricer,
},
user_defaults::UserDefaults,
};
use ethcore::{ use ethcore::{
client::Mode, client::Mode,
ethereum, ethereum,
@ -24,13 +31,8 @@ use ethcore::{
use ethereum_types::{Address, U256}; use ethereum_types::{Address, U256};
use fetch::Client as FetchClient; use fetch::Client as FetchClient;
use journaldb::Algorithm; use journaldb::Algorithm;
use miner::{
gas_price_calibrator::{GasPriceCalibrator, GasPriceCalibratorOptions},
gas_pricer::GasPricer,
};
use parity_runtime::Executor; use parity_runtime::Executor;
use parity_version::version_data; use parity_version::version_data;
use user_defaults::UserDefaults;
use crate::configuration; use crate::configuration;
@ -374,8 +376,8 @@ pub fn mode_switch_to_bool(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{tracing_switch_to_bool, Pruning, ResealPolicy, SpecType, Switch}; use super::{tracing_switch_to_bool, Pruning, ResealPolicy, SpecType, Switch};
use crate::user_defaults::UserDefaults;
use journaldb::Algorithm; use journaldb::Algorithm;
use user_defaults::UserDefaults;
#[test] #[test]
fn test_spec_type_parsing() { fn test_spec_type_parsing() {

View File

@ -14,10 +14,14 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>. // along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use crate::{
helpers::{password_from_file, password_prompt},
params::SpecType,
};
use crypto::publickey;
use ethkey::Password; use ethkey::Password;
use ethstore::PresaleWallet; use ethstore::PresaleWallet;
use helpers::{password_from_file, password_prompt};
use params::SpecType;
use std::num::NonZeroU32; use std::num::NonZeroU32;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -44,7 +48,8 @@ pub fn execute(cmd: ImportWallet) -> Result<String, String> {
} }
#[cfg(feature = "accounts")] #[cfg(feature = "accounts")]
pub fn import_account(cmd: &ImportWallet, kp: ethkey::KeyPair, password: Password) {
pub fn import_account(cmd: &ImportWallet, kp: publickey::KeyPair, password: Password) {
use accounts::{AccountProvider, AccountProviderSettings}; use accounts::{AccountProvider, AccountProviderSettings};
use ethstore::{accounts_dir::RootDiskDirectory, EthStore}; use ethstore::{accounts_dir::RootDiskDirectory, EthStore};
@ -57,4 +62,4 @@ pub fn import_account(cmd: &ImportWallet, kp: ethkey::KeyPair, password: Passwor
} }
#[cfg(not(feature = "accounts"))] #[cfg(not(feature = "accounts"))]
pub fn import_account(_cmd: &ImportWallet, _kp: ethkey::KeyPair, _password: Password) {} pub fn import_account(_cmd: &ImportWallet, _kp: publickey::KeyPair, _password: Password) {}

View File

@ -16,8 +16,11 @@
use std::{collections::HashSet, io, path::PathBuf, sync::Arc}; use std::{collections::HashSet, io, path::PathBuf, sync::Arc};
use crate::{
helpers::parity_ipc_path,
rpc_apis::{self, ApiSet},
};
use dir::{default_data_path, helpers::replace_home}; use dir::{default_data_path, helpers::replace_home};
use helpers::parity_ipc_path;
use jsonrpc_core::MetaIoHandler; use jsonrpc_core::MetaIoHandler;
use parity_rpc::{ use parity_rpc::{
self as rpc, self as rpc,
@ -25,7 +28,6 @@ use parity_rpc::{
DomainsValidation, Metadata, DomainsValidation, Metadata,
}; };
use parity_runtime::Executor; use parity_runtime::Executor;
use rpc_apis::{self, ApiSet};
pub use parity_rpc::{HttpServer, IpcServer, RequestMiddleware}; pub use parity_rpc::{HttpServer, IpcServer, RequestMiddleware};
//pub use parity_rpc::ws::Server as WsServer; //pub use parity_rpc::ws::Server as WsServer;
@ -182,7 +184,7 @@ pub fn new_ws<D: rpc_apis::Dependencies>(
let signer_path; let signer_path;
let path = match conf.support_token_api { let path = match conf.support_token_api {
true => { true => {
signer_path = ::signer::codes_path(&conf.signer_path); signer_path = crate::signer::codes_path(&conf.signer_path);
Some(signer_path.as_path()) Some(signer_path.as_path())
} }
false => None, false => None,

View File

@ -14,16 +14,24 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>. // along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use std::{cmp::PartialEq, collections::HashSet, str::FromStr, sync::Arc}; use std::{
cmp::PartialEq,
collections::{BTreeMap, HashSet},
str::FromStr,
sync::Arc,
};
pub use parity_rpc::signer::SignerService; pub use parity_rpc::signer::SignerService;
use account_utils::{self, AccountProvider}; use crate::{
account_utils::{self, AccountProvider},
miner::external::ExternalMiner,
sync::{ManageNetwork, SyncProvider},
};
use ethcore::{client::Client, miner::Miner, snapshot::SnapshotService}; use ethcore::{client::Client, miner::Miner, snapshot::SnapshotService};
use ethcore_logger::RotatingLogger; use ethcore_logger::RotatingLogger;
use fetch::Client as FetchClient; use fetch::Client as FetchClient;
use jsonrpc_core::{self as core, MetaIoHandler}; use jsonrpc_core::{self as core, MetaIoHandler};
use miner::external::ExternalMiner;
use parity_rpc::{ use parity_rpc::{
dispatch::FullDispatcher, dispatch::FullDispatcher,
informant::{ActivityNotifier, ClientNotifier}, informant::{ActivityNotifier, ClientNotifier},
@ -31,7 +39,6 @@ use parity_rpc::{
}; };
use parity_runtime::Executor; use parity_runtime::Executor;
use parking_lot::Mutex; use parking_lot::Mutex;
use sync::{ManageNetwork, SyncProvider};
#[derive(Debug, PartialEq, Clone, Eq, Hash)] #[derive(Debug, PartialEq, Clone, Eq, Hash)]
pub enum Api { pub enum Api {
@ -51,6 +58,8 @@ pub enum Api {
Parity, Parity,
/// Traces (Safe) /// Traces (Safe)
Traces, Traces,
/// Rpc (Safe)
Rpc,
/// Parity PubSub - Generic Publish-Subscriber (Safety depends on other APIs exposed). /// Parity PubSub - Generic Publish-Subscriber (Safety depends on other APIs exposed).
ParityPubSub, ParityPubSub,
/// Parity Accounts extensions (UNSAFE: Passwords, Side Effects (new account)) /// Parity Accounts extensions (UNSAFE: Passwords, Side Effects (new account))
@ -80,6 +89,7 @@ impl FromStr for Api {
"parity_set" => Ok(ParitySet), "parity_set" => Ok(ParitySet),
"personal" => Ok(Personal), "personal" => Ok(Personal),
"pubsub" => Ok(EthPubSub), "pubsub" => Ok(EthPubSub),
"rpc" => Ok(Rpc),
"secretstore" => Ok(SecretStore), "secretstore" => Ok(SecretStore),
"signer" => Ok(Signer), "signer" => Ok(Signer),
"traces" => Ok(Traces), "traces" => Ok(Traces),
@ -146,6 +156,30 @@ impl FromStr for ApiSet {
} }
} }
fn to_modules(apis: &HashSet<Api>) -> BTreeMap<String, String> {
let mut modules = BTreeMap::new();
for api in apis {
let (name, version) = match *api {
Api::Debug => ("debug", "1.0"),
Api::Eth => ("eth", "1.0"),
Api::EthPubSub => ("pubsub", "1.0"),
Api::Net => ("net", "1.0"),
Api::Parity => ("parity", "1.0"),
Api::ParityAccounts => ("parity_accounts", "1.0"),
Api::ParityPubSub => ("parity_pubsub", "1.0"),
Api::ParitySet => ("parity_set", "1.0"),
Api::Personal => ("personal", "1.0"),
Api::Rpc => ("rpc", "1.0"),
Api::SecretStore => ("secretstore", "1.0"),
Api::Signer => ("signer", "1.0"),
Api::Traces => ("traces", "1.0"),
Api::Web3 => ("web3", "1.0"),
};
modules.insert(name.into(), version.into());
}
modules
}
macro_rules! add_signing_methods { macro_rules! add_signing_methods {
($namespace:ident, $handler:expr, $deps:expr, $dispatch:expr) => {{ ($namespace:ident, $handler:expr, $deps:expr, $dispatch:expr) => {{
let deps = &$deps; let deps = &$deps;
@ -376,6 +410,10 @@ impl FullDependencies {
); );
} }
Api::Traces => handler.extend_with(TracesClient::new(&self.client).to_delegate()), Api::Traces => handler.extend_with(TracesClient::new(&self.client).to_delegate()),
Api::Rpc => {
let modules = to_modules(&apis);
handler.extend_with(RpcClient::new(modules).to_delegate());
}
Api::SecretStore => { Api::SecretStore => {
#[cfg(feature = "accounts")] #[cfg(feature = "accounts")]
handler.extend_with(SecretStoreClient::new(&self.accounts).to_delegate()); handler.extend_with(SecretStoreClient::new(&self.accounts).to_delegate());
@ -409,11 +447,17 @@ impl ApiSet {
} }
pub fn list_apis(&self) -> HashSet<Api> { pub fn list_apis(&self) -> HashSet<Api> {
let mut public_list: HashSet<Api> = let mut public_list: HashSet<Api> = [
[Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity] Api::Web3,
.iter() Api::Net,
.cloned() Api::Eth,
.collect(); Api::EthPubSub,
Api::Parity,
Api::Rpc,
]
.iter()
.cloned()
.collect();
match *self { match *self {
ApiSet::List(ref apis) => apis.clone(), ApiSet::List(ref apis) => apis.clone(),
@ -470,6 +514,7 @@ mod test {
assert_eq!(Api::ParityAccounts, "parity_accounts".parse().unwrap()); assert_eq!(Api::ParityAccounts, "parity_accounts".parse().unwrap());
assert_eq!(Api::ParitySet, "parity_set".parse().unwrap()); assert_eq!(Api::ParitySet, "parity_set".parse().unwrap());
assert_eq!(Api::Traces, "traces".parse().unwrap()); assert_eq!(Api::Traces, "traces".parse().unwrap());
assert_eq!(Api::Rpc, "rpc".parse().unwrap());
assert_eq!(Api::SecretStore, "secretstore".parse().unwrap()); assert_eq!(Api::SecretStore, "secretstore".parse().unwrap());
assert!("rp".parse::<Api>().is_err()); assert!("rp".parse::<Api>().is_err());
} }
@ -498,6 +543,7 @@ mod test {
Api::Parity, Api::Parity,
Api::ParityPubSub, Api::ParityPubSub,
Api::Traces, Api::Traces,
Api::Rpc,
] ]
.into_iter() .into_iter()
.collect(); .collect();
@ -515,6 +561,7 @@ mod test {
Api::Parity, Api::Parity,
Api::ParityPubSub, Api::ParityPubSub,
Api::Traces, Api::Traces,
Api::Rpc,
// semi-safe // semi-safe
Api::ParityAccounts, Api::ParityAccounts,
] ]
@ -536,6 +583,7 @@ mod test {
Api::Parity, Api::Parity,
Api::ParityPubSub, Api::ParityPubSub,
Api::Traces, Api::Traces,
Api::Rpc,
Api::SecretStore, Api::SecretStore,
Api::ParityAccounts, Api::ParityAccounts,
Api::ParitySet, Api::ParitySet,
@ -562,6 +610,7 @@ mod test {
Api::Parity, Api::Parity,
Api::ParityPubSub, Api::ParityPubSub,
Api::Traces, Api::Traces,
Api::Rpc,
Api::SecretStore, Api::SecretStore,
Api::ParityAccounts, Api::ParityAccounts,
Api::ParitySet, Api::ParitySet,
@ -587,6 +636,7 @@ mod test {
Api::Parity, Api::Parity,
Api::ParityPubSub, Api::ParityPubSub,
Api::Traces, Api::Traces,
Api::Rpc,
] ]
.into_iter() .into_iter()
.collect() .collect()

View File

@ -16,15 +16,30 @@
use std::{ use std::{
any::Any, any::Any,
str::FromStr,
sync::{atomic, Arc, Weak}, sync::{atomic, Arc, Weak},
thread, thread,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use account_utils; use crate::{
account_utils,
cache::CacheConfig,
db,
helpers::{execute_upgrades, passwords_from_files, to_client_config},
informant::{FullNodeInformantData, Informant},
metrics::{start_prometheus_metrics, MetricsConfiguration},
miner::{external::ExternalMiner, work_notify::WorkPoster},
modules,
params::{
fatdb_switch_to_bool, mode_switch_to_bool, tracing_switch_to_bool, AccountsConfig,
GasPricerConfig, MinerExtras, Pruning, SpecType, Switch,
},
rpc, rpc_apis, secretstore, signer,
sync::{self, SyncConfig},
user_defaults::UserDefaults,
};
use ansi_term::Colour; use ansi_term::Colour;
use cache::CacheConfig;
use db;
use dir::{DatabaseDirectories, Directories}; use dir::{DatabaseDirectories, Directories};
use ethcore::{ use ethcore::{
client::{BlockChainClient, BlockInfo, Client, DatabaseCompactionProfile, Mode, VMType}, client::{BlockChainClient, BlockInfo, Client, DatabaseCompactionProfile, Mode, VMType},
@ -35,36 +50,21 @@ use ethcore::{
use ethcore_logger::{Config as LogConfig, RotatingLogger}; use ethcore_logger::{Config as LogConfig, RotatingLogger};
use ethcore_service::ClientService; use ethcore_service::ClientService;
use ethereum_types::{H256, U64}; use ethereum_types::{H256, U64};
use helpers::{execute_upgrades, passwords_from_files, to_client_config};
use informant::{FullNodeInformantData, Informant};
use journaldb::Algorithm; use journaldb::Algorithm;
use jsonrpc_core; use jsonrpc_core;
use metrics::{start_prometheus_metrics, MetricsConfiguration};
use miner::{external::ExternalMiner, work_notify::WorkPoster};
use modules;
use node_filter::NodeFilter; use node_filter::NodeFilter;
use params::{
fatdb_switch_to_bool, mode_switch_to_bool, tracing_switch_to_bool, AccountsConfig,
GasPricerConfig, MinerExtras, Pruning, SpecType, Switch,
};
use parity_rpc::{ use parity_rpc::{
informant, is_major_importing, FutureOutput, FutureResponse, FutureResult, Metadata, informant, is_major_importing, FutureOutput, FutureResponse, FutureResult, Metadata,
NetworkSettings, Origin, PubSubSession, NetworkSettings, Origin, PubSubSession,
}; };
use parity_runtime::Runtime; use parity_runtime::Runtime;
use parity_version::version; use parity_version::version;
use rpc;
use rpc_apis;
use secretstore;
use signer;
use sync::{self, SyncConfig};
use user_defaults::UserDefaults;
// how often to take periodic snapshots. // How often we attempt to take a snapshot: only snapshot on blocknumbers that are multiples of this.
const SNAPSHOT_PERIOD: u64 = 5000; const SNAPSHOT_PERIOD: u64 = 20000;
// how many blocks to wait before starting a periodic snapshot. // Start snapshoting from `tip`-`history, with this we want to bypass reorgs. Should be smaller than prunning history.
const SNAPSHOT_HISTORY: u64 = 100; const SNAPSHOT_HISTORY: u64 = 50;
// Full client number of DNS threads // Full client number of DNS threads
const FETCH_FULL_NUM_DNS_THREADS: usize = 4; const FETCH_FULL_NUM_DNS_THREADS: usize = 4;
@ -119,8 +119,8 @@ struct FullNodeInfo {
miner: Option<Arc<Miner>>, // TODO: only TXQ needed, just use that after decoupling. miner: Option<Arc<Miner>>, // TODO: only TXQ needed, just use that after decoupling.
} }
impl ::local_store::NodeInfo for FullNodeInfo { impl crate::local_store::NodeInfo for FullNodeInfo {
fn pending_transactions(&self) -> Vec<::types::transaction::PendingTransaction> { fn pending_transactions(&self) -> Vec<crate::types::transaction::PendingTransaction> {
let miner = match self.miner.as_ref() { let miner = match self.miner.as_ref() {
Some(m) => m, Some(m) => m,
None => return Vec::new(), None => return Vec::new(),
@ -130,7 +130,7 @@ impl ::local_store::NodeInfo for FullNodeInfo {
.local_transactions() .local_transactions()
.values() .values()
.filter_map(|status| match *status { .filter_map(|status| match *status {
::miner::pool::local_transactions::Status::Pending(ref tx) => { crate::miner::pool::local_transactions::Status::Pending(ref tx) => {
Some(tx.pending().clone()) Some(tx.pending().clone())
} }
_ => None, _ => None,
@ -254,6 +254,7 @@ pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<RunningClient
_ => sync::WarpSync::Disabled, _ => sync::WarpSync::Disabled,
}; };
sync_config.download_old_blocks = cmd.download_old_blocks; sync_config.download_old_blocks = cmd.download_old_blocks;
sync_config.eip1559_transition = spec.params().eip1559_transition;
let passwords = passwords_from_files(&cmd.acc_conf.password_files)?; let passwords = passwords_from_files(&cmd.acc_conf.password_files)?;
@ -365,8 +366,18 @@ pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<RunningClient
// take handle to client // take handle to client
let client = service.client(); let client = service.client();
// Update miners block gas limit // Update miners block gas limit and base_fee
miner.update_transaction_queue_limits(*client.best_block_header().gas_limit()); let base_fee = client
.engine()
.calculate_base_fee(&client.best_block_header());
let allow_non_eoa_sender = client
.engine()
.allow_non_eoa_sender(client.best_block_header().number() + 1);
miner.update_transaction_queue_limits(
*client.best_block_header().gas_limit(),
base_fee,
allow_non_eoa_sender,
);
let connection_filter = connection_filter_address.map(|a| { let connection_filter = connection_filter_address.map(|a| {
Arc::new(NodeFilter::new( Arc::new(NodeFilter::new(
@ -386,7 +397,7 @@ pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<RunningClient
}, },
}; };
let store = ::local_store::create( let store = crate::local_store::create(
db.key_value().clone(), db.key_value().clone(),
::ethcore_db::COL_NODE_INFO, ::ethcore_db::COL_NODE_INFO,
node_info, node_info,
@ -450,9 +461,17 @@ pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<RunningClient
let is_ready = Arc::new(atomic::AtomicBool::new(true)); let is_ready = Arc::new(atomic::AtomicBool::new(true));
miner.add_transactions_listener(Box::new(move |_hashes| { miner.add_transactions_listener(Box::new(move |_hashes| {
// we want to have only one PendingTransactions task in the queue. // we want to have only one PendingTransactions task in the queue.
if is_ready.compare_and_swap(true, false, atomic::Ordering::SeqCst) { if is_ready
.compare_exchange(
true,
false,
atomic::Ordering::SeqCst,
atomic::Ordering::SeqCst,
)
.is_ok()
{
let task = let task =
::sync::PriorityTask::PropagateTransactions(Instant::now(), is_ready.clone()); crate::sync::PriorityTask::PropagateTransactions(Instant::now(), is_ready.clone());
// we ignore error cause it means that we are closing // we ignore error cause it means that we are closing
let _ = tx.lock().send(task); let _ = tx.lock().send(task);
} }
@ -598,7 +617,10 @@ pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<RunningClient
fn verification_bad_blocks(spec: &SpecType) -> Vec<H256> { fn verification_bad_blocks(spec: &SpecType) -> Vec<H256> {
match *spec { match *spec {
SpecType::Ropsten => { SpecType::Ropsten => {
vec!["1eac3d16c642411f13c287e29144c6f58fda859407c8f24c38deb168e1040714".into()] vec![
H256::from_str("1eac3d16c642411f13c287e29144c6f58fda859407c8f24c38deb168e1040714")
.expect("Valid hex string"),
]
} }
_ => vec![], _ => vec![],
} }

View File

@ -14,14 +14,14 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>. // along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use account_utils::AccountProvider; use crate::{account_utils::AccountProvider, sync::SyncProvider};
use crypto::publickey::{Public, Secret};
use dir::{default_data_path, helpers::replace_home}; use dir::{default_data_path, helpers::replace_home};
use ethcore::{client::Client, miner::Miner}; use ethcore::{client::Client, miner::Miner};
use ethereum_types::Address; use ethereum_types::Address;
use ethkey::{Password, Public, Secret}; use ethkey::Password;
use parity_runtime::Executor; use parity_runtime::Executor;
use std::{collections::BTreeMap, sync::Arc}; use std::{collections::BTreeMap, sync::Arc};
use sync::SyncProvider;
/// This node secret key. /// This node secret key.
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]

View File

@ -19,12 +19,10 @@ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use crate::{path::restrict_permissions_owner, rpc, rpc_apis};
use ansi_term::Colour::White; use ansi_term::Colour::White;
use ethcore_logger::Config as LogConfig; use ethcore_logger::Config as LogConfig;
use parity_rpc; use parity_rpc;
use path::restrict_permissions_owner;
use rpc;
use rpc_apis;
pub const CODES_FILENAME: &'static str = "authcodes"; pub const CODES_FILENAME: &'static str = "authcodes";

View File

@ -22,6 +22,7 @@ use std::{
time::Duration, time::Duration,
}; };
use crate::{hash::keccak, types::ids::BlockId};
use ethcore::{ use ethcore::{
client::{DatabaseCompactionProfile, Mode, VMType}, client::{DatabaseCompactionProfile, Mode, VMType},
miner::Miner, miner::Miner,
@ -32,15 +33,15 @@ use ethcore::{
}, },
}; };
use ethcore_service::ClientService; use ethcore_service::ClientService;
use hash::keccak;
use types::ids::BlockId;
use cache::CacheConfig; use crate::{
use db; cache::CacheConfig,
db,
helpers::{execute_upgrades, to_client_config},
params::{fatdb_switch_to_bool, tracing_switch_to_bool, Pruning, SpecType, Switch},
user_defaults::UserDefaults,
};
use dir::Directories; use dir::Directories;
use helpers::{execute_upgrades, to_client_config};
use params::{fatdb_switch_to_bool, tracing_switch_to_bool, Pruning, SpecType, Switch};
use user_defaults::UserDefaults;
/// Kinds of snapshot commands. /// Kinds of snapshot commands.
#[derive(Debug, PartialEq, Clone, Copy)] #[derive(Debug, PartialEq, Clone, Copy)]
@ -303,7 +304,7 @@ impl SnapshotCommand {
let cur_size = p.size(); let cur_size = p.size();
if cur_size != last_size { if cur_size != last_size {
last_size = cur_size; last_size = cur_size;
let bytes = ::informant::format_bytes(cur_size as usize); let bytes = crate::informant::format_bytes(cur_size as usize);
info!( info!(
"Snapshot: {} accounts {} blocks {}", "Snapshot: {} accounts {} blocks {}",
p.accounts(), p.accounts(),

View File

@ -39,7 +39,7 @@ struct StratumControlService {
impl ControlService for StratumControlService { impl ControlService for StratumControlService {
fn shutdown(&self) -> bool { fn shutdown(&self) -> bool {
trace!(target: "hypervisor", "Received shutdown from control service"); trace!(target: "hypervisor", "Received shutdown from control service");
self.stop.store(true, ::std::sync::atomic::Ordering::Relaxed); self.stop.store(true, ::std::sync::atomic::Ordering::SeqCst);
true true
} }
} }

View File

@ -12,11 +12,12 @@ common-types = { path = "../ethcore/types" }
ethkey = { path = "ethkey" } ethkey = { path = "ethkey" }
ethstore = { path = "ethstore" } ethstore = { path = "ethstore" }
log = "0.4" log = "0.4"
parking_lot = "0.7" parity-crypto = { version = "0.6.2", features = [ "publickey" ] }
parking_lot = "0.11.1"
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
serde_json = "1.0" serde_json = "1.0"
[dev-dependencies] [dev-dependencies]
ethereum-types = "0.4" ethereum-types = "0.9.2"
tempdir = "0.3" tempdir = "0.3"

View File

@ -6,15 +6,15 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies] [dependencies]
edit-distance = "2.0" edit-distance = "2.0"
parity-crypto = "0.3.0" parity-crypto = { version = "0.6.2", features = ["publickey"] }
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1", rev = "ccc06e7480148b723eb44ac56cf4d20eec380b6f" } eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1", rev = "9791e79f21a5309dcb6e0bd254b1ef88fca2f1f4" }
ethereum-types = "0.4" ethereum-types = "0.9.2"
lazy_static = "1.0" lazy_static = "1.0"
log = "0.4" log = "0.4"
memzero = { path = "../../../crates/util/memzero" } memzero = { path = "../../../crates/util/memzero" }
parity-wordlist = "1.3" parity-wordlist = "1.3"
quick-error = "1.2.2" quick-error = "1.2.2"
rand = "0.4" rand = "0.7.3"
rustc-hex = "1.0" rustc-hex = "1.0"
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"

View File

@ -14,8 +14,10 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>. // along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::{Generator, KeyPair, Secret}; use parity_crypto::{
use keccak::Keccak256; publickey::{KeyPair, Secret},
Keccak256,
};
use parity_wordlist; use parity_wordlist;
/// Simple brainwallet. /// Simple brainwallet.
@ -29,12 +31,8 @@ impl Brain {
pub fn validate_phrase(phrase: &str, expected_words: usize) -> Result<(), ::WordlistError> { pub fn validate_phrase(phrase: &str, expected_words: usize) -> Result<(), ::WordlistError> {
parity_wordlist::validate_phrase(phrase, expected_words) parity_wordlist::validate_phrase(phrase, expected_words)
} }
}
impl Generator for Brain { pub fn generate(&mut self) -> KeyPair {
type Error = ::Void;
fn generate(&mut self) -> Result<KeyPair, Self::Error> {
let seed = self.0.clone(); let seed = self.0.clone();
let mut secret = seed.into_bytes().keccak256(); let mut secret = seed.into_bytes().keccak256();
@ -45,12 +43,10 @@ impl Generator for Brain {
match i > 16384 { match i > 16384 {
false => i += 1, false => i += 1,
true => { true => {
if let Ok(pair) = if let Ok(pair) = Secret::import_key(&secret).and_then(KeyPair::from_secret) {
Secret::from_unsafe_slice(&secret).and_then(KeyPair::from_secret)
{
if pair.address()[0] == 0 { if pair.address()[0] == 0 {
trace!("Testing: {}, got: {:?}", self.0, pair.address()); trace!("Testing: {}, got: {:?}", self.0, pair.address());
return Ok(pair); return pair;
} }
} }
} }
@ -62,13 +58,12 @@ impl Generator for Brain {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use Brain; use Brain;
use Generator;
#[test] #[test]
fn test_brain() { fn test_brain() {
let words = "this is sparta!".to_owned(); let words = "this is sparta!".to_owned();
let first_keypair = Brain::new(words.clone()).generate().unwrap(); let first_keypair = Brain::new(words.clone()).generate();
let second_keypair = Brain::new(words.clone()).generate().unwrap(); let second_keypair = Brain::new(words.clone()).generate();
assert_eq!(first_keypair.secret(), second_keypair.secret()); assert_eq!(first_keypair.secret(), second_keypair.secret());
} }
} }

View File

@ -14,7 +14,8 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>. // along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::{Brain, Error, Generator, KeyPair}; use super::Brain;
use parity_crypto::publickey::{Error, KeyPair};
use parity_wordlist as wordlist; use parity_wordlist as wordlist;
/// Tries to find brain-seed keypair with address starting with given prefix. /// Tries to find brain-seed keypair with address starting with given prefix.
@ -38,16 +39,12 @@ impl BrainPrefix {
pub fn phrase(&self) -> &str { pub fn phrase(&self) -> &str {
&self.last_phrase &self.last_phrase
} }
}
impl Generator for BrainPrefix { pub fn generate(&mut self) -> Result<KeyPair, Error> {
type Error = Error;
fn generate(&mut self) -> Result<KeyPair, Error> {
for _ in 0..self.iterations { for _ in 0..self.iterations {
let phrase = wordlist::random_phrase(self.no_of_words); let phrase = wordlist::random_phrase(self.no_of_words);
let keypair = Brain::new(phrase.clone()).generate().unwrap(); let keypair = Brain::new(phrase.clone()).generate();
if keypair.address().starts_with(&self.prefix) { if keypair.address().as_ref().starts_with(&self.prefix) {
self.last_phrase = phrase; self.last_phrase = phrase;
return Ok(keypair); return Ok(keypair);
} }
@ -60,7 +57,6 @@ impl Generator for BrainPrefix {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use BrainPrefix; use BrainPrefix;
use Generator;
#[test] #[test]
fn prefix_generator() { fn prefix_generator() {
@ -68,6 +64,6 @@ mod tests {
let keypair = BrainPrefix::new(prefix.clone(), usize::max_value(), 12) let keypair = BrainPrefix::new(prefix.clone(), usize::max_value(), 12)
.generate() .generate()
.unwrap(); .unwrap();
assert!(keypair.address().starts_with(&prefix)); assert!(keypair.address().as_bytes().starts_with(&prefix));
} }
} }

View File

@ -17,9 +17,10 @@
use std::collections::HashSet; use std::collections::HashSet;
use edit_distance::edit_distance; use edit_distance::edit_distance;
use parity_crypto::publickey::Address;
use parity_wordlist; use parity_wordlist;
use super::{Address, Brain, Generator}; use super::Brain;
/// Tries to find a phrase for address, given the number /// Tries to find a phrase for address, given the number
/// of expected words and a partial phrase. /// of expected words and a partial phrase.
@ -32,9 +33,7 @@ pub fn brain_recover(
) -> Option<String> { ) -> Option<String> {
let it = PhrasesIterator::from_known_phrase(known_phrase, expected_words); let it = PhrasesIterator::from_known_phrase(known_phrase, expected_words);
for phrase in it { for phrase in it {
let keypair = Brain::new(phrase.clone()) let keypair = Brain::new(phrase.clone()).generate();
.generate()
.expect("Brain wallets are infallible; qed");
trace!("Testing: {}, got: {:?}", phrase, keypair.address()); trace!("Testing: {}, got: {:?}", phrase, keypair.address());
if &keypair.address() == address { if &keypair.address() == address {
return Some(phrase); return Some(phrase);

View File

@ -1,202 +0,0 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
#![allow(deprecated)]
use parity_crypto::error::SymmError;
use secp256k1;
use std::io;
quick_error! {
#[derive(Debug)]
pub enum Error {
Secp(e: secp256k1::Error) {
display("secp256k1 error: {}", e)
cause(e)
from()
}
Io(e: io::Error) {
display("i/o error: {}", e)
cause(e)
from()
}
InvalidMessage {
display("invalid message")
}
Symm(e: SymmError) {
cause(e)
from()
}
}
}
/// ECDH functions
pub mod ecdh {
use super::Error;
use secp256k1::{self, ecdh, key};
use Public;
use Secret;
use SECP256K1;
/// Agree on a shared secret
pub fn agree(secret: &Secret, public: &Public) -> Result<Secret, Error> {
let context = &SECP256K1;
let pdata = {
let mut temp = [4u8; 65];
(&mut temp[1..65]).copy_from_slice(&public[0..64]);
temp
};
let publ = key::PublicKey::from_slice(context, &pdata)?;
let sec = key::SecretKey::from_slice(context, &secret)?;
let shared = ecdh::SharedSecret::new_raw(context, &publ, &sec);
Secret::from_unsafe_slice(&shared[0..32])
.map_err(|_| Error::Secp(secp256k1::Error::InvalidSecretKey))
}
}
/// ECIES function
pub mod ecies {
use super::{ecdh, Error};
use ethereum_types::H128;
use parity_crypto::{aes, digest, hmac, is_equal};
use Generator;
use Public;
use Random;
use Secret;
/// Encrypt a message with a public key, writing an HMAC covering both
/// the plaintext and authenticated data.
///
/// Authenticated data may be empty.
pub fn encrypt(public: &Public, auth_data: &[u8], plain: &[u8]) -> Result<Vec<u8>, Error> {
let r = Random.generate()?;
let z = ecdh::agree(r.secret(), public)?;
let mut key = [0u8; 32];
kdf(&z, &[0u8; 0], &mut key);
let ekey = &key[0..16];
let mkey = hmac::SigKey::sha256(&digest::sha256(&key[16..32]));
let mut msg = vec![0u8; 1 + 64 + 16 + plain.len() + 32];
msg[0] = 0x04u8;
{
let msgd = &mut msg[1..];
msgd[0..64].copy_from_slice(r.public());
let iv = H128::random();
msgd[64..80].copy_from_slice(&iv);
{
let cipher = &mut msgd[(64 + 16)..(64 + 16 + plain.len())];
aes::encrypt_128_ctr(ekey, &iv, plain, cipher)?;
}
let mut hmac = hmac::Signer::with(&mkey);
{
let cipher_iv = &msgd[64..(64 + 16 + plain.len())];
hmac.update(cipher_iv);
}
hmac.update(auth_data);
let sig = hmac.sign();
msgd[(64 + 16 + plain.len())..].copy_from_slice(&sig);
}
Ok(msg)
}
/// Decrypt a message with a secret key, checking HMAC for ciphertext
/// and authenticated data validity.
pub fn decrypt(secret: &Secret, auth_data: &[u8], encrypted: &[u8]) -> Result<Vec<u8>, Error> {
let meta_len = 1 + 64 + 16 + 32;
if encrypted.len() < meta_len || encrypted[0] < 2 || encrypted[0] > 4 {
return Err(Error::InvalidMessage); //invalid message: publickey
}
let e = &encrypted[1..];
let p = Public::from_slice(&e[0..64]);
let z = ecdh::agree(secret, &p)?;
let mut key = [0u8; 32];
kdf(&z, &[0u8; 0], &mut key);
let ekey = &key[0..16];
let mkey = hmac::SigKey::sha256(&digest::sha256(&key[16..32]));
let clen = encrypted.len() - meta_len;
let cipher_with_iv = &e[64..(64 + 16 + clen)];
let cipher_iv = &cipher_with_iv[0..16];
let cipher_no_iv = &cipher_with_iv[16..];
let msg_mac = &e[(64 + 16 + clen)..];
// Verify tag
let mut hmac = hmac::Signer::with(&mkey);
hmac.update(cipher_with_iv);
hmac.update(auth_data);
let mac = hmac.sign();
if !is_equal(&mac.as_ref()[..], msg_mac) {
return Err(Error::InvalidMessage);
}
let mut msg = vec![0u8; clen];
aes::decrypt_128_ctr(ekey, cipher_iv, cipher_no_iv, &mut msg[..])?;
Ok(msg)
}
fn kdf(secret: &Secret, s1: &[u8], dest: &mut [u8]) {
// SEC/ISO/Shoup specify counter size SHOULD be equivalent
// to size of hash output, however, it also notes that
// the 4 bytes is okay. NIST specifies 4 bytes.
let mut ctr = 1u32;
let mut written = 0usize;
while written < dest.len() {
let mut hasher = digest::Hasher::sha256();
let ctrs = [
(ctr >> 24) as u8,
(ctr >> 16) as u8,
(ctr >> 8) as u8,
ctr as u8,
];
hasher.update(&ctrs);
hasher.update(secret);
hasher.update(s1);
let d = hasher.finish();
&mut dest[written..(written + 32)].copy_from_slice(&d);
written += 32;
ctr += 1;
}
}
}
#[cfg(test)]
mod tests {
use super::ecies;
use Generator;
use Random;
#[test]
fn ecies_shared() {
let kp = Random.generate().unwrap();
let message = b"So many books, so little time";
let shared = b"shared";
let wrong_shared = b"incorrect";
let encrypted = ecies::encrypt(kp.public(), shared, message).unwrap();
assert!(encrypted[..] != message[..]);
assert_eq!(encrypted[0], 0x04);
assert!(ecies::decrypt(kp.secret(), wrong_shared, &encrypted).is_err());
let decrypted = ecies::decrypt(kp.secret(), shared, &encrypted).unwrap();
assert_eq!(decrypted[..message.len()], message[..]);
}
}

View File

@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>. // along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use crypto::Error as CryptoError;
use std::{error, fmt}; use std::{error, fmt};
#[derive(Debug)] #[derive(Debug)]
@ -53,7 +54,7 @@ impl fmt::Display for Error {
impl error::Error for Error { impl error::Error for Error {
fn description(&self) -> &str { fn description(&self) -> &str {
"Crypto error" format!("{:?}", &self)
} }
} }
@ -63,6 +64,12 @@ impl Into<String> for Error {
} }
} }
impl From<CryptoError> for Error {
fn from(e: CryptoError) -> Error {
Error::Custom(e.to_string())
}
}
impl From<::secp256k1::Error> for Error { impl From<::secp256k1::Error> for Error {
fn from(e: ::secp256k1::Error) -> Error { fn from(e: ::secp256k1::Error) -> Error {
match e { match e {

View File

@ -1,589 +0,0 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
//! Extended keys
pub use self::derivation::Error as DerivationError;
use ethereum_types::H256;
use secret::Secret;
use Public;
/// Represents label that can be stored as a part of key derivation
pub trait Label {
/// Length of the data that label occupies
fn len() -> usize;
/// Store label data to the key derivation sequence
/// Must not use more than `len()` bytes from slice
fn store(&self, target: &mut [u8]);
}
impl Label for u32 {
fn len() -> usize {
4
}
fn store(&self, target: &mut [u8]) {
let bytes = self.to_be_bytes();
target[0..4].copy_from_slice(&bytes);
}
}
/// Key derivation over generic label `T`
pub enum Derivation<T: Label> {
/// Soft key derivation (allow proof of parent)
Soft(T),
/// Hard key derivation (does not allow proof of parent)
Hard(T),
}
impl From<u32> for Derivation<u32> {
fn from(index: u32) -> Self {
if index < (2 << 30) {
Derivation::Soft(index)
} else {
Derivation::Hard(index)
}
}
}
impl Label for H256 {
fn len() -> usize {
32
}
fn store(&self, target: &mut [u8]) {
self.copy_to(&mut target[0..32]);
}
}
/// Extended secret key, allows deterministic derivation of subsequent keys.
pub struct ExtendedSecret {
secret: Secret,
chain_code: H256,
}
impl ExtendedSecret {
/// New extended key from given secret and chain code.
pub fn with_code(secret: Secret, chain_code: H256) -> ExtendedSecret {
ExtendedSecret {
secret: secret,
chain_code: chain_code,
}
}
/// New extended key from given secret with the random chain code.
pub fn new_random(secret: Secret) -> ExtendedSecret {
ExtendedSecret::with_code(secret, H256::random())
}
/// New extended key from given secret.
/// Chain code will be derived from the secret itself (in a deterministic way).
pub fn new(secret: Secret) -> ExtendedSecret {
let chain_code = derivation::chain_code(*secret);
ExtendedSecret::with_code(secret, chain_code)
}
/// Derive new private key
pub fn derive<T>(&self, index: Derivation<T>) -> ExtendedSecret
where
T: Label,
{
let (derived_key, next_chain_code) =
derivation::private(*self.secret, self.chain_code, index);
let derived_secret = Secret::from(derived_key.0);
ExtendedSecret::with_code(derived_secret, next_chain_code)
}
/// Private key component of the extended key.
pub fn as_raw(&self) -> &Secret {
&self.secret
}
}
/// Extended public key, allows deterministic derivation of subsequent keys.
pub struct ExtendedPublic {
public: Public,
chain_code: H256,
}
impl ExtendedPublic {
/// New extended public key from known parent and chain code
pub fn new(public: Public, chain_code: H256) -> Self {
ExtendedPublic {
public: public,
chain_code: chain_code,
}
}
/// Create new extended public key from known secret
pub fn from_secret(secret: &ExtendedSecret) -> Result<Self, DerivationError> {
Ok(ExtendedPublic::new(
derivation::point(**secret.as_raw())?,
secret.chain_code.clone(),
))
}
/// Derive new public key
/// Operation is defined only for index belongs [0..2^31)
pub fn derive<T>(&self, index: Derivation<T>) -> Result<Self, DerivationError>
where
T: Label,
{
let (derived_key, next_chain_code) =
derivation::public(self.public, self.chain_code, index)?;
Ok(ExtendedPublic::new(derived_key, next_chain_code))
}
pub fn public(&self) -> &Public {
&self.public
}
}
pub struct ExtendedKeyPair {
secret: ExtendedSecret,
public: ExtendedPublic,
}
impl ExtendedKeyPair {
pub fn new(secret: Secret) -> Self {
let extended_secret = ExtendedSecret::new(secret);
let extended_public = ExtendedPublic::from_secret(&extended_secret)
.expect("Valid `Secret` always produces valid public; qed");
ExtendedKeyPair {
secret: extended_secret,
public: extended_public,
}
}
pub fn with_code(secret: Secret, public: Public, chain_code: H256) -> Self {
ExtendedKeyPair {
secret: ExtendedSecret::with_code(secret, chain_code.clone()),
public: ExtendedPublic::new(public, chain_code),
}
}
pub fn with_secret(secret: Secret, chain_code: H256) -> Self {
let extended_secret = ExtendedSecret::with_code(secret, chain_code);
let extended_public = ExtendedPublic::from_secret(&extended_secret)
.expect("Valid `Secret` always produces valid public; qed");
ExtendedKeyPair {
secret: extended_secret,
public: extended_public,
}
}
pub fn with_seed(seed: &[u8]) -> Result<ExtendedKeyPair, DerivationError> {
let (master_key, chain_code) = derivation::seed_pair(seed);
Ok(ExtendedKeyPair::with_secret(
Secret::from_unsafe_slice(&*master_key).map_err(|_| DerivationError::InvalidSeed)?,
chain_code,
))
}
pub fn secret(&self) -> &ExtendedSecret {
&self.secret
}
pub fn public(&self) -> &ExtendedPublic {
&self.public
}
pub fn derive<T>(&self, index: Derivation<T>) -> Result<Self, DerivationError>
where
T: Label,
{
let derived = self.secret.derive(index);
Ok(ExtendedKeyPair {
public: ExtendedPublic::from_secret(&derived)?,
secret: derived,
})
}
}
// Derivation functions for private and public keys
// Work is based on BIP0032
// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
mod derivation {
use super::{Derivation, Label};
use ethereum_types::{H256, H512, U256, U512};
use keccak;
use math::curve_order;
use parity_crypto::hmac;
use secp256k1::key::{PublicKey, SecretKey};
use SECP256K1;
#[derive(Debug)]
pub enum Error {
InvalidHardenedUse,
InvalidPoint,
MissingIndex,
InvalidSeed,
}
// Deterministic derivation of the key using secp256k1 elliptic curve.
// Derivation can be either hardened or not.
// For hardened derivation, pass u32 index at least 2^31 or custom Derivation::Hard(T) enum
//
// Can panic if passed `private_key` is not a valid secp256k1 private key
// (outside of (0..curve_order()]) field
pub fn private<T>(private_key: H256, chain_code: H256, index: Derivation<T>) -> (H256, H256)
where
T: Label,
{
match index {
Derivation::Soft(index) => private_soft(private_key, chain_code, index),
Derivation::Hard(index) => private_hard(private_key, chain_code, index),
}
}
fn hmac_pair(data: &[u8], private_key: H256, chain_code: H256) -> (H256, H256) {
let private: U256 = private_key.into();
// produces 512-bit derived hmac (I)
let skey = hmac::SigKey::sha512(&*chain_code);
let i_512 = hmac::sign(&skey, &data[..]);
// left most 256 bits are later added to original private key
let hmac_key: U256 = H256::from_slice(&i_512[0..32]).into();
// right most 256 bits are new chain code for later derivations
let next_chain_code = H256::from(&i_512[32..64]);
let child_key = private_add(hmac_key, private).into();
(child_key, next_chain_code)
}
// Can panic if passed `private_key` is not a valid secp256k1 private key
// (outside of (0..curve_order()]) field
fn private_soft<T>(private_key: H256, chain_code: H256, index: T) -> (H256, H256)
where
T: Label,
{
let mut data = vec![0u8; 33 + T::len()];
let sec_private = SecretKey::from_slice(&SECP256K1, &*private_key)
.expect("Caller should provide valid private key");
let sec_public = PublicKey::from_secret_key(&SECP256K1, &sec_private)
.expect("Caller should provide valid private key");
let public_serialized = sec_public.serialize_vec(&SECP256K1, true);
// curve point (compressed public key) -- index
// 0.33 -- 33..end
data[0..33].copy_from_slice(&public_serialized);
index.store(&mut data[33..]);
hmac_pair(&data, private_key, chain_code)
}
// Deterministic derivation of the key using secp256k1 elliptic curve
// This is hardened derivation and does not allow to associate
// corresponding public keys of the original and derived private keys
fn private_hard<T>(private_key: H256, chain_code: H256, index: T) -> (H256, H256)
where
T: Label,
{
let mut data: Vec<u8> = vec![0u8; 33 + T::len()];
let private: U256 = private_key.into();
// 0x00 (padding) -- private_key -- index
// 0 -- 1..33 -- 33..end
private.to_big_endian(&mut data[1..33]);
index.store(&mut data[33..(33 + T::len())]);
hmac_pair(&data, private_key, chain_code)
}
fn private_add(k1: U256, k2: U256) -> U256 {
let sum = U512::from(k1) + U512::from(k2);
modulo(sum, curve_order())
}
// todo: surely can be optimized
fn modulo(u1: U512, u2: U256) -> U256 {
let dv = u1 / U512::from(u2);
let md = u1 - (dv * U512::from(u2));
md.into()
}
pub fn public<T>(
public_key: H512,
chain_code: H256,
derivation: Derivation<T>,
) -> Result<(H512, H256), Error>
where
T: Label,
{
let index = match derivation {
Derivation::Soft(index) => index,
Derivation::Hard(_) => {
return Err(Error::InvalidHardenedUse);
}
};
let mut public_sec_raw = [0u8; 65];
public_sec_raw[0] = 4;
public_sec_raw[1..65].copy_from_slice(&*public_key);
let public_sec =
PublicKey::from_slice(&SECP256K1, &public_sec_raw).map_err(|_| Error::InvalidPoint)?;
let public_serialized = public_sec.serialize_vec(&SECP256K1, true);
let mut data = vec![0u8; 33 + T::len()];
// curve point (compressed public key) -- index
// 0.33 -- 33..end
data[0..33].copy_from_slice(&public_serialized);
index.store(&mut data[33..(33 + T::len())]);
// HMAC512SHA produces [derived private(256); new chain code(256)]
let skey = hmac::SigKey::sha512(&*chain_code);
let i_512 = hmac::sign(&skey, &data[..]);
let new_private = H256::from(&i_512[0..32]);
let new_chain_code = H256::from(&i_512[32..64]);
// Generated private key can (extremely rarely) be out of secp256k1 key field
if curve_order() <= new_private.clone().into() {
return Err(Error::MissingIndex);
}
let new_private_sec = SecretKey::from_slice(&SECP256K1, &*new_private)
.expect("Private key belongs to the field [0..CURVE_ORDER) (checked above); So initializing can never fail; qed");
let mut new_public = PublicKey::from_secret_key(&SECP256K1, &new_private_sec)
.expect("Valid private key produces valid public key");
// Adding two points on the elliptic curves (combining two public keys)
new_public
.add_assign(&SECP256K1, &public_sec)
.expect("Addition of two valid points produce valid point");
let serialized = new_public.serialize_vec(&SECP256K1, false);
Ok((H512::from(&serialized[1..65]), new_chain_code))
}
fn sha3(slc: &[u8]) -> H256 {
keccak::Keccak256::keccak256(slc).into()
}
pub fn chain_code(secret: H256) -> H256 {
// 10,000 rounds of sha3
let mut running_sha3 = sha3(&*secret);
for _ in 0..99999 {
running_sha3 = sha3(&*running_sha3);
}
running_sha3
}
pub fn point(secret: H256) -> Result<H512, Error> {
let sec = SecretKey::from_slice(&SECP256K1, &*secret).map_err(|_| Error::InvalidPoint)?;
let public_sec =
PublicKey::from_secret_key(&SECP256K1, &sec).map_err(|_| Error::InvalidPoint)?;
let serialized = public_sec.serialize_vec(&SECP256K1, false);
Ok(H512::from(&serialized[1..65]))
}
pub fn seed_pair(seed: &[u8]) -> (H256, H256) {
let skey = hmac::SigKey::sha512(b"Bitcoin seed");
let i_512 = hmac::sign(&skey, seed);
let master_key = H256::from_slice(&i_512[0..32]);
let chain_code = H256::from_slice(&i_512[32..64]);
(master_key, chain_code)
}
}
#[cfg(test)]
mod tests {
use super::{derivation, Derivation, ExtendedKeyPair, ExtendedPublic, ExtendedSecret};
use ethereum_types::{H128, H256};
use secret::Secret;
use std::str::FromStr;
fn master_chain_basic() -> (H256, H256) {
let seed = H128::from_str("000102030405060708090a0b0c0d0e0f")
.expect("Seed should be valid H128")
.to_vec();
derivation::seed_pair(&*seed)
}
fn test_extended<F>(f: F, test_private: H256)
where
F: Fn(ExtendedSecret) -> ExtendedSecret,
{
let (private_seed, chain_code) = master_chain_basic();
let extended_secret = ExtendedSecret::with_code(Secret::from(private_seed.0), chain_code);
let derived = f(extended_secret);
assert_eq!(**derived.as_raw(), test_private);
}
#[test]
fn smoky() {
let secret =
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
.unwrap();
let extended_secret = ExtendedSecret::with_code(secret.clone(), 0u64.into());
// hardened
assert_eq!(&**extended_secret.as_raw(), &*secret);
assert_eq!(
&**extended_secret.derive(2147483648.into()).as_raw(),
&"0927453daed47839608e414a3738dfad10aed17c459bbd9ab53f89b026c834b6".into()
);
assert_eq!(
&**extended_secret.derive(2147483649.into()).as_raw(),
&"44238b6a29c6dcbe9b401364141ba11e2198c289a5fed243a1c11af35c19dc0f".into()
);
// normal
assert_eq!(
&**extended_secret.derive(0.into()).as_raw(),
&"bf6a74e3f7b36fc4c96a1e12f31abc817f9f5904f5a8fc27713163d1f0b713f6".into()
);
assert_eq!(
&**extended_secret.derive(1.into()).as_raw(),
&"bd4fca9eb1f9c201e9448c1eecd66e302d68d4d313ce895b8c134f512205c1bc".into()
);
assert_eq!(
&**extended_secret.derive(2.into()).as_raw(),
&"86932b542d6cab4d9c65490c7ef502d89ecc0e2a5f4852157649e3251e2a3268".into()
);
let extended_public = ExtendedPublic::from_secret(&extended_secret)
.expect("Extended public should be created");
let derived_public = extended_public
.derive(0.into())
.expect("First derivation of public should succeed");
assert_eq!(&*derived_public.public(), &"f7b3244c96688f92372bfd4def26dc4151529747bab9f188a4ad34e141d47bd66522ff048bc6f19a0a4429b04318b1a8796c000265b4fa200dae5f6dda92dd94".into());
let keypair = ExtendedKeyPair::with_secret(
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
.unwrap(),
064.into(),
);
assert_eq!(
&**keypair
.derive(2147483648u32.into())
.expect("Derivation of keypair should succeed")
.secret()
.as_raw(),
&"edef54414c03196557cf73774bc97a645c9a1df2164ed34f0c2a78d1375a930c".into()
);
}
#[test]
fn h256_soft_match() {
let secret =
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
.unwrap();
let derivation_secret =
H256::from_str("51eaf04f9dbbc1417dc97e789edd0c37ecda88bac490434e367ea81b71b7b015")
.unwrap();
let extended_secret = ExtendedSecret::with_code(secret.clone(), 0u64.into());
let extended_public = ExtendedPublic::from_secret(&extended_secret)
.expect("Extended public should be created");
let derived_secret0 = extended_secret.derive(Derivation::Soft(derivation_secret));
let derived_public0 = extended_public
.derive(Derivation::Soft(derivation_secret))
.expect("First derivation of public should succeed");
let public_from_secret0 = ExtendedPublic::from_secret(&derived_secret0)
.expect("Extended public should be created");
assert_eq!(public_from_secret0.public(), derived_public0.public());
}
#[test]
fn h256_hard() {
let secret =
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
.unwrap();
let derivation_secret =
H256::from_str("51eaf04f9dbbc1417dc97e789edd0c37ecda88bac490434e367ea81b71b7b015")
.unwrap();
let extended_secret = ExtendedSecret::with_code(secret.clone(), 1u64.into());
assert_eq!(
&**extended_secret
.derive(Derivation::Hard(derivation_secret))
.as_raw(),
&"2bc2d696fb744d77ff813b4a1ef0ad64e1e5188b622c54ba917acc5ebc7c5486".into()
);
}
#[test]
fn match_() {
let secret =
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
.unwrap();
let extended_secret = ExtendedSecret::with_code(secret.clone(), 1.into());
let extended_public = ExtendedPublic::from_secret(&extended_secret)
.expect("Extended public should be created");
let derived_secret0 = extended_secret.derive(0.into());
let derived_public0 = extended_public
.derive(0.into())
.expect("First derivation of public should succeed");
let public_from_secret0 = ExtendedPublic::from_secret(&derived_secret0)
.expect("Extended public should be created");
assert_eq!(public_from_secret0.public(), derived_public0.public());
}
#[test]
fn test_seeds() {
let seed = H128::from_str("000102030405060708090a0b0c0d0e0f")
.expect("Seed should be valid H128")
.to_vec();
// private key from bitcoin test vector
// xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs
let test_private =
H256::from_str("e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35")
.expect("Private should be decoded ok");
let (private_seed, _) = derivation::seed_pair(&*seed);
assert_eq!(private_seed, test_private);
}
#[test]
fn test_vector_1() {
// xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7
// H(0)
test_extended(
|secret| secret.derive(2147483648.into()),
H256::from_str("edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea")
.expect("Private should be decoded ok"),
);
}
#[test]
fn test_vector_2() {
// xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs
// H(0)/1
test_extended(
|secret| secret.derive(2147483648.into()).derive(1.into()),
H256::from_str("3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368")
.expect("Private should be decoded ok"),
);
}
}

View File

@ -1,120 +0,0 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::{Address, Error, Public, Secret, SECP256K1};
use keccak::Keccak256;
use rustc_hex::ToHex;
use secp256k1::key;
use std::fmt;
pub fn public_to_address(public: &Public) -> Address {
let hash = public.keccak256();
let mut result = Address::default();
result.copy_from_slice(&hash[12..]);
result
}
#[derive(Debug, Clone, PartialEq)]
/// secp256k1 key pair
pub struct KeyPair {
secret: Secret,
public: Public,
}
impl fmt::Display for KeyPair {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
writeln!(f, "secret: {}", self.secret.to_hex())?;
writeln!(f, "public: {}", self.public.to_hex())?;
write!(f, "address: {}", self.address().to_hex())
}
}
impl KeyPair {
/// Create a pair from secret key
pub fn from_secret(secret: Secret) -> Result<KeyPair, Error> {
let context = &SECP256K1;
let s: key::SecretKey = key::SecretKey::from_slice(context, &secret[..])?;
let pub_key = key::PublicKey::from_secret_key(context, &s)?;
let serialized = pub_key.serialize_vec(context, false);
let mut public = Public::default();
public.copy_from_slice(&serialized[1..65]);
let keypair = KeyPair {
secret: secret,
public: public,
};
Ok(keypair)
}
pub fn from_secret_slice(slice: &[u8]) -> Result<KeyPair, Error> {
Self::from_secret(Secret::from_unsafe_slice(slice)?)
}
pub fn from_keypair(sec: key::SecretKey, publ: key::PublicKey) -> Self {
let context = &SECP256K1;
let serialized = publ.serialize_vec(context, false);
let secret = Secret::from(sec);
let mut public = Public::default();
public.copy_from_slice(&serialized[1..65]);
KeyPair {
secret: secret,
public: public,
}
}
pub fn secret(&self) -> &Secret {
&self.secret
}
pub fn public(&self) -> &Public {
&self.public
}
pub fn address(&self) -> Address {
public_to_address(&self.public)
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use KeyPair;
use Secret;
#[test]
fn from_secret() {
let secret =
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
.unwrap();
let _ = KeyPair::from_secret(secret).unwrap();
}
#[test]
fn keypair_display() {
let expected =
"secret: a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65
public: 8ce0db0b0359ffc5866ba61903cc2518c3675ef2cf380a7e54bde7ea20e6fa1ab45b7617346cd11b7610001ee6ae5b0155c41cad9527cbcdff44ec67848943a4
address: 5b073e9233944b5e729e46d618f0d8edf3d9c34a".to_owned();
let secret =
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
.unwrap();
let kp = KeyPair::from_secret(secret).unwrap();
assert_eq!(format!("{}", kp), expected);
}
}

View File

@ -17,20 +17,10 @@
// #![warn(missing_docs)] // #![warn(missing_docs)]
extern crate edit_distance; extern crate edit_distance;
extern crate ethereum_types;
extern crate memzero;
extern crate parity_crypto; extern crate parity_crypto;
extern crate parity_wordlist; extern crate parity_wordlist;
#[macro_use]
extern crate quick_error;
extern crate rand;
extern crate rustc_hex;
extern crate secp256k1;
extern crate serde; extern crate serde;
extern crate tiny_keccak;
#[macro_use]
extern crate lazy_static;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
#[macro_use] #[macro_use]
@ -38,52 +28,12 @@ extern crate serde_derive;
mod brain; mod brain;
mod brain_prefix; mod brain_prefix;
mod error;
mod extended;
mod keccak;
mod keypair;
mod password; mod password;
mod prefix; mod prefix;
mod random;
mod secret;
mod signature;
pub mod brain_recover; pub mod brain_recover;
pub mod crypto;
pub mod math;
pub use self::{ pub use self::{
brain::Brain, brain::Brain, brain_prefix::BrainPrefix, parity_wordlist::Error as WordlistError,
brain_prefix::BrainPrefix, password::Password, prefix::Prefix,
error::Error,
extended::{Derivation, DerivationError, ExtendedKeyPair, ExtendedPublic, ExtendedSecret},
keypair::{public_to_address, KeyPair},
math::public_is_valid,
parity_wordlist::Error as WordlistError,
password::Password,
prefix::Prefix,
random::Random,
secret::Secret,
signature::{recover, sign, verify_address, verify_public, Signature},
}; };
use ethereum_types::H256;
pub use ethereum_types::{Address, Public};
pub type Message = H256;
lazy_static! {
pub static ref SECP256K1: secp256k1::Secp256k1 = secp256k1::Secp256k1::new();
}
/// Uninstantiatable error type for infallible generators.
#[derive(Debug)]
pub enum Void {}
/// Generates new keypair.
pub trait Generator {
type Error;
/// Should be called to generate new keypair.
fn generate(&mut self) -> Result<KeyPair, Self::Error>;
}

View File

@ -1,134 +0,0 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::{Error, Public, Secret, SECP256K1};
use ethereum_types::{H256, U256};
use secp256k1::{
constants::{CURVE_ORDER, GENERATOR_X, GENERATOR_Y},
key,
};
/// Whether the public key is valid.
pub fn public_is_valid(public: &Public) -> bool {
to_secp256k1_public(public)
.ok()
.map_or(false, |p| p.is_valid())
}
/// Inplace multiply public key by secret key (EC point * scalar)
pub fn public_mul_secret(public: &mut Public, secret: &Secret) -> Result<(), Error> {
let key_secret = secret.to_secp256k1_secret()?;
let mut key_public = to_secp256k1_public(public)?;
key_public.mul_assign(&SECP256K1, &key_secret)?;
set_public(public, &key_public);
Ok(())
}
/// Inplace add one public key to another (EC point + EC point)
pub fn public_add(public: &mut Public, other: &Public) -> Result<(), Error> {
let mut key_public = to_secp256k1_public(public)?;
let other_public = to_secp256k1_public(other)?;
key_public.add_assign(&SECP256K1, &other_public)?;
set_public(public, &key_public);
Ok(())
}
/// Inplace sub one public key from another (EC point - EC point)
pub fn public_sub(public: &mut Public, other: &Public) -> Result<(), Error> {
let mut key_neg_other = to_secp256k1_public(other)?;
key_neg_other.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
let mut key_public = to_secp256k1_public(public)?;
key_public.add_assign(&SECP256K1, &key_neg_other)?;
set_public(public, &key_public);
Ok(())
}
/// Replace public key with its negation (EC point = - EC point)
pub fn public_negate(public: &mut Public) -> Result<(), Error> {
let mut key_public = to_secp256k1_public(public)?;
key_public.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
set_public(public, &key_public);
Ok(())
}
/// Return base point of secp256k1
pub fn generation_point() -> Public {
let mut public_sec_raw = [0u8; 65];
public_sec_raw[0] = 4;
public_sec_raw[1..33].copy_from_slice(&GENERATOR_X);
public_sec_raw[33..65].copy_from_slice(&GENERATOR_Y);
let public_key = key::PublicKey::from_slice(&SECP256K1, &public_sec_raw)
.expect("constructing using predefined constants; qed");
let mut public = Public::default();
set_public(&mut public, &public_key);
public
}
/// Return secp256k1 elliptic curve order
pub fn curve_order() -> U256 {
H256::from_slice(&CURVE_ORDER).into()
}
fn to_secp256k1_public(public: &Public) -> Result<key::PublicKey, Error> {
let public_data = {
let mut temp = [4u8; 65];
(&mut temp[1..65]).copy_from_slice(&public[0..64]);
temp
};
Ok(key::PublicKey::from_slice(&SECP256K1, &public_data)?)
}
fn set_public(public: &mut Public, key_public: &key::PublicKey) {
let key_public_serialized = key_public.serialize_vec(&SECP256K1, false);
public.copy_from_slice(&key_public_serialized[1..65]);
}
#[cfg(test)]
mod tests {
use super::{
super::{Generator, Random},
public_add, public_sub,
};
#[test]
fn public_addition_is_commutative() {
let public1 = Random.generate().unwrap().public().clone();
let public2 = Random.generate().unwrap().public().clone();
let mut left = public1.clone();
public_add(&mut left, &public2).unwrap();
let mut right = public2.clone();
public_add(&mut right, &public1).unwrap();
assert_eq!(left, right);
}
#[test]
fn public_addition_is_reversible_with_subtraction() {
let public1 = Random.generate().unwrap().public().clone();
let public2 = Random.generate().unwrap().public().clone();
let mut sum = public1.clone();
public_add(&mut sum, &public2).unwrap();
public_sub(&mut sum, &public2).unwrap();
assert_eq!(sum, public1);
}
}

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>. // along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::{Error, Generator, KeyPair, Random}; use parity_crypto::publickey::{Error, Generator, KeyPair, Random};
/// Tries to find keypair with address starting with given prefix. /// Tries to find keypair with address starting with given prefix.
pub struct Prefix { pub struct Prefix {
@ -24,20 +24,13 @@ pub struct Prefix {
impl Prefix { impl Prefix {
pub fn new(prefix: Vec<u8>, iterations: usize) -> Self { pub fn new(prefix: Vec<u8>, iterations: usize) -> Self {
Prefix { Prefix { prefix, iterations }
prefix: prefix,
iterations: iterations,
}
} }
}
impl Generator for Prefix { pub fn generate(&mut self) -> Result<KeyPair, Error> {
type Error = Error;
fn generate(&mut self) -> Result<KeyPair, Error> {
for _ in 0..self.iterations { for _ in 0..self.iterations {
let keypair = Random.generate()?; let keypair = Random.generate();
if keypair.address().starts_with(&self.prefix) { if keypair.address().as_ref().starts_with(&self.prefix) {
return Ok(keypair); return Ok(keypair);
} }
} }
@ -48,7 +41,6 @@ impl Generator for Prefix {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use Generator;
use Prefix; use Prefix;
#[test] #[test]
@ -57,6 +49,6 @@ mod tests {
let keypair = Prefix::new(prefix.clone(), usize::max_value()) let keypair = Prefix::new(prefix.clone(), usize::max_value())
.generate() .generate()
.unwrap(); .unwrap();
assert!(keypair.address().starts_with(&prefix)); assert!(keypair.address().as_bytes().starts_with(&prefix));
} }
} }

View File

@ -1,322 +0,0 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use ethereum_types::H256;
use memzero::Memzero;
use rustc_hex::ToHex;
use secp256k1::{constants::SECRET_KEY_SIZE as SECP256K1_SECRET_KEY_SIZE, key};
use std::{fmt, ops::Deref, str::FromStr};
use Error;
use SECP256K1;
#[derive(Clone, PartialEq, Eq)]
pub struct Secret {
inner: Memzero<H256>,
}
impl ToHex for Secret {
fn to_hex(&self) -> String {
format!("{:x}", *self.inner)
}
}
impl fmt::LowerHex for Secret {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.inner.fmt(fmt)
}
}
impl fmt::Debug for Secret {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.inner.fmt(fmt)
}
}
impl fmt::Display for Secret {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(
fmt,
"Secret: 0x{:x}{:x}..{:x}{:x}",
self.inner[0], self.inner[1], self.inner[30], self.inner[31]
)
}
}
impl Secret {
/// Creates a `Secret` from the given slice, returning `None` if the slice length != 32.
pub fn from_slice(key: &[u8]) -> Option<Self> {
if key.len() != 32 {
return None;
}
let mut h = H256::default();
h.copy_from_slice(&key[0..32]);
Some(Secret {
inner: Memzero::from(h),
})
}
/// Creates zero key, which is invalid for crypto operations, but valid for math operation.
pub fn zero() -> Self {
Secret {
inner: Memzero::from(H256::default()),
}
}
/// Imports and validates the key.
pub fn from_unsafe_slice(key: &[u8]) -> Result<Self, Error> {
let secret = key::SecretKey::from_slice(&super::SECP256K1, key)?;
Ok(secret.into())
}
/// Checks validity of this key.
pub fn check_validity(&self) -> Result<(), Error> {
self.to_secp256k1_secret().map(|_| ())
}
/// Inplace add one secret key to another (scalar + scalar)
pub fn add(&mut self, other: &Secret) -> Result<(), Error> {
match (self.is_zero(), other.is_zero()) {
(true, true) | (false, true) => Ok(()),
(true, false) => {
*self = other.clone();
Ok(())
}
(false, false) => {
let mut key_secret = self.to_secp256k1_secret()?;
let other_secret = other.to_secp256k1_secret()?;
key_secret.add_assign(&SECP256K1, &other_secret)?;
*self = key_secret.into();
Ok(())
}
}
}
/// Inplace subtract one secret key from another (scalar - scalar)
pub fn sub(&mut self, other: &Secret) -> Result<(), Error> {
match (self.is_zero(), other.is_zero()) {
(true, true) | (false, true) => Ok(()),
(true, false) => {
*self = other.clone();
self.neg()
}
(false, false) => {
let mut key_secret = self.to_secp256k1_secret()?;
let mut other_secret = other.to_secp256k1_secret()?;
other_secret.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
key_secret.add_assign(&SECP256K1, &other_secret)?;
*self = key_secret.into();
Ok(())
}
}
}
/// Inplace decrease secret key (scalar - 1)
pub fn dec(&mut self) -> Result<(), Error> {
match self.is_zero() {
true => {
*self = key::MINUS_ONE_KEY.into();
Ok(())
}
false => {
let mut key_secret = self.to_secp256k1_secret()?;
key_secret.add_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
*self = key_secret.into();
Ok(())
}
}
}
/// Inplace multiply one secret key to another (scalar * scalar)
pub fn mul(&mut self, other: &Secret) -> Result<(), Error> {
match (self.is_zero(), other.is_zero()) {
(true, true) | (true, false) => Ok(()),
(false, true) => {
*self = Self::zero();
Ok(())
}
(false, false) => {
let mut key_secret = self.to_secp256k1_secret()?;
let other_secret = other.to_secp256k1_secret()?;
key_secret.mul_assign(&SECP256K1, &other_secret)?;
*self = key_secret.into();
Ok(())
}
}
}
/// Inplace negate secret key (-scalar)
pub fn neg(&mut self) -> Result<(), Error> {
match self.is_zero() {
true => Ok(()),
false => {
let mut key_secret = self.to_secp256k1_secret()?;
key_secret.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
*self = key_secret.into();
Ok(())
}
}
}
/// Inplace inverse secret key (1 / scalar)
pub fn inv(&mut self) -> Result<(), Error> {
let mut key_secret = self.to_secp256k1_secret()?;
key_secret.inv_assign(&SECP256K1)?;
*self = key_secret.into();
Ok(())
}
/// Compute power of secret key inplace (secret ^ pow).
/// This function is not intended to be used with large powers.
pub fn pow(&mut self, pow: usize) -> Result<(), Error> {
if self.is_zero() {
return Ok(());
}
match pow {
0 => *self = key::ONE_KEY.into(),
1 => (),
_ => {
let c = self.clone();
for _ in 1..pow {
self.mul(&c)?;
}
}
}
Ok(())
}
/// Create `secp256k1::key::SecretKey` based on this secret
pub fn to_secp256k1_secret(&self) -> Result<key::SecretKey, Error> {
Ok(key::SecretKey::from_slice(&SECP256K1, &self[..])?)
}
}
impl FromStr for Secret {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(H256::from_str(s)
.map_err(|e| Error::Custom(format!("{:?}", e)))?
.into())
}
}
impl From<[u8; 32]> for Secret {
fn from(k: [u8; 32]) -> Self {
Secret {
inner: Memzero::from(H256(k)),
}
}
}
impl From<H256> for Secret {
fn from(s: H256) -> Self {
s.0.into()
}
}
impl From<&'static str> for Secret {
fn from(s: &'static str) -> Self {
s.parse().expect(&format!(
"invalid string literal for {}: '{}'",
stringify!(Self),
s
))
}
}
impl From<key::SecretKey> for Secret {
fn from(key: key::SecretKey) -> Self {
let mut a = [0; SECP256K1_SECRET_KEY_SIZE];
a.copy_from_slice(&key[0..SECP256K1_SECRET_KEY_SIZE]);
a.into()
}
}
impl Deref for Secret {
type Target = H256;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
#[cfg(test)]
mod tests {
use super::{
super::{Generator, Random},
Secret,
};
use std::str::FromStr;
#[test]
fn multiplicating_secret_inversion_with_secret_gives_one() {
let secret = Random.generate().unwrap().secret().clone();
let mut inversion = secret.clone();
inversion.inv().unwrap();
inversion.mul(&secret).unwrap();
assert_eq!(
inversion,
Secret::from_str("0000000000000000000000000000000000000000000000000000000000000001")
.unwrap()
);
}
#[test]
fn secret_inversion_is_reversible_with_inversion() {
let secret = Random.generate().unwrap().secret().clone();
let mut inversion = secret.clone();
inversion.inv().unwrap();
inversion.inv().unwrap();
assert_eq!(inversion, secret);
}
#[test]
fn secret_pow() {
let secret = Random.generate().unwrap().secret().clone();
let mut pow0 = secret.clone();
pow0.pow(0).unwrap();
assert_eq!(
pow0,
Secret::from_str("0000000000000000000000000000000000000000000000000000000000000001")
.unwrap()
);
let mut pow1 = secret.clone();
pow1.pow(1).unwrap();
assert_eq!(pow1, secret);
let mut pow2 = secret.clone();
pow2.pow(2).unwrap();
let mut pow2_expected = secret.clone();
pow2_expected.mul(&secret).unwrap();
assert_eq!(pow2, pow2_expected);
let mut pow3 = secret.clone();
pow3.pow(3).unwrap();
let mut pow3_expected = secret.clone();
pow3_expected.mul(&secret).unwrap();
pow3_expected.mul(&secret).unwrap();
assert_eq!(pow3, pow3_expected);
}
}

View File

@ -1,325 +0,0 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use ethereum_types::{H256, H520};
use public_to_address;
use rustc_hex::{FromHex, ToHex};
use secp256k1::{
key::{PublicKey, SecretKey},
Error as SecpError, Message as SecpMessage, RecoverableSignature, RecoveryId,
};
use std::{
cmp::PartialEq,
fmt,
hash::{Hash, Hasher},
ops::{Deref, DerefMut},
str::FromStr,
};
use Address;
use Error;
use Message;
use Public;
use Secret;
use SECP256K1;
/// Signature encoded as RSV components
#[repr(C)]
pub struct Signature([u8; 65]);
impl Signature {
/// Get a slice into the 'r' portion of the data.
pub fn r(&self) -> &[u8] {
&self.0[0..32]
}
/// Get a slice into the 's' portion of the data.
pub fn s(&self) -> &[u8] {
&self.0[32..64]
}
/// Get the recovery byte.
pub fn v(&self) -> u8 {
self.0[64]
}
/// Encode the signature into RSV array (V altered to be in "Electrum" notation).
pub fn into_electrum(mut self) -> [u8; 65] {
self.0[64] += 27;
self.0
}
/// Parse bytes as a signature encoded as RSV (V in "Electrum" notation).
/// May return empty (invalid) signature if given data has invalid length.
pub fn from_electrum(data: &[u8]) -> Self {
if data.len() != 65 || data[64] < 27 {
// fallback to empty (invalid) signature
return Signature::default();
}
let mut sig = [0u8; 65];
sig.copy_from_slice(data);
sig[64] -= 27;
Signature(sig)
}
/// Create a signature object from the sig.
pub fn from_rsv(r: &H256, s: &H256, v: u8) -> Self {
let mut sig = [0u8; 65];
sig[0..32].copy_from_slice(&r);
sig[32..64].copy_from_slice(&s);
sig[64] = v;
Signature(sig)
}
/// Check if this is a "low" signature.
pub fn is_low_s(&self) -> bool {
H256::from_slice(self.s())
<= "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0".into()
}
/// Check if each component of the signature is in range.
pub fn is_valid(&self) -> bool {
self.v() <= 1
&& H256::from_slice(self.r())
< "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141".into()
&& H256::from_slice(self.r()) >= 1.into()
&& H256::from_slice(self.s())
< "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141".into()
&& H256::from_slice(self.s()) >= 1.into()
}
}
// manual implementation large arrays don't have trait impls by default.
// remove when integer generics exist
impl PartialEq for Signature {
fn eq(&self, other: &Self) -> bool {
&self.0[..] == &other.0[..]
}
}
// manual implementation required in Rust 1.13+, see `std::cmp::AssertParamIsEq`.
impl Eq for Signature {}
// also manual for the same reason, but the pretty printing might be useful.
impl fmt::Debug for Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.debug_struct("Signature")
.field("r", &self.0[0..32].to_hex())
.field("s", &self.0[32..64].to_hex())
.field("v", &self.0[64..65].to_hex())
.finish()
}
}
impl fmt::Display for Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}", self.to_hex())
}
}
impl FromStr for Signature {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.from_hex() {
Ok(ref hex) if hex.len() == 65 => {
let mut data = [0; 65];
data.copy_from_slice(&hex[0..65]);
Ok(Signature(data))
}
_ => Err(Error::InvalidSignature),
}
}
}
impl Default for Signature {
fn default() -> Self {
Signature([0; 65])
}
}
impl Hash for Signature {
fn hash<H: Hasher>(&self, state: &mut H) {
H520::from(self.0).hash(state);
}
}
impl Clone for Signature {
fn clone(&self) -> Self {
Signature(self.0)
}
}
impl From<[u8; 65]> for Signature {
fn from(s: [u8; 65]) -> Self {
Signature(s)
}
}
impl Into<[u8; 65]> for Signature {
fn into(self) -> [u8; 65] {
self.0
}
}
impl From<Signature> for H520 {
fn from(s: Signature) -> Self {
H520::from(s.0)
}
}
impl From<H520> for Signature {
fn from(bytes: H520) -> Self {
Signature(bytes.into())
}
}
impl Deref for Signature {
type Target = [u8; 65];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Signature {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
pub fn sign(secret: &Secret, message: &Message) -> Result<Signature, Error> {
let context = &SECP256K1;
let sec = SecretKey::from_slice(context, &secret)?;
let s = context.sign_recoverable(&SecpMessage::from_slice(&message[..])?, &sec)?;
let (rec_id, data) = s.serialize_compact(context);
let mut data_arr = [0; 65];
// no need to check if s is low, it always is
data_arr[0..64].copy_from_slice(&data[0..64]);
data_arr[64] = rec_id.to_i32() as u8;
Ok(Signature(data_arr))
}
pub fn verify_public(
public: &Public,
signature: &Signature,
message: &Message,
) -> Result<bool, Error> {
let context = &SECP256K1;
let rsig = RecoverableSignature::from_compact(
context,
&signature[0..64],
RecoveryId::from_i32(signature[64] as i32)?,
)?;
let sig = rsig.to_standard(context);
let pdata: [u8; 65] = {
let mut temp = [4u8; 65];
temp[1..65].copy_from_slice(&**public);
temp
};
let publ = PublicKey::from_slice(context, &pdata)?;
match context.verify(&SecpMessage::from_slice(&message[..])?, &sig, &publ) {
Ok(_) => Ok(true),
Err(SecpError::IncorrectSignature) => Ok(false),
Err(x) => Err(Error::from(x)),
}
}
pub fn verify_address(
address: &Address,
signature: &Signature,
message: &Message,
) -> Result<bool, Error> {
let public = recover(signature, message)?;
let recovered_address = public_to_address(&public);
Ok(address == &recovered_address)
}
pub fn recover(signature: &Signature, message: &Message) -> Result<Public, Error> {
let context = &SECP256K1;
let rsig = RecoverableSignature::from_compact(
context,
&signature[0..64],
RecoveryId::from_i32(signature[64] as i32)?,
)?;
let pubkey = context.recover(&SecpMessage::from_slice(&message[..])?, &rsig)?;
let serialized = pubkey.serialize_vec(context, false);
let mut public = Public::default();
public.copy_from_slice(&serialized[1..65]);
Ok(public)
}
#[cfg(test)]
mod tests {
use super::{recover, sign, verify_address, verify_public, Signature};
use std::str::FromStr;
use Generator;
use Message;
use Random;
#[test]
fn vrs_conversion() {
// given
let keypair = Random.generate().unwrap();
let message = Message::default();
let signature = sign(keypair.secret(), &message).unwrap();
// when
let vrs = signature.clone().into_electrum();
let from_vrs = Signature::from_electrum(&vrs);
// then
assert_eq!(signature, from_vrs);
}
#[test]
fn signature_to_and_from_str() {
let keypair = Random.generate().unwrap();
let message = Message::default();
let signature = sign(keypair.secret(), &message).unwrap();
let string = format!("{}", signature);
let deserialized = Signature::from_str(&string).unwrap();
assert_eq!(signature, deserialized);
}
#[test]
fn sign_and_recover_public() {
let keypair = Random.generate().unwrap();
let message = Message::default();
let signature = sign(keypair.secret(), &message).unwrap();
assert_eq!(keypair.public(), &recover(&signature, &message).unwrap());
}
#[test]
fn sign_and_verify_public() {
let keypair = Random.generate().unwrap();
let message = Message::default();
let signature = sign(keypair.secret(), &message).unwrap();
assert!(verify_public(keypair.public(), &signature, &message).unwrap());
}
#[test]
fn sign_and_verify_address() {
let keypair = Random.generate().unwrap();
let message = Message::default();
let signature = sign(keypair.secret(), &message).unwrap();
assert!(verify_address(&keypair.address(), &signature, &message).unwrap());
}
}

View File

@ -7,7 +7,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies] [dependencies]
log = "0.4" log = "0.4"
libc = "0.2" libc = "0.2"
rand = "0.4" rand = "0.7.3"
ethkey = { path = "../ethkey" } ethkey = { path = "../ethkey" }
serde = "1.0" serde = "1.0"
serde_json = "1.0" serde_json = "1.0"
@ -15,9 +15,9 @@ serde_derive = "1.0"
rustc-hex = "1.0" rustc-hex = "1.0"
time = "0.1.34" time = "0.1.34"
itertools = "0.5" itertools = "0.5"
parking_lot = "0.7" parking_lot = "0.11.1"
parity-crypto = "0.3.0" parity-crypto = { version = "0.6.2", features = [ "publickey"] }
ethereum-types = "0.4" ethereum-types = "0.9.2"
smallvec = "0.6" smallvec = "0.6"
parity-wordlist = "1.3" parity-wordlist = "1.3"
tempdir = "0.3" tempdir = "0.3"

View File

@ -15,8 +15,8 @@
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>. // along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use account::{Aes128Ctr, Cipher, Kdf, Pbkdf2, Prf}; use account::{Aes128Ctr, Cipher, Kdf, Pbkdf2, Prf};
use crypto::{self, Keccak256}; use crypto::{self, publickey::Secret, Keccak256};
use ethkey::{Password, Secret}; use ethkey::Password;
use json; use json;
use random::Random; use random::Random;
use smallvec::SmallVec; use smallvec::SmallVec;
@ -79,7 +79,7 @@ impl Crypto {
password: &Password, password: &Password,
iterations: NonZeroU32, iterations: NonZeroU32,
) -> Result<Self, crypto::Error> { ) -> Result<Self, crypto::Error> {
Crypto::with_plain(&*secret, password, iterations) Crypto::with_plain(secret.as_bytes(), password, iterations)
} }
/// Encrypt custom plain data /// Encrypt custom plain data
@ -94,7 +94,7 @@ impl Crypto {
// two parts of derived key // two parts of derived key
// DK = [ DK[0..15] DK[16..31] ] = [derived_left_bits, derived_right_bits] // DK = [ DK[0..15] DK[16..31] ] = [derived_left_bits, derived_right_bits]
let (derived_left_bits, derived_right_bits) = let (derived_left_bits, derived_right_bits) =
crypto::derive_key_iterations(password.as_bytes(), &salt, iterations); crypto::derive_key_iterations(password.as_bytes(), &salt, iterations.get());
// preallocated (on-stack in case of `Secret`) buffer to hold cipher // preallocated (on-stack in case of `Secret`) buffer to hold cipher
// length = length(plain) as we are using CTR-approach // length = length(plain) as we are using CTR-approach
@ -127,7 +127,7 @@ impl Crypto {
} }
let secret = self.do_decrypt(password, 32)?; let secret = self.do_decrypt(password, 32)?;
Ok(Secret::from_unsafe_slice(&secret)?) Ok(Secret::import_key(&secret)?)
} }
/// Try to decrypt and return result as is /// Try to decrypt and return result as is
@ -139,7 +139,7 @@ impl Crypto {
fn do_decrypt(&self, password: &Password, expected_len: usize) -> Result<Vec<u8>, Error> { fn do_decrypt(&self, password: &Password, expected_len: usize) -> Result<Vec<u8>, Error> {
let (derived_left_bits, derived_right_bits) = match self.kdf { let (derived_left_bits, derived_right_bits) = match self.kdf {
Kdf::Pbkdf2(ref params) => { Kdf::Pbkdf2(ref params) => {
crypto::derive_key_iterations(password.as_bytes(), &params.salt, params.c) crypto::derive_key_iterations(password.as_bytes(), &params.salt, params.c.get())
} }
Kdf::Scrypt(ref params) => crypto::scrypt::derive_key( Kdf::Scrypt(ref params) => crypto::scrypt::derive_key(
password.as_bytes(), password.as_bytes(),
@ -179,7 +179,7 @@ impl Crypto {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{Crypto, Error, NonZeroU32}; use super::{Crypto, Error, NonZeroU32};
use ethkey::{Generator, Random}; use crypto::publickey::{Generator, Random};
lazy_static! { lazy_static! {
static ref ITERATIONS: NonZeroU32 = NonZeroU32::new(10240).expect("10240 > 0; qed"); static ref ITERATIONS: NonZeroU32 = NonZeroU32::new(10240).expect("10240 > 0; qed");
@ -187,7 +187,7 @@ mod tests {
#[test] #[test]
fn crypto_with_secret_create() { fn crypto_with_secret_create() {
let keypair = Random.generate().unwrap(); let keypair = Random.generate();
let passwd = "this is sparta".into(); let passwd = "this is sparta".into();
let crypto = Crypto::with_secret(keypair.secret(), &passwd, *ITERATIONS).unwrap(); let crypto = Crypto::with_secret(keypair.secret(), &passwd, *ITERATIONS).unwrap();
let secret = crypto.secret(&passwd).unwrap(); let secret = crypto.secret(&passwd).unwrap();
@ -196,7 +196,7 @@ mod tests {
#[test] #[test]
fn crypto_with_secret_invalid_password() { fn crypto_with_secret_invalid_password() {
let keypair = Random.generate().unwrap(); let keypair = Random.generate();
let crypto = let crypto =
Crypto::with_secret(keypair.secret(), &"this is sparta".into(), *ITERATIONS).unwrap(); Crypto::with_secret(keypair.secret(), &"this is sparta".into(), *ITERATIONS).unwrap();
assert_matches!( assert_matches!(

View File

@ -16,10 +16,11 @@
use super::crypto::Crypto; use super::crypto::Crypto;
use account::Version; use account::Version;
use crypto; use crypto::{
use ethkey::{ self,
self, crypto::ecdh::agree, sign, Address, KeyPair, Message, Password, Public, Secret, Signature, publickey::{ecdh::agree, sign, Address, KeyPair, Message, Public, Secret, Signature},
}; };
use ethkey::Password;
use json; use json;
use std::num::NonZeroU32; use std::num::NonZeroU32;
use Error; use Error;
@ -193,7 +194,7 @@ impl SafeAccount {
message: &[u8], message: &[u8],
) -> Result<Vec<u8>, Error> { ) -> Result<Vec<u8>, Error> {
let secret = self.crypto.secret(password)?; let secret = self.crypto.secret(password)?;
ethkey::crypto::ecies::decrypt(&secret, shared_mac, message).map_err(From::from) crypto::publickey::ecies::decrypt(&secret, shared_mac, message).map_err(From::from)
} }
/// Agree on shared key. /// Agree on shared key.
@ -237,7 +238,7 @@ impl SafeAccount {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{NonZeroU32, SafeAccount}; use super::{NonZeroU32, SafeAccount};
use ethkey::{verify_public, Generator, Message, Random}; use crypto::publickey::{verify_public, Generator, Random};
lazy_static! { lazy_static! {
static ref ITERATIONS: NonZeroU32 = NonZeroU32::new(10240).expect("10240 > 0; qed"); static ref ITERATIONS: NonZeroU32 = NonZeroU32::new(10240).expect("10240 > 0; qed");
@ -245,9 +246,9 @@ mod tests {
#[test] #[test]
fn sign_and_verify_public() { fn sign_and_verify_public() {
let keypair = Random.generate().unwrap(); let keypair = Random.generate();
let password = "hello world".into(); let password = "hello world".into();
let message = Message::default(); let message = [1u8; 32].into();
let account = SafeAccount::create( let account = SafeAccount::create(
&keypair, &keypair,
[0u8; 16], [0u8; 16],
@ -262,10 +263,10 @@ mod tests {
#[test] #[test]
fn change_password() { fn change_password() {
let keypair = Random.generate().unwrap(); let keypair = Random.generate();
let first_password = "hello world".into(); let first_password = "hello world".into();
let sec_password = "this is sparta".into(); let sec_password = "this is sparta".into();
let message = Message::default(); let message = [1u8; 32].into();
let account = SafeAccount::create( let account = SafeAccount::create(
&keypair, &keypair,
[0u8; 16], [0u8; 16],

View File

@ -420,7 +420,7 @@ mod test {
use self::tempdir::TempDir; use self::tempdir::TempDir;
use super::{KeyDirectory, RootDiskDirectory, VaultKey}; use super::{KeyDirectory, RootDiskDirectory, VaultKey};
use account::SafeAccount; use account::SafeAccount;
use ethkey::{Generator, Random}; use crypto::publickey::{Generator, Random};
use std::{env, fs, num::NonZeroU32}; use std::{env, fs, num::NonZeroU32};
lazy_static! { lazy_static! {
@ -432,7 +432,7 @@ mod test {
// given // given
let mut dir = env::temp_dir(); let mut dir = env::temp_dir();
dir.push("ethstore_should_create_new_account"); dir.push("ethstore_should_create_new_account");
let keypair = Random.generate().unwrap(); let keypair = Random.generate();
let password = "hello world".into(); let password = "hello world".into();
let directory = RootDiskDirectory::create(dir.clone()).unwrap(); let directory = RootDiskDirectory::create(dir.clone()).unwrap();
@ -463,7 +463,7 @@ mod test {
// given // given
let mut dir = env::temp_dir(); let mut dir = env::temp_dir();
dir.push("ethstore_should_handle_duplicate_filenames"); dir.push("ethstore_should_handle_duplicate_filenames");
let keypair = Random.generate().unwrap(); let keypair = Random.generate();
let password = "hello world".into(); let password = "hello world".into();
let directory = RootDiskDirectory::create(dir.clone()).unwrap(); let directory = RootDiskDirectory::create(dir.clone()).unwrap();
@ -582,7 +582,7 @@ mod test {
.expect("Files hash should be calculated ok"); .expect("Files hash should be calculated ok");
assert_eq!(hash, 15130871412783076140); assert_eq!(hash, 15130871412783076140);
let keypair = Random.generate().unwrap(); let keypair = Random.generate();
let password = "test pass".into(); let password = "test pass".into();
let account = SafeAccount::create( let account = SafeAccount::create(
&keypair, &keypair,

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>. // along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use ethkey::Address; use crypto::publickey::Address;
use itertools; use itertools;
use parking_lot::RwLock; use parking_lot::RwLock;
use std::collections::HashMap; use std::collections::HashMap;
@ -70,7 +70,7 @@ impl KeyDirectory for MemoryDirectory {
let mut val = 0u64; let mut val = 0u64;
let accounts = self.accounts.read(); let accounts = self.accounts.read();
for acc in accounts.keys() { for acc in accounts.keys() {
val = val ^ acc.low_u64() val = val ^ acc.to_low_u64_be()
} }
Ok(val) Ok(val)
} }

View File

@ -14,8 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>. // along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use crypto::{self, Error as EthCryptoError}; use crypto::publickey::DerivationError;
use ethkey::{self, DerivationError, Error as EthKeyError};
use std::{fmt, io::Error as IoError}; use std::{fmt, io::Error as IoError};
/// Account-related errors. /// Account-related errors.
@ -45,12 +44,10 @@ pub enum Error {
VaultNotFound, VaultNotFound,
/// Account creation failed. /// Account creation failed.
CreationFailed, CreationFailed,
/// `EthKey` error /// `crypto::publickey::Error`
EthKey(EthKeyError), EthCrypto(crypto::Error),
/// `ethkey::crypto::Error`
EthKeyCrypto(ethkey::crypto::Error),
/// `EthCrypto` error /// `EthCrypto` error
EthCrypto(EthCryptoError), EthCryptoPublicKey(crypto::publickey::Error),
/// Derivation error /// Derivation error
Derivation(DerivationError), Derivation(DerivationError),
/// Custom error /// Custom error
@ -72,9 +69,8 @@ impl fmt::Display for Error {
Error::InvalidVaultName => "Invalid vault name".into(), Error::InvalidVaultName => "Invalid vault name".into(),
Error::VaultNotFound => "Vault not found".into(), Error::VaultNotFound => "Vault not found".into(),
Error::CreationFailed => "Account creation failed".into(), Error::CreationFailed => "Account creation failed".into(),
Error::EthKey(ref err) => err.to_string(),
Error::EthKeyCrypto(ref err) => err.to_string(),
Error::EthCrypto(ref err) => err.to_string(), Error::EthCrypto(ref err) => err.to_string(),
Error::EthCryptoPublicKey(ref err) => err.to_string(),
Error::Derivation(ref err) => format!("Derivation error: {:?}", err), Error::Derivation(ref err) => format!("Derivation error: {:?}", err),
Error::Custom(ref s) => s.clone(), Error::Custom(ref s) => s.clone(),
}; };
@ -89,20 +85,14 @@ impl From<IoError> for Error {
} }
} }
impl From<EthKeyError> for Error { impl From<crypto::publickey::Error> for Error {
fn from(err: EthKeyError) -> Self { fn from(err: crypto::publickey::Error) -> Self {
Error::EthKey(err) Error::EthCryptoPublicKey(err)
} }
} }
impl From<ethkey::crypto::Error> for Error { impl From<crypto::Error> for Error {
fn from(err: ethkey::crypto::Error) -> Self { fn from(err: crypto::Error) -> Self {
Error::EthKeyCrypto(err)
}
}
impl From<EthCryptoError> for Error {
fn from(err: EthCryptoError) -> Self {
Error::EthCrypto(err) Error::EthCrypto(err)
} }
} }

View File

@ -16,6 +16,7 @@
//! ethkey reexport to make documentation look pretty. //! ethkey reexport to make documentation look pretty.
pub use _ethkey::*; pub use _ethkey::*;
pub use crypto::publickey::Address;
use json; use json;
impl Into<json::H160> for Address { impl Into<json::H160> for Address {

View File

@ -24,9 +24,10 @@ use std::{
use account::SafeAccount; use account::SafeAccount;
use accounts_dir::{KeyDirectory, SetKeyError, VaultKey, VaultKeyDirectory}; use accounts_dir::{KeyDirectory, SetKeyError, VaultKey, VaultKeyDirectory};
use ethkey::{ use crypto::publickey::{
self, Address, ExtendedKeyPair, KeyPair, Message, Password, Public, Secret, Signature, self, Address, ExtendedKeyPair, KeyPair, Message, Public, Secret, Signature,
}; };
use ethkey::Password;
use json::{self, OpaqueKeyFile, Uuid}; use json::{self, OpaqueKeyFile, Uuid};
use presale::PresaleWallet; use presale::PresaleWallet;
use random::Random; use random::Random;
@ -554,17 +555,17 @@ impl EthMultiStore {
Derivation::Hierarchical(path) => { Derivation::Hierarchical(path) => {
for path_item in path { for path_item in path {
extended = extended.derive(if path_item.soft { extended = extended.derive(if path_item.soft {
ethkey::Derivation::Soft(path_item.index) publickey::Derivation::Soft(path_item.index)
} else { } else {
ethkey::Derivation::Hard(path_item.index) publickey::Derivation::Hard(path_item.index)
})?; })?;
} }
} }
Derivation::SoftHash(h256) => { Derivation::SoftHash(h256) => {
extended = extended.derive(ethkey::Derivation::Soft(h256))?; extended = extended.derive(publickey::Derivation::Soft(h256))?;
} }
Derivation::HardHash(h256) => { Derivation::HardHash(h256) => {
extended = extended.derive(ethkey::Derivation::Hard(h256))?; extended = extended.derive(publickey::Derivation::Hard(h256))?;
} }
} }
Ok(extended) Ok(extended)
@ -615,7 +616,7 @@ impl SimpleSecretStore for EthMultiStore {
let accounts = self.get_matching(&account_ref, password)?; let accounts = self.get_matching(&account_ref, password)?;
for account in accounts { for account in accounts {
let extended = self.generate(account.crypto.secret(password)?, derivation)?; let extended = self.generate(account.crypto.secret(password)?, derivation)?;
return Ok(ethkey::public_to_address(extended.public().public())); return Ok(publickey::public_to_address(extended.public().public()));
} }
Err(Error::InvalidPassword) Err(Error::InvalidPassword)
} }
@ -631,7 +632,7 @@ impl SimpleSecretStore for EthMultiStore {
for account in accounts { for account in accounts {
let extended = self.generate(account.crypto.secret(password)?, derivation)?; let extended = self.generate(account.crypto.secret(password)?, derivation)?;
let secret = extended.secret().as_raw(); let secret = extended.secret().as_raw();
return Ok(ethkey::sign(&secret, message)?); return Ok(publickey::sign(&secret, message)?);
} }
Err(Error::InvalidPassword) Err(Error::InvalidPassword)
} }
@ -898,14 +899,14 @@ mod tests {
use self::tempdir::TempDir; use self::tempdir::TempDir;
use super::{EthMultiStore, EthStore}; use super::{EthMultiStore, EthStore};
use accounts_dir::{KeyDirectory, MemoryDirectory, RootDiskDirectory}; use accounts_dir::{KeyDirectory, MemoryDirectory, RootDiskDirectory};
use crypto::publickey::{Generator, KeyPair, Random};
use ethereum_types::H256; use ethereum_types::H256;
use ethkey::{Generator, KeyPair, Random};
use secret_store::{ use secret_store::{
Derivation, SecretStore, SecretVaultRef, SimpleSecretStore, StoreAccountRef, Derivation, SecretStore, SecretVaultRef, SimpleSecretStore, StoreAccountRef,
}; };
fn keypair() -> KeyPair { fn keypair() -> KeyPair {
Random.generate().unwrap() Random.generate()
} }
fn store() -> EthStore { fn store() -> EthStore {
@ -1051,6 +1052,7 @@ mod tests {
let passwd2 = "xzy".into(); let passwd2 = "xzy".into();
let multi_store = multi_store(); let multi_store = multi_store();
let keypair = keypair(); let keypair = keypair();
let message = [1u8; 32].into();
let address = store let address = store
.insert_account(SecretVaultRef::Root, keypair.secret().clone(), &passwd1) .insert_account(SecretVaultRef::Root, keypair.secret().clone(), &passwd1)
.unwrap(); .unwrap();
@ -1073,9 +1075,7 @@ mod tests {
"First password should work for store." "First password should work for store."
); );
assert!( assert!(
multi_store multi_store.sign(&address, &passwd2, &message).is_ok(),
.sign(&address, &passwd2, &Default::default())
.is_ok(),
"Second password should work for second store." "Second password should work for second store."
); );
assert_eq!(multi_store.accounts().unwrap().len(), 1); assert_eq!(multi_store.accounts().unwrap().len(), 1);
@ -1462,7 +1462,7 @@ mod tests {
SecretVaultRef::Root, SecretVaultRef::Root,
&address, &address,
&"test".into(), &"test".into(),
Derivation::HardHash(H256::from(0)), Derivation::HardHash(H256::zero()),
) )
.unwrap(); .unwrap();
@ -1470,11 +1470,10 @@ mod tests {
let accounts = store.accounts().unwrap(); let accounts = store.accounts().unwrap();
assert_eq!(accounts.len(), 2); assert_eq!(accounts.len(), 2);
let message = [1u8; 32].into();
// and we can sign with the derived contract // and we can sign with the derived contract
assert!( assert!(
store store.sign(&derived, &"test".into(), &message).is_ok(),
.sign(&derived, &"test".into(), &Default::default())
.is_ok(),
"Second password should work for second store." "Second password should work for second store."
); );
} }

View File

@ -17,7 +17,7 @@
use std::{collections::HashSet, fs, path::Path}; use std::{collections::HashSet, fs, path::Path};
use accounts_dir::{DiskKeyFileManager, KeyDirectory, KeyFileManager}; use accounts_dir::{DiskKeyFileManager, KeyDirectory, KeyFileManager};
use ethkey::Address; use crypto::publickey::Address;
use Error; use Error;
/// Import an account from a file. /// Import an account from a file.

View File

@ -74,4 +74,4 @@ pub use self::{
}; };
/// An opaque wrapper for secret. /// An opaque wrapper for secret.
pub struct OpaqueSecret(::ethkey::Secret); pub struct OpaqueSecret(crypto::publickey::Secret);

View File

@ -14,8 +14,12 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>. // along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use crypto::{self, pbkdf2, Keccak256}; use crypto::{
use ethkey::{Address, KeyPair, Password, Secret}; self, pbkdf2,
publickey::{Address, KeyPair, Secret},
Keccak256,
};
use ethkey::Password;
use json; use json;
use std::{fs, num::NonZeroU32, path::Path}; use std::{fs, num::NonZeroU32, path::Path};
use Error; use Error;
@ -61,7 +65,7 @@ impl PresaleWallet {
let salt = pbkdf2::Salt(password.as_bytes()); let salt = pbkdf2::Salt(password.as_bytes());
let sec = pbkdf2::Secret(password.as_bytes()); let sec = pbkdf2::Secret(password.as_bytes());
let iter = NonZeroU32::new(2000).expect("2000 > 0; qed"); let iter = NonZeroU32::new(2000).expect("2000 > 0; qed");
pbkdf2::sha256(iter, salt, sec, &mut derived_key); pbkdf2::sha256(iter.get(), salt, sec, &mut derived_key);
let mut key = vec![0; self.ciphertext.len()]; let mut key = vec![0; self.ciphertext.len()];
let len = let len =
@ -69,7 +73,7 @@ impl PresaleWallet {
.map_err(|_| Error::InvalidPassword)?; .map_err(|_| Error::InvalidPassword)?;
let unpadded = &key[..len]; let unpadded = &key[..len];
let secret = Secret::from_unsafe_slice(&unpadded.keccak256())?; let secret = Secret::import_key(&unpadded.keccak256())?;
if let Ok(kp) = KeyPair::from_secret(secret) { if let Ok(kp) = KeyPair::from_secret(secret) {
if kp.address() == self.address { if kp.address() == self.address {
return Ok(kp); return Ok(kp);

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>. // along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use rand::{OsRng, Rng}; use rand::{distributions::Alphanumeric, rngs::OsRng, Rng, RngCore};
pub trait Random { pub trait Random {
fn random() -> Self fn random() -> Self
@ -25,7 +25,7 @@ pub trait Random {
impl Random for [u8; 16] { impl Random for [u8; 16] {
fn random() -> Self { fn random() -> Self {
let mut result = [0u8; 16]; let mut result = [0u8; 16];
let mut rng = OsRng::new().unwrap(); let mut rng = OsRng;
rng.fill_bytes(&mut result); rng.fill_bytes(&mut result);
result result
} }
@ -34,7 +34,7 @@ impl Random for [u8; 16] {
impl Random for [u8; 32] { impl Random for [u8; 32] {
fn random() -> Self { fn random() -> Self {
let mut result = [0u8; 32]; let mut result = [0u8; 32];
let mut rng = OsRng::new().unwrap(); let mut rng = OsRng;
rng.fill_bytes(&mut result); rng.fill_bytes(&mut result);
result result
} }
@ -42,6 +42,6 @@ impl Random for [u8; 32] {
/// Generate a random string of given length. /// Generate a random string of given length.
pub fn random_string(length: usize) -> String { pub fn random_string(length: usize) -> String {
let mut rng = OsRng::new().expect("Not able to operate without random source."); let rng = OsRng;
rng.gen_ascii_chars().take(length).collect() rng.sample_iter(&Alphanumeric).take(length).collect()
} }

View File

@ -14,8 +14,9 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>. // along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use crypto::publickey::{Address, Message, Public, Secret, Signature};
use ethereum_types::H256; use ethereum_types::H256;
use ethkey::{Address, Message, Password, Public, Secret, Signature}; use ethkey::Password;
use json::{OpaqueKeyFile, Uuid}; use json::{OpaqueKeyFile, Uuid};
use std::{ use std::{
cmp::Ordering, cmp::Ordering,
@ -174,7 +175,7 @@ pub trait SecretStore: SimpleSecretStore {
secret: &OpaqueSecret, secret: &OpaqueSecret,
message: &Message, message: &Message,
) -> Result<Signature, Error> { ) -> Result<Signature, Error> {
Ok(::ethkey::sign(&secret.0, message)?) Ok(crypto::publickey::sign(&secret.0, message)?)
} }
/// Imports presale wallet /// Imports presale wallet

View File

@ -14,15 +14,19 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>. // along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
extern crate ethereum_types;
extern crate ethstore; extern crate ethstore;
extern crate parity_crypto as crypto;
extern crate rand; extern crate rand;
mod util; mod util;
use std::str::FromStr;
use crypto::publickey::{verify_address, Generator, KeyPair, Random, Secret};
use ethereum_types::H160;
use ethstore::{ use ethstore::{
accounts_dir::RootDiskDirectory, accounts_dir::RootDiskDirectory, EthStore, SecretVaultRef, SimpleSecretStore, StoreAccountRef,
ethkey::{verify_address, Generator, KeyPair, Random, Secret},
EthStore, SecretVaultRef, SimpleSecretStore, StoreAccountRef,
}; };
use util::TransientDir; use util::TransientDir;
@ -40,7 +44,7 @@ fn secret_store_open_not_existing() {
} }
fn random_secret() -> Secret { fn random_secret() -> Secret {
Random.generate().unwrap().secret().clone() Random.generate().secret().clone()
} }
#[test] #[test]
@ -66,13 +70,10 @@ fn secret_store_sign() {
.insert_account(SecretVaultRef::Root, random_secret(), &"".into()) .insert_account(SecretVaultRef::Root, random_secret(), &"".into())
.is_ok()); .is_ok());
let accounts = store.accounts().unwrap(); let accounts = store.accounts().unwrap();
let message = [1u8; 32].into();
assert_eq!(accounts.len(), 1); assert_eq!(accounts.len(), 1);
assert!(store assert!(store.sign(&accounts[0], &"".into(), &message).is_ok());
.sign(&accounts[0], &"".into(), &Default::default()) assert!(store.sign(&accounts[0], &"1".into(), &message).is_err());
.is_ok());
assert!(store
.sign(&accounts[0], &"1".into(), &Default::default())
.is_err());
} }
#[test] #[test]
@ -83,19 +84,14 @@ fn secret_store_change_password() {
.insert_account(SecretVaultRef::Root, random_secret(), &"".into()) .insert_account(SecretVaultRef::Root, random_secret(), &"".into())
.is_ok()); .is_ok());
let accounts = store.accounts().unwrap(); let accounts = store.accounts().unwrap();
let message = [1u8; 32].into();
assert_eq!(accounts.len(), 1); assert_eq!(accounts.len(), 1);
assert!(store assert!(store.sign(&accounts[0], &"".into(), &message).is_ok());
.sign(&accounts[0], &"".into(), &Default::default())
.is_ok());
assert!(store assert!(store
.change_password(&accounts[0], &"".into(), &"1".into()) .change_password(&accounts[0], &"".into(), &"1".into())
.is_ok()); .is_ok());
assert!(store assert!(store.sign(&accounts[0], &"".into(), &message).is_err());
.sign(&accounts[0], &"".into(), &Default::default()) assert!(store.sign(&accounts[0], &"1".into(), &message).is_ok());
.is_err());
assert!(store
.sign(&accounts[0], &"1".into(), &Default::default())
.is_ok());
} }
#[test] #[test]
@ -140,9 +136,15 @@ fn secret_store_laod_geth_files() {
assert_eq!( assert_eq!(
store.accounts().unwrap(), store.accounts().unwrap(),
vec![ vec![
StoreAccountRef::root("3f49624084b67849c7b4e805c5988c21a430f9d9".into()), StoreAccountRef::root(
StoreAccountRef::root("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf".into()), H160::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap()
StoreAccountRef::root("63121b431a52f8043c16fcf0d1df9cb7b5f66649".into()), ),
StoreAccountRef::root(
H160::from_str("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf").unwrap()
),
StoreAccountRef::root(
H160::from_str("63121b431a52f8043c16fcf0d1df9cb7b5f66649").unwrap()
),
] ]
); );
} }
@ -154,8 +156,12 @@ fn secret_store_load_pat_files() {
assert_eq!( assert_eq!(
store.accounts().unwrap(), store.accounts().unwrap(),
vec![ vec![
StoreAccountRef::root("3f49624084b67849c7b4e805c5988c21a430f9d9".into()), StoreAccountRef::root(
StoreAccountRef::root("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf".into()), H160::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap()
),
StoreAccountRef::root(
H160::from_str("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf").unwrap()
),
] ]
); );
} }
@ -182,12 +188,16 @@ fn test_decrypting_files_with_short_ciphertext() {
assert_eq!( assert_eq!(
accounts, accounts,
vec![ vec![
StoreAccountRef::root("31e9d1e6d844bd3a536800ef8d8be6a9975db509".into()), StoreAccountRef::root(
StoreAccountRef::root("d1e64e5480bfaf733ba7d48712decb8227797a4e".into()), H160::from_str("31e9d1e6d844bd3a536800ef8d8be6a9975db509").unwrap()
),
StoreAccountRef::root(
H160::from_str("d1e64e5480bfaf733ba7d48712decb8227797a4e").unwrap()
),
] ]
); );
let message = Default::default(); let message = [1u8; 32].into();
let s1 = store.sign(&accounts[0], &"foo".into(), &message).unwrap(); let s1 = store.sign(&accounts[0], &"foo".into(), &message).unwrap();
let s2 = store.sign(&accounts[1], &"foo".into(), &message).unwrap(); let s2 = store.sign(&accounts[1], &"foo".into(), &message).unwrap();

View File

@ -18,11 +18,11 @@ use ethstore::{
accounts_dir::{KeyDirectory, RootDiskDirectory}, accounts_dir::{KeyDirectory, RootDiskDirectory},
Error, SafeAccount, Error, SafeAccount,
}; };
use rand::{OsRng, Rng}; use rand::{rngs::OsRng, RngCore};
use std::{env, fs, path::PathBuf}; use std::{env, fs, path::PathBuf};
pub fn random_dir() -> PathBuf { pub fn random_dir() -> PathBuf {
let mut rng = OsRng::new().unwrap(); let mut rng = OsRng;
let mut dir = env::temp_dir(); let mut dir = env::temp_dir();
dir.push(format!("{:x}-{:x}", rng.next_u64(), rng.next_u64())); dir.push(format!("{:x}-{:x}", rng.next_u64(), rng.next_u64()));
dir dir

View File

@ -18,7 +18,8 @@
use std::{collections::HashMap, time::Instant}; use std::{collections::HashMap, time::Instant};
use ethkey::{Address, Password}; use crypto::publickey::Address;
use ethkey::Password;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use serde_json; use serde_json;

View File

@ -18,6 +18,8 @@
//! Account management. //! Account management.
extern crate parity_crypto as crypto;
mod account_data; mod account_data;
mod error; mod error;
mod stores; mod stores;
@ -32,7 +34,8 @@ use std::{
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use ethkey::{Address, Generator, Message, Password, Public, Random, Secret}; use crypto::publickey::{Address, Generator, Message, Public, Random, Secret};
use ethkey::Password;
use ethstore::{ use ethstore::{
accounts_dir::MemoryDirectory, random_string, EthMultiStore, EthStore, OpaqueSecret, accounts_dir::MemoryDirectory, random_string, EthMultiStore, EthStore, OpaqueSecret,
SecretStore, SecretVaultRef, SimpleSecretStore, StoreAccountRef, SecretStore, SecretVaultRef, SimpleSecretStore, StoreAccountRef,
@ -40,7 +43,7 @@ use ethstore::{
use log::*; use log::*;
use parking_lot::RwLock; use parking_lot::RwLock;
pub use ethkey::Signature; pub use crypto::publickey::Signature;
pub use ethstore::{Derivation, Error, IndexDerivation, KeyFile}; pub use ethstore::{Derivation, Error, IndexDerivation, KeyFile};
pub use self::{account_data::AccountMeta, error::SignError}; pub use self::{account_data::AccountMeta, error::SignError};
@ -134,9 +137,7 @@ impl AccountProvider {
/// Creates new random account and returns address and public key /// Creates new random account and returns address and public key
pub fn new_account_and_public(&self, password: &Password) -> Result<(Address, Public), Error> { pub fn new_account_and_public(&self, password: &Password) -> Result<(Address, Public), Error> {
let acc = Random let acc = Random.generate();
.generate()
.expect("secp context has generation capabilities; qed");
let public = acc.public().clone(); let public = acc.public().clone();
let secret = acc.secret().clone(); let secret = acc.secret().clone();
let account = self let account = self
@ -355,7 +356,8 @@ impl AccountProvider {
} else { } else {
// verify password by signing dump message // verify password by signing dump message
// result may be discarded // result may be discarded
let _ = self.sstore.sign(&account, &password, &Default::default())?; let dummy_msg = [1u8; 32].into();
let _ = self.sstore.sign(&account, &password, &dummy_msg)?;
} }
let data = AccountData { let data = AccountData {
@ -632,15 +634,16 @@ impl AccountProvider {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{AccountProvider, Unlock}; use super::{AccountProvider, Unlock};
use crypto::publickey::{Address, Generator, Random};
use ethereum_types::H256; use ethereum_types::H256;
use ethkey::{Address, Generator, Random};
use ethstore::{Derivation, StoreAccountRef}; use ethstore::{Derivation, StoreAccountRef};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
#[test] #[test]
fn unlock_account_temp() { fn unlock_account_temp() {
let kp = Random.generate().unwrap(); let kp = Random.generate();
let ap = AccountProvider::transient_provider(); let ap = AccountProvider::transient_provider();
let dummy_msg = [1u8; 32].into();
assert!(ap assert!(ap
.insert_account(kp.secret().clone(), &"test".into()) .insert_account(kp.secret().clone(), &"test".into())
.is_ok()); .is_ok());
@ -650,13 +653,13 @@ mod tests {
assert!(ap assert!(ap
.unlock_account_temporarily(kp.address(), "test".into()) .unlock_account_temporarily(kp.address(), "test".into())
.is_ok()); .is_ok());
assert!(ap.sign(kp.address(), None, Default::default()).is_ok()); assert!(ap.sign(kp.address(), None, dummy_msg).is_ok());
assert!(ap.sign(kp.address(), None, Default::default()).is_err()); assert!(ap.sign(kp.address(), None, dummy_msg).is_err());
} }
#[test] #[test]
fn derived_account_nosave() { fn derived_account_nosave() {
let kp = Random.generate().unwrap(); let kp = Random.generate();
let ap = AccountProvider::transient_provider(); let ap = AccountProvider::transient_provider();
assert!(ap assert!(ap
.insert_account(kp.secret().clone(), &"base".into()) .insert_account(kp.secret().clone(), &"base".into())
@ -669,7 +672,7 @@ mod tests {
.derive_account( .derive_account(
&kp.address(), &kp.address(),
None, None,
Derivation::SoftHash(H256::from(999)), Derivation::SoftHash(H256::from_low_u64_be(999)),
false, false,
) )
.expect("Derivation should not fail"); .expect("Derivation should not fail");
@ -683,7 +686,7 @@ mod tests {
#[test] #[test]
fn derived_account_save() { fn derived_account_save() {
let kp = Random.generate().unwrap(); let kp = Random.generate();
let ap = AccountProvider::transient_provider(); let ap = AccountProvider::transient_provider();
assert!(ap assert!(ap
.insert_account(kp.secret().clone(), &"base".into()) .insert_account(kp.secret().clone(), &"base".into())
@ -696,7 +699,7 @@ mod tests {
.derive_account( .derive_account(
&kp.address(), &kp.address(),
None, None,
Derivation::SoftHash(H256::from(999)), Derivation::SoftHash(H256::from_low_u64_be(999)),
true, true,
) )
.expect("Derivation should not fail"); .expect("Derivation should not fail");
@ -716,7 +719,7 @@ mod tests {
#[test] #[test]
fn derived_account_sign() { fn derived_account_sign() {
let kp = Random.generate().unwrap(); let kp = Random.generate();
let ap = AccountProvider::transient_provider(); let ap = AccountProvider::transient_provider();
assert!(ap assert!(ap
.insert_account(kp.secret().clone(), &"base".into()) .insert_account(kp.secret().clone(), &"base".into())
@ -729,14 +732,14 @@ mod tests {
.derive_account( .derive_account(
&kp.address(), &kp.address(),
None, None,
Derivation::SoftHash(H256::from(1999)), Derivation::SoftHash(H256::from_low_u64_be(1999)),
true, true,
) )
.expect("Derivation should not fail"); .expect("Derivation should not fail");
ap.unlock_account_permanently(derived_addr, "base".into()) ap.unlock_account_permanently(derived_addr, "base".into())
.expect("Should be ok because account is saved and password is valid"); .expect("Should be ok because account is saved and password is valid");
let msg = Default::default(); let msg = [2u8; 32].into();
let signed_msg1 = ap let signed_msg1 = ap
.sign(derived_addr, None, msg) .sign(derived_addr, None, msg)
.expect("Signing with existing unlocked account should not fail"); .expect("Signing with existing unlocked account should not fail");
@ -744,7 +747,7 @@ mod tests {
.sign_derived( .sign_derived(
&kp.address(), &kp.address(),
None, None,
Derivation::SoftHash(H256::from(1999)), Derivation::SoftHash(H256::from_low_u64_be(1999)),
msg, msg,
) )
.expect("Derived signing with existing unlocked account should not fail"); .expect("Derived signing with existing unlocked account should not fail");
@ -754,8 +757,9 @@ mod tests {
#[test] #[test]
fn unlock_account_perm() { fn unlock_account_perm() {
let kp = Random.generate().unwrap(); let kp = Random.generate();
let ap = AccountProvider::transient_provider(); let ap = AccountProvider::transient_provider();
let dummy_msg = [1u8; 32].into();
assert!(ap assert!(ap
.insert_account(kp.secret().clone(), &"test".into()) .insert_account(kp.secret().clone(), &"test".into())
.is_ok()); .is_ok());
@ -765,19 +769,20 @@ mod tests {
assert!(ap assert!(ap
.unlock_account_permanently(kp.address(), "test".into()) .unlock_account_permanently(kp.address(), "test".into())
.is_ok()); .is_ok());
assert!(ap.sign(kp.address(), None, Default::default()).is_ok()); assert!(ap.sign(kp.address(), None, dummy_msg).is_ok());
assert!(ap.sign(kp.address(), None, Default::default()).is_ok()); assert!(ap.sign(kp.address(), None, dummy_msg).is_ok());
assert!(ap assert!(ap
.unlock_account_temporarily(kp.address(), "test".into()) .unlock_account_temporarily(kp.address(), "test".into())
.is_ok()); .is_ok());
assert!(ap.sign(kp.address(), None, Default::default()).is_ok()); assert!(ap.sign(kp.address(), None, dummy_msg).is_ok());
assert!(ap.sign(kp.address(), None, Default::default()).is_ok()); assert!(ap.sign(kp.address(), None, dummy_msg).is_ok());
} }
#[test] #[test]
fn unlock_account_timer() { fn unlock_account_timer() {
let kp = Random.generate().unwrap(); let kp = Random.generate();
let ap = AccountProvider::transient_provider(); let ap = AccountProvider::transient_provider();
let dummy_msg = [1u8; 32].into();
assert!(ap assert!(ap
.insert_account(kp.secret().clone(), &"test".into()) .insert_account(kp.secret().clone(), &"test".into())
.is_ok()); .is_ok());
@ -787,35 +792,35 @@ mod tests {
assert!(ap assert!(ap
.unlock_account_timed(kp.address(), "test".into(), Duration::from_secs(60)) .unlock_account_timed(kp.address(), "test".into(), Duration::from_secs(60))
.is_ok()); .is_ok());
assert!(ap.sign(kp.address(), None, Default::default()).is_ok()); assert!(ap.sign(kp.address(), None, dummy_msg).is_ok());
ap.unlocked ap.unlocked
.write() .write()
.get_mut(&StoreAccountRef::root(kp.address())) .get_mut(&StoreAccountRef::root(kp.address()))
.unwrap() .unwrap()
.unlock = Unlock::Timed(Instant::now()); .unlock = Unlock::Timed(Instant::now());
assert!(ap.sign(kp.address(), None, Default::default()).is_err()); assert!(ap.sign(kp.address(), None, dummy_msg).is_err());
} }
#[test] #[test]
fn should_sign_and_return_token() { fn should_sign_and_return_token() {
// given // given
let kp = Random.generate().unwrap(); let kp = Random.generate();
let ap = AccountProvider::transient_provider(); let ap = AccountProvider::transient_provider();
let dummy_msg = [1u8; 32].into();
assert!(ap assert!(ap
.insert_account(kp.secret().clone(), &"test".into()) .insert_account(kp.secret().clone(), &"test".into())
.is_ok()); .is_ok());
// when // when
let (_signature, token) = ap let (_signature, token) = ap
.sign_with_token(kp.address(), "test".into(), Default::default()) .sign_with_token(kp.address(), "test".into(), dummy_msg)
.unwrap(); .unwrap();
// then // then
ap.sign_with_token(kp.address(), token.clone(), Default::default()) ap.sign_with_token(kp.address(), token.clone(), dummy_msg)
.expect("First usage of token should be correct."); .expect("First usage of token should be correct.");
assert!( assert!(
ap.sign_with_token(kp.address(), token, Default::default()) ap.sign_with_token(kp.address(), token, dummy_msg).is_err(),
.is_err(),
"Second usage of the same token should fail." "Second usage of the same token should fail."
); );
} }

View File

@ -22,7 +22,7 @@ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use ethkey::Address; use crypto::publickey::Address;
use log::{trace, warn}; use log::{trace, warn};
use crate::AccountMeta; use crate::AccountMeta;
@ -172,6 +172,7 @@ impl<K: hash::Hash + Eq, V> DiskMap<K, V> {
mod tests { mod tests {
use super::AddressBook; use super::AddressBook;
use crate::account_data::AccountMeta; use crate::account_data::AccountMeta;
use ethereum_types::H160;
use std::collections::HashMap; use std::collections::HashMap;
use tempdir::TempDir; use tempdir::TempDir;
@ -179,8 +180,8 @@ mod tests {
fn should_save_and_reload_address_book() { fn should_save_and_reload_address_book() {
let tempdir = TempDir::new("").unwrap(); let tempdir = TempDir::new("").unwrap();
let mut b = AddressBook::new(tempdir.path()); let mut b = AddressBook::new(tempdir.path());
b.set_name(1.into(), "One".to_owned()); b.set_name(H160::from_low_u64_be(1), "One".to_owned());
b.set_meta(1.into(), "{1:1}".to_owned()); b.set_meta(H160::from_low_u64_be(1), "{1:1}".to_owned());
let b = AddressBook::new(tempdir.path()); let b = AddressBook::new(tempdir.path());
assert_eq!( assert_eq!(
b.get(), b.get(),
@ -193,7 +194,7 @@ mod tests {
} }
)] )]
.into_iter() .into_iter()
.map(|(a, b)| (a.into(), b)) .map(|(a, b)| (H160::from_low_u64_be(a), b))
.collect::<HashMap<_, _>>() .collect::<HashMap<_, _>>()
); );
} }
@ -203,10 +204,10 @@ mod tests {
let tempdir = TempDir::new("").unwrap(); let tempdir = TempDir::new("").unwrap();
let mut b = AddressBook::new(tempdir.path()); let mut b = AddressBook::new(tempdir.path());
b.set_name(1.into(), "One".to_owned()); b.set_name(H160::from_low_u64_be(1), "One".to_owned());
b.set_name(2.into(), "Two".to_owned()); b.set_name(H160::from_low_u64_be(2), "Two".to_owned());
b.set_name(3.into(), "Three".to_owned()); b.set_name(H160::from_low_u64_be(3), "Three".to_owned());
b.remove(2.into()); b.remove(H160::from_low_u64_be(2));
let b = AddressBook::new(tempdir.path()); let b = AddressBook::new(tempdir.path());
assert_eq!( assert_eq!(
@ -230,7 +231,7 @@ mod tests {
), ),
] ]
.into_iter() .into_iter()
.map(|(a, b)| (a.into(), b)) .map(|(a, b)| (H160::from_low_u64_be(a), b))
.collect::<HashMap<_, _>>() .collect::<HashMap<_, _>>()
); );
} }

View File

@ -7,11 +7,12 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies] [dependencies]
crunchy = "0.1.0" crunchy = "0.1.0"
either = "1.0.0" either = "1.0.0"
ethereum-types = "0.4" ethereum-types = "0.9.2"
keccak-hash = "0.1" keccak-hash = "0.5.0"
tiny-keccak = "2.0.2"
log = "0.4" log = "0.4"
memmap = "0.6" memmap = "0.6"
parking_lot = "0.7" parking_lot = "0.11.1"
primal = "0.2.3" primal = "0.2.3"
[dev-dependencies] [dev-dependencies]

View File

@ -21,7 +21,7 @@ use memmap::MmapMut;
use parking_lot::Mutex; use parking_lot::Mutex;
use seed_compute::SeedHashCompute; use seed_compute::SeedHashCompute;
use shared::{epoch, get_cache_size, to_hex, Node, ETHASH_CACHE_ROUNDS, NODE_BYTES, NODE_DWORDS}; use shared::{epoch, get_cache_size, to_hex, Node, ETHASH_CACHE_ROUNDS, NODE_BYTES};
use std::{ use std::{
borrow::Cow, borrow::Cow,
@ -318,27 +318,22 @@ impl AsRef<[Node]> for NodeCache {
// out. It counts as a read and causes all writes afterwards to be elided. Yes, really. I know, I // out. It counts as a read and causes all writes afterwards to be elided. Yes, really. I know, I
// want to refactor this to use less `unsafe` as much as the next rustacean. // want to refactor this to use less `unsafe` as much as the next rustacean.
unsafe fn initialize_memory(memory: *mut Node, num_nodes: usize, ident: &H256) { unsafe fn initialize_memory(memory: *mut Node, num_nodes: usize, ident: &H256) {
let dst = memory as *mut u8; // We use raw pointers here, see above
let dst = slice::from_raw_parts_mut(memory as *mut u8, NODE_BYTES);
debug_assert_eq!(ident.len(), 32); debug_assert_eq!(ident.len(), 32);
keccak_512::unchecked(dst, NODE_BYTES, ident.as_ptr(), ident.len()); keccak_512::write(&ident[..], dst);
for i in 1..num_nodes { for i in 1..num_nodes {
// We use raw pointers here, see above // We use raw pointers here, see above
let dst = memory.offset(i as _) as *mut u8; let dst = slice::from_raw_parts_mut(memory.offset(i as _) as *mut u8, NODE_BYTES);
let src = memory.offset(i as isize - 1) as *mut u8; let src = slice::from_raw_parts(memory.offset(i as isize - 1) as *mut u8, NODE_BYTES);
keccak_512::write(src, dst);
keccak_512::unchecked(dst, NODE_BYTES, src, NODE_BYTES);
} }
// Now this is initialized, we can treat it as a slice. // Now this is initialized, we can treat it as a slice.
let nodes: &mut [Node] = slice::from_raw_parts_mut(memory, num_nodes); let nodes: &mut [Node] = slice::from_raw_parts_mut(memory, num_nodes);
// For `unroll!`, see below. If the literal in `unroll!` is not the same as the RHS here then
// these have got out of sync! Don't let this happen!
debug_assert_eq!(NODE_DWORDS, 8);
// This _should_ get unrolled by the compiler, since it's not using the loop variable.
for _ in 0..ETHASH_CACHE_ROUNDS { for _ in 0..ETHASH_CACHE_ROUNDS {
for i in 0..num_nodes { for i in 0..num_nodes {
let data_idx = (num_nodes - 1 + i) % num_nodes; let data_idx = (num_nodes - 1 + i) % num_nodes;
@ -348,11 +343,8 @@ unsafe fn initialize_memory(memory: *mut Node, num_nodes: usize, ident: &H256) {
let mut data: Node = nodes.get_unchecked(data_idx).clone(); let mut data: Node = nodes.get_unchecked(data_idx).clone();
let rhs: &Node = nodes.get_unchecked(idx); let rhs: &Node = nodes.get_unchecked(idx);
unroll! { for (a, b) in data.as_dwords_mut().iter_mut().zip(rhs.as_dwords()) {
for w in 0..8 { *a ^= *b;
*data.as_dwords_mut().get_unchecked_mut(w) ^=
*rhs.as_dwords().get_unchecked(w);
}
} }
data data

View File

@ -26,7 +26,7 @@ use seed_compute::SeedHashCompute;
use shared::*; use shared::*;
use std::io; use std::io;
use std::{mem, path::Path, ptr}; use std::{mem, path::Path};
const MIX_WORDS: usize = ETHASH_MIX_BYTES / 4; const MIX_WORDS: usize = ETHASH_MIX_BYTES / 4;
const MIX_NODES: usize = MIX_WORDS / NODE_WORDS; const MIX_NODES: usize = MIX_WORDS / NODE_WORDS;
@ -141,31 +141,24 @@ pub fn quick_get_difficulty(
mix_hash: &H256, mix_hash: &H256,
progpow: bool, progpow: bool,
) -> H256 { ) -> H256 {
unsafe { if progpow {
if progpow { let seed = keccak_f800_short(*header_hash, nonce, [0u32; 8]);
let seed = keccak_f800_short(*header_hash, nonce, [0u32; 8]); keccak_f800_long(*header_hash, seed, unsafe { mem::transmute(*mix_hash) })
keccak_f800_long(*header_hash, seed, mem::transmute(*mix_hash)) } else {
} else { let mut buf = [0u8; 64 + 32];
// This is safe - the `keccak_512` call below reads the first 40 bytes (which we explicitly set
// with two `copy_nonoverlapping` calls) but writes the first 64, and then we explicitly write
// the next 32 bytes before we read the whole thing with `keccak_256`.
//
// This cannot be elided by the compiler as it doesn't know the implementation of
// `keccak_512`.
let mut buf: [u8; 64 + 32] = ::mem::MaybeUninit::uninit().assume_init();
ptr::copy_nonoverlapping(header_hash.as_ptr(), buf.as_mut_ptr(), 32); let hash_len = header_hash.len();
ptr::copy_nonoverlapping(&nonce as *const u64 as *const u8, buf[32..].as_mut_ptr(), 8); buf[..hash_len].copy_from_slice(header_hash);
let end = hash_len + mem::size_of::<u64>();
buf[hash_len..end].copy_from_slice(&nonce.to_ne_bytes());
keccak_512::unchecked(buf.as_mut_ptr(), 64, buf.as_ptr(), 40); keccak_512::inplace_range(&mut buf, 0..end);
ptr::copy_nonoverlapping(mix_hash.as_ptr(), buf[64..].as_mut_ptr(), 32); buf[64..].copy_from_slice(mix_hash);
// This is initialized in `keccak_256` let mut hash = [0u8; 32];
let mut hash: [u8; 32] = ::mem::MaybeUninit::uninit().assume_init(); keccak_256::write(&buf, &mut hash);
keccak_256::unchecked(hash.as_mut_ptr(), hash.len(), buf.as_ptr(), buf.len());
hash hash
}
} }
} }
@ -214,32 +207,21 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64)
// improvements, since I can't imagine that 3-5% of our runtime is taken up by catting two // improvements, since I can't imagine that 3-5% of our runtime is taken up by catting two
// arrays together. // arrays together.
let mut buf: MixBuf = MixBuf { let mut buf: MixBuf = MixBuf {
half_mix: unsafe { half_mix: {
// Pack `header_hash` and `nonce` together // Pack `header_hash` and `nonce` together
// We explicitly write the first 40 bytes, leaving the last 24 as uninitialized. Then let mut out = [0u8; NODE_BYTES];
// `keccak_512` reads the first 40 bytes (4th parameter) and overwrites the entire array,
// leaving it fully initialized.
let mut out: [u8; NODE_BYTES] = ::mem::MaybeUninit::uninit().assume_init();
ptr::copy_nonoverlapping(header_hash.as_ptr(), out.as_mut_ptr(), header_hash.len()); let hash_len = header_hash.len();
ptr::copy_nonoverlapping( out[..hash_len].copy_from_slice(header_hash);
&nonce as *const u64 as *const u8, let end = hash_len + mem::size_of::<u64>();
out[header_hash.len()..].as_mut_ptr(), out[hash_len..end].copy_from_slice(&nonce.to_ne_bytes());
mem::size_of::<u64>(),
);
// compute keccak-512 hash and replicate across mix // compute keccak-512 hash and replicate across mix
keccak_512::unchecked( keccak_512::inplace_range(&mut out, 0..end);
out.as_mut_ptr(),
NODE_BYTES,
out.as_ptr(),
header_hash.len() + mem::size_of::<u64>(),
);
Node { bytes: out } Node { bytes: out }
}, },
// This is fully initialized before being read, see `let mut compress = ...` below compress_bytes: [0u8; MIX_WORDS],
compress_bytes: unsafe { ::mem::MaybeUninit::uninit().assume_init() },
}; };
let mut mix: [_; MIX_NODES] = [buf.half_mix.clone(), buf.half_mix.clone()]; let mut mix: [_; MIX_NODES] = [buf.half_mix.clone(), buf.half_mix.clone()];
@ -263,24 +245,13 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64)
fnv_hash(first_val ^ i, mix_words[i as usize % MIX_WORDS]) % num_full_pages fnv_hash(first_val ^ i, mix_words[i as usize % MIX_WORDS]) % num_full_pages
}; };
unroll! { // MIX_NODES
// MIX_NODES for n in 0..2 {
for n in 0..2 { 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,
cache,
);
unroll! { // NODE_WORDS
// NODE_WORDS for (a, b) in mix[n].as_words_mut().iter_mut().zip(tmp_node.as_words()) {
for w in 0..16 { *a = fnv_hash(*a, *b);
mix[n].as_words_mut()[w] =
fnv_hash(
mix[n].as_words()[w],
tmp_node.as_words()[w],
);
}
}
} }
} }
} }
@ -288,25 +259,27 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64)
let mix_words: [u32; MIX_WORDS] = unsafe { mem::transmute(mix) }; let mix_words: [u32; MIX_WORDS] = unsafe { mem::transmute(mix) };
{ {
// This is an uninitialized buffer to begin with, but we iterate precisely `compress.len()` // We iterate precisely `compress.len()` times and set each index,
// times and set each index, leaving the array fully initialized. THIS ONLY WORKS ON LITTLE- // leaving the array fully initialized. THIS ONLY WORKS ON LITTLE-ENDIAN MACHINES.
// ENDIAN MACHINES. See a future PR to make this and the rest of the code work correctly on // See a future PR to make this and the rest of the code work correctly on
// big-endian arches like mips. // big-endian arches like mips.
let compress: &mut [u32; MIX_WORDS / 4] = let compress: &mut [u32; MIX_WORDS / 4] =
unsafe { make_const_array!(MIX_WORDS / 4, &mut buf.compress_bytes) }; unsafe { make_const_array!(MIX_WORDS / 4, &mut buf.compress_bytes) };
#[cfg(target_endian = "big")]
{
compile_error!("OpenEthereum currently only supports little-endian targets");
}
// Compress mix // Compress mix
debug_assert_eq!(MIX_WORDS / 4, 8); debug_assert_eq!(MIX_WORDS / 4, 8);
unroll! { for i in 0..8 {
for i in 0..8 { let w = i * 4;
let w = i * 4;
let mut reduction = mix_words[w + 0]; let mut reduction = mix_words[w + 0];
reduction = reduction.wrapping_mul(FNV_PRIME) ^ mix_words[w + 1]; reduction = reduction.wrapping_mul(FNV_PRIME) ^ mix_words[w + 1];
reduction = reduction.wrapping_mul(FNV_PRIME) ^ mix_words[w + 2]; reduction = reduction.wrapping_mul(FNV_PRIME) ^ mix_words[w + 2];
reduction = reduction.wrapping_mul(FNV_PRIME) ^ mix_words[w + 3]; reduction = reduction.wrapping_mul(FNV_PRIME) ^ mix_words[w + 3];
compress[i] = reduction; compress[i] = reduction;
}
} }
} }
@ -315,24 +288,20 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64)
let value: H256 = { let value: H256 = {
// We can interpret the buffer as an array of `u8`s, since it's `repr(C)`. // We can interpret the buffer as an array of `u8`s, since it's `repr(C)`.
let read_ptr: *const u8 = &buf as *const MixBuf as *const u8; let read_ptr: *const u8 = &buf as *const MixBuf as *const u8;
// We overwrite the second half since `keccak_256` has an internal buffer and so allows let buffer = unsafe {
// overlapping arrays as input. core::slice::from_raw_parts(
let write_ptr: *mut u8 = &mut buf.compress_bytes as *mut [u8; 32] as *mut u8;
unsafe {
keccak_256::unchecked(
write_ptr,
buf.compress_bytes.len(),
read_ptr, read_ptr,
buf.half_mix.bytes.len() + buf.compress_bytes.len(), buf.half_mix.bytes.len() + buf.compress_bytes.len(),
); )
} };
// We overwrite the buf.compress_bytes since `keccak_256` has an internal buffer and so allows
// overlapping arrays as input.
keccak_256::write(buffer, &mut buf.compress_bytes);
buf.compress_bytes buf.compress_bytes
}; };
ProofOfWork { ProofOfWork { mix_hash, value }
mix_hash: mix_hash,
value: value,
}
} }
// TODO: Use the `simd` crate // TODO: Use the `simd` crate

View File

@ -21,46 +21,15 @@ pub type H256 = [u8; 32];
pub mod keccak_512 { pub mod keccak_512 {
use super::hash; use super::hash;
pub use self::hash::keccak_512_unchecked as unchecked; pub use self::hash::{
keccak512 as inplace, keccak512_range as inplace_range, keccak_512 as write,
pub fn write(input: &[u8], output: &mut [u8]) { };
hash::keccak_512(input, output);
}
pub fn inplace(input: &mut [u8]) {
// This is safe since `keccak_*` uses an internal buffer and copies the result to the output. This
// means that we can reuse the input buffer for both input and output.
unsafe {
hash::keccak_512_unchecked(
input.as_mut_ptr(),
input.len(),
input.as_ptr(),
input.len(),
);
}
}
} }
pub mod keccak_256 { pub mod keccak_256 {
use super::hash; use super::hash;
pub use self::hash::keccak_256_unchecked as unchecked; pub use self::hash::{
keccak256 as inplace, keccak256_range as inplace_range, keccak_256 as write,
#[allow(dead_code)] };
pub fn write(input: &[u8], output: &mut [u8]) {
hash::keccak_256(input, output);
}
pub fn inplace(input: &mut [u8]) {
// This is safe since `keccak_*` uses an internal buffer and copies the result to the output. This
// means that we can reuse the input buffer for both input and output.
unsafe {
hash::keccak_256_unchecked(
input.as_mut_ptr(),
input.len(),
input.as_ptr(),
input.len(),
);
}
}
} }

View File

@ -19,6 +19,7 @@ extern crate ethereum_types;
extern crate memmap; extern crate memmap;
extern crate parking_lot; extern crate parking_lot;
extern crate primal; extern crate primal;
extern crate tiny_keccak;
#[macro_use] #[macro_use]
extern crate crunchy; extern crate crunchy;
@ -52,12 +53,13 @@ mod progpow;
pub use cache::{NodeCacheBuilder, OptimizeFor}; pub use cache::{NodeCacheBuilder, OptimizeFor};
use compute::Light; use compute::Light;
pub use compute::{quick_get_difficulty, slow_hash_block_number, ProofOfWork}; pub use compute::{quick_get_difficulty, slow_hash_block_number, ProofOfWork};
use ethereum_types::{U256, U512}; use ethereum_types::{BigEndianHash, U256, U512};
use keccak::H256; use keccak::H256;
use parking_lot::Mutex; use parking_lot::Mutex;
pub use seed_compute::SeedHashCompute; pub use seed_compute::SeedHashCompute;
pub use shared::ETHASH_EPOCH_LENGTH; pub use shared::ETHASH_EPOCH_LENGTH;
use std::{ use std::{
convert::TryFrom,
mem, mem,
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
@ -168,12 +170,12 @@ impl EthashManager {
/// Convert an Ethash boundary to its original difficulty. Basically just `f(x) = 2^256 / x`. /// Convert an Ethash boundary to its original difficulty. Basically just `f(x) = 2^256 / x`.
pub fn boundary_to_difficulty(boundary: &ethereum_types::H256) -> U256 { pub fn boundary_to_difficulty(boundary: &ethereum_types::H256) -> U256 {
difficulty_to_boundary_aux(&**boundary) difficulty_to_boundary_aux(&boundary.into_uint())
} }
/// Convert an Ethash difficulty to the target boundary. Basically just `f(x) = 2^256 / x`. /// Convert an Ethash difficulty to the target boundary. Basically just `f(x) = 2^256 / x`.
pub fn difficulty_to_boundary(difficulty: &U256) -> ethereum_types::H256 { pub fn difficulty_to_boundary(difficulty: &U256) -> ethereum_types::H256 {
difficulty_to_boundary_aux(difficulty).into() BigEndianHash::from_uint(&difficulty_to_boundary_aux(difficulty))
} }
fn difficulty_to_boundary_aux<T: Into<U512>>(difficulty: T) -> ethereum_types::U256 { fn difficulty_to_boundary_aux<T: Into<U512>>(difficulty: T) -> ethereum_types::U256 {
@ -184,8 +186,8 @@ fn difficulty_to_boundary_aux<T: Into<U512>>(difficulty: T) -> ethereum_types::U
if difficulty == U512::one() { if difficulty == U512::one() {
U256::max_value() U256::max_value()
} else { } else {
// difficulty > 1, so result should never overflow 256 bits const PROOF: &str = "difficulty > 1, so result never overflows 256 bits; qed";
U256::from((U512::one() << 256) / difficulty) U256::try_from((U512::one() << 256) / difficulty).expect(PROOF)
} }
} }
@ -210,12 +212,12 @@ fn test_lru() {
#[test] #[test]
fn test_difficulty_to_boundary() { fn test_difficulty_to_boundary() {
use ethereum_types::H256; use ethereum_types::{BigEndianHash, H256};
use std::str::FromStr; use std::str::FromStr;
assert_eq!( assert_eq!(
difficulty_to_boundary(&U256::from(1)), difficulty_to_boundary(&U256::from(1)),
H256::from(U256::max_value()) BigEndianHash::from_uint(&U256::max_value())
); );
assert_eq!( assert_eq!(
difficulty_to_boundary(&U256::from(2)), difficulty_to_boundary(&U256::from(2)),
@ -243,16 +245,18 @@ fn test_difficulty_to_boundary_regression() {
boundary_to_difficulty(&difficulty_to_boundary(&difficulty.into())) boundary_to_difficulty(&difficulty_to_boundary(&difficulty.into()))
); );
assert_eq!( assert_eq!(
H256::from(difficulty), H256::from_low_u64_be(difficulty),
difficulty_to_boundary(&boundary_to_difficulty(&difficulty.into())) difficulty_to_boundary(&boundary_to_difficulty(&H256::from_low_u64_be(difficulty)))
); );
assert_eq!( assert_eq!(
U256::from(difficulty), U256::from(difficulty),
boundary_to_difficulty(&boundary_to_difficulty(&difficulty.into()).into()) boundary_to_difficulty(&BigEndianHash::from_uint(&boundary_to_difficulty(
&H256::from_low_u64_be(difficulty)
))),
); );
assert_eq!( assert_eq!(
H256::from(difficulty), H256::from_low_u64_be(difficulty),
difficulty_to_boundary(&difficulty_to_boundary(&difficulty.into()).into()) difficulty_to_boundary(&difficulty_to_boundary(&difficulty.into()).into_uint())
); );
} }
} }
@ -266,5 +270,5 @@ fn test_difficulty_to_boundary_panics_on_zero() {
#[test] #[test]
#[should_panic] #[should_panic]
fn test_boundary_to_difficulty_panics_on_zero() { fn test_boundary_to_difficulty_panics_on_zero() {
boundary_to_difficulty(&ethereum_types::H256::from(0)); boundary_to_difficulty(&ethereum_types::H256::zero());
} }

View File

@ -17,22 +17,26 @@ url = { version = "2", optional = true }
ansi_term = "0.10" ansi_term = "0.10"
common-types = { path = "../../ethcore/types" } common-types = { path = "../../ethcore/types" }
error-chain = "0.12" error-chain = "0.12"
ethabi = "6.0" ethabi = "12.0.0"
ethabi-derive = "6.0" ethabi-derive = "12.0.0"
ethabi-contract = "6.0" ethabi-contract = "11.0.0"
ethcore-call-contract = { path = "../../vm/call-contract" } ethcore-call-contract = { path = "../../vm/call-contract" }
ethereum-types = "0.4" ethereum-types = "0.9.2"
futures = "0.1" futures = "0.1"
heapsize = "0.4" keccak-hash = "0.5.0"
keccak-hash = "0.1"
linked-hash-map = "0.5" linked-hash-map = "0.5"
log = "0.4" log = "0.4"
parity-crypto = { version = "0.6.2", features = [ "publickey" ] }
parity-runtime = { path = "../../runtime/runtime" } parity-runtime = { path = "../../runtime/runtime" }
parking_lot = "0.7" parity-util-mem = "0.7"
parking_lot = "0.11.1"
price-info = { path = "./price-info", optional = true } price-info = { path = "./price-info", optional = true }
rlp = { version = "0.3.0", features = ["ethereum"] } rlp = { version = "0.4.6" }
serde = { version = "1.0", features = ["derive"] }
serde_derive = "1.0"
serde_json = "1.0"
trace-time = "0.1" trace-time = "0.1"
transaction-pool = "2.0.1" txpool = { path = "../../transaction-pool" }
[dev-dependencies] [dev-dependencies]
env_logger = "0.5" env_logger = "0.5"

View File

@ -7,9 +7,11 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies] [dependencies]
common-types = { path = "../../../ethcore/types" } common-types = { path = "../../../ethcore/types" }
ethcore-io = { path = "../../../runtime/io" } ethcore-io = { path = "../../../runtime/io" }
ethcore-db = { path = "../../../db/db"}
kvdb = "0.1" kvdb = "0.1"
log = "0.4" log = "0.4"
rlp = { version = "0.3.0", features = ["ethereum"] } parity-crypto = { version = "0.6.2", features = [ "publickey" ] }
rlp = { version = "0.4.6" }
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
serde_json = "1.0" serde_json = "1.0"

View File

@ -18,16 +18,18 @@
use std::{fmt, sync::Arc, time::Duration}; use std::{fmt, sync::Arc, time::Duration};
use ethcore_db::KeyValueDB;
use io::IoHandler; use io::IoHandler;
use kvdb::KeyValueDB;
use types::transaction::{ use types::transaction::{
Condition as TransactionCondition, PendingTransaction, SignedTransaction, TypedTransaction, Condition as TransactionCondition, PendingTransaction, SignedTransaction, TypedTransaction,
UnverifiedTransaction, UnverifiedTransaction,
}; };
extern crate common_types as types; extern crate common_types as types;
extern crate ethcore_db;
extern crate ethcore_io as io; extern crate ethcore_io as io;
extern crate kvdb; extern crate kvdb;
extern crate parity_crypto as crypto;
extern crate rlp; extern crate rlp;
extern crate serde; extern crate serde;
extern crate serde_json; extern crate serde_json;
@ -237,7 +239,7 @@ impl<T: NodeInfo> Drop for LocalDataStore<T> {
mod tests { mod tests {
use super::NodeInfo; use super::NodeInfo;
use ethkey::{Brain, Generator}; use ethkey::Brain;
use std::sync::Arc; use std::sync::Arc;
use types::transaction::{Condition, PendingTransaction, Transaction, TypedTransaction}; use types::transaction::{Condition, PendingTransaction, Transaction, TypedTransaction};
@ -253,7 +255,7 @@ mod tests {
#[test] #[test]
fn twice_empty() { fn twice_empty() {
let db = Arc::new(::kvdb_memorydb::create(0)); let db = Arc::new(ethcore_db::InMemoryWithMetrics::create(0));
{ {
let store = super::create(db.clone(), None, Dummy(vec![])); let store = super::create(db.clone(), None, Dummy(vec![]));
@ -268,7 +270,7 @@ mod tests {
#[test] #[test]
fn with_condition() { fn with_condition() {
let keypair = Brain::new("abcd".into()).generate().unwrap(); let keypair = Brain::new("abcd".into()).generate();
let transactions: Vec<_> = (0..10u64) let transactions: Vec<_> = (0..10u64)
.map(|nonce| { .map(|nonce| {
let mut tx = TypedTransaction::Legacy(Transaction::default()); let mut tx = TypedTransaction::Legacy(Transaction::default());
@ -284,7 +286,7 @@ mod tests {
}) })
.collect(); .collect();
let db = Arc::new(::kvdb_memorydb::create(0)); let db = Arc::new(ethcore_db::InMemoryWithMetrics::create(0));
{ {
// nothing written yet, will write pending. // nothing written yet, will write pending.
@ -305,7 +307,7 @@ mod tests {
#[test] #[test]
fn skips_bad_transactions() { fn skips_bad_transactions() {
let keypair = Brain::new("abcd".into()).generate().unwrap(); let keypair = Brain::new("abcd".into()).generate();
let mut transactions: Vec<_> = (0..10u64) let mut transactions: Vec<_> = (0..10u64)
.map(|nonce| { .map(|nonce| {
let mut tx = TypedTransaction::Legacy(Transaction::default()); let mut tx = TypedTransaction::Legacy(Transaction::default());
@ -325,7 +327,7 @@ mod tests {
PendingTransaction::new(signed, None) PendingTransaction::new(signed, None)
}); });
let db = Arc::new(::kvdb_memorydb::create(0)); let db = Arc::new(ethcore_db::InMemoryWithMetrics::create(0));
{ {
// nothing written, will write bad. // nothing written, will write bad.
let store = super::create(db.clone(), None, Dummy(transactions.clone())); let store = super::create(db.clone(), None, Dummy(transactions.clone()));

View File

@ -14,5 +14,5 @@ log = "0.4"
serde_json = "1.0" serde_json = "1.0"
[dev-dependencies] [dev-dependencies]
parking_lot = "0.7" parking_lot = "0.11.1"
fake-fetch = { path = "../../../net/fake-fetch" } fake-fetch = { path = "../../../net/fake-fetch" }

View File

@ -207,11 +207,11 @@ mod test {
// when // when
let bb = b.clone(); let bb = b.clone();
price_info.get(move |_| { price_info.get(move |_| {
bb.store(true, Ordering::Relaxed); bb.store(true, Ordering::SeqCst);
}); });
// then // then
assert_eq!(b.load(Ordering::Relaxed), false); assert_eq!(b.load(Ordering::SeqCst), false);
} }
#[test] #[test]
@ -225,10 +225,10 @@ mod test {
// when // when
let bb = b.clone(); let bb = b.clone();
price_info.get(move |_| { price_info.get(move |_| {
bb.store(true, Ordering::Relaxed); bb.store(true, Ordering::SeqCst);
}); });
// then // then
assert_eq!(b.load(Ordering::Relaxed), false); assert_eq!(b.load(Ordering::SeqCst), false);
} }
} }

View File

@ -92,7 +92,7 @@ mod tests {
// given // given
let m = miner(); let m = miner();
assert_eq!(m.hashrate(), U256::from(0)); assert_eq!(m.hashrate(), U256::from(0));
m.submit_hashrate(U256::from(10), H256::from(1)); m.submit_hashrate(U256::from(10), H256::from_low_u64_be(1));
assert_eq!(m.hashrate(), U256::from(10)); assert_eq!(m.hashrate(), U256::from(10));
// when // when
@ -107,12 +107,12 @@ mod tests {
// given // given
let m = miner(); let m = miner();
assert_eq!(m.hashrate(), U256::from(0)); assert_eq!(m.hashrate(), U256::from(0));
m.submit_hashrate(U256::from(10), H256::from(1)); m.submit_hashrate(U256::from(10), H256::from_low_u64_be(1));
assert_eq!(m.hashrate(), U256::from(10)); assert_eq!(m.hashrate(), U256::from(10));
// when // when
m.submit_hashrate(U256::from(15), H256::from(1)); m.submit_hashrate(U256::from(15), H256::from_low_u64_be(1));
m.submit_hashrate(U256::from(20), H256::from(2)); m.submit_hashrate(U256::from(20), H256::from_low_u64_be(2));
// then // then
assert_eq!(m.hashrate(), U256::from(35)); assert_eq!(m.hashrate(), U256::from(35));

View File

@ -22,28 +22,30 @@
extern crate ansi_term; extern crate ansi_term;
extern crate common_types as types; extern crate common_types as types;
extern crate ethabi; extern crate ethabi;
extern crate ethabi_derive;
extern crate ethcore_call_contract as call_contract; extern crate ethcore_call_contract as call_contract;
extern crate ethereum_types; extern crate ethereum_types;
extern crate futures; extern crate futures;
extern crate heapsize;
extern crate keccak_hash as hash; extern crate keccak_hash as hash;
extern crate linked_hash_map; extern crate linked_hash_map;
extern crate parity_crypto as crypto;
extern crate parity_runtime; extern crate parity_runtime;
extern crate parity_util_mem;
extern crate parking_lot; extern crate parking_lot;
#[cfg(feature = "price-info")] #[cfg(feature = "price-info")]
extern crate price_info; extern crate price_info;
extern crate rlp; extern crate rlp;
extern crate transaction_pool as txpool; extern crate txpool;
#[macro_use] #[macro_use]
extern crate ethabi_contract; extern crate ethabi_contract;
#[macro_use] #[macro_use]
extern crate ethabi_derive;
#[macro_use]
extern crate error_chain; extern crate error_chain;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
#[macro_use] #[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate trace_time; extern crate trace_time;
#[cfg(test)] #[cfg(test)]

View File

@ -32,6 +32,8 @@ pub struct AccountDetails {
pub nonce: U256, pub nonce: U256,
/// Current account balance /// Current account balance
pub balance: U256, pub balance: U256,
/// Code hash associated with an account if any
pub code_hash: Option<H256>,
/// Is this account a local account? /// Is this account a local account?
pub is_local: bool, pub is_local: bool,
} }

View File

@ -124,6 +124,7 @@ impl txpool::Listener<Transaction> for Logger {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use ethereum_types::H160;
use parking_lot::Mutex; use parking_lot::Mutex;
use txpool::Listener; use txpool::Listener;
use types::transaction; use types::transaction;
@ -166,7 +167,7 @@ mod tests {
gas_price: 5.into(), gas_price: 5.into(),
value: 0.into(), value: 0.into(),
}) })
.fake_sign(5.into()); .fake_sign(H160::from_low_u64_be(5));
Arc::new(Transaction::from_pending_block_transaction(signed)) Arc::new(Transaction::from_pending_block_transaction(signed))
} }

View File

@ -254,8 +254,8 @@ impl txpool::Listener<Transaction> for LocalTransactionsList {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crypto::publickey::{Generator, Random};
use ethereum_types::U256; use ethereum_types::U256;
use ethkey::{Generator, Random};
use txpool::Listener; use txpool::Listener;
use types::transaction; use types::transaction;
@ -339,7 +339,7 @@ mod tests {
} }
fn new_tx<T: Into<U256>>(nonce: T) -> Arc<Transaction> { fn new_tx<T: Into<U256>>(nonce: T) -> Arc<Transaction> {
let keypair = Random.generate().unwrap(); let keypair = Random.generate();
let signed = transaction::TypedTransaction::Legacy(transaction::Transaction { let signed = transaction::TypedTransaction::Legacy(transaction::Transaction {
action: transaction::Action::Create, action: transaction::Action::Create,
value: U256::from(100), value: U256::from(100),

View File

@ -17,7 +17,7 @@
//! Transaction Pool //! Transaction Pool
use ethereum_types::{Address, H256, U256}; use ethereum_types::{Address, H256, U256};
use heapsize::HeapSizeOf; use parity_util_mem::MallocSizeOfExt;
use txpool; use txpool;
use types::transaction; use types::transaction;
@ -29,6 +29,7 @@ pub mod client;
pub mod local_transactions; pub mod local_transactions;
pub mod replace; pub mod replace;
pub mod scoring; pub mod scoring;
pub mod transaction_filter;
pub mod verifier; pub mod verifier;
#[cfg(test)] #[cfg(test)]
@ -70,6 +71,9 @@ pub struct PendingSettings {
pub max_len: usize, pub max_len: usize,
/// Ordering of transactions. /// Ordering of transactions.
pub ordering: PendingOrdering, pub ordering: PendingOrdering,
/// Value of score that is a boundary between includable and non-includable transactions
/// Before EIP1559 it should be equal to zero, after EIP1559 it should be equal to block_base_fee
pub includable_boundary: U256,
} }
impl PendingSettings { impl PendingSettings {
@ -81,6 +85,7 @@ impl PendingSettings {
nonce_cap: None, nonce_cap: None,
max_len: usize::max_value(), max_len: usize::max_value(),
ordering: PendingOrdering::Priority, ordering: PendingOrdering::Priority,
includable_boundary: Default::default(),
} }
} }
} }
@ -117,7 +122,7 @@ pub trait ScoredTransaction {
fn priority(&self) -> Priority; fn priority(&self) -> Priority;
/// Gets transaction gas price. /// Gets transaction gas price.
fn gas_price(&self) -> &U256; fn effective_gas_price(&self, block_base_fee: Option<U256>) -> U256;
/// Gets transaction nonce. /// Gets transaction nonce.
fn nonce(&self) -> U256; fn nonce(&self) -> U256;
@ -177,12 +182,16 @@ impl txpool::VerifiedTransaction for VerifiedTransaction {
} }
fn mem_usage(&self) -> usize { fn mem_usage(&self) -> usize {
self.transaction.heap_size_of_children() self.transaction.malloc_size_of()
} }
fn sender(&self) -> &Address { fn sender(&self) -> &Address {
&self.sender &self.sender
} }
fn has_zero_gas_price(&self) -> bool {
self.transaction.has_zero_gas_price()
}
} }
impl ScoredTransaction for VerifiedTransaction { impl ScoredTransaction for VerifiedTransaction {
@ -190,9 +199,8 @@ impl ScoredTransaction for VerifiedTransaction {
self.priority self.priority
} }
/// Gets transaction gas price. fn effective_gas_price(&self, block_base_fee: Option<U256>) -> U256 {
fn gas_price(&self) -> &U256 { self.transaction.effective_gas_price(block_base_fee)
&self.transaction.tx().gas_price
} }
/// Gets transaction nonce. /// Gets transaction nonce.

View File

@ -26,13 +26,17 @@ use std::{
}, },
}; };
use self::scoring::ScoringEvent;
use ethereum_types::{Address, H256, U256}; use ethereum_types::{Address, H256, U256};
use parking_lot::RwLock; use parking_lot::RwLock;
use txpool::{self, Verifier}; use txpool::{self, Verifier};
use types::transaction; use types::transaction;
use pool::{ use pool::{
self, client, listener, local_transactions::LocalTransactionsList, ready, replace, scoring, self, client, listener,
local_transactions::LocalTransactionsList,
ready, replace, scoring,
transaction_filter::{match_filter, TransactionFilter},
verifier, PendingOrdering, PendingSettings, PrioritizationStrategy, verifier, PendingOrdering, PendingSettings, PrioritizationStrategy,
}; };
@ -120,6 +124,17 @@ impl CachedPending {
current_timestamp: u64, current_timestamp: u64,
nonce_cap: Option<&U256>, nonce_cap: Option<&U256>,
max_len: usize, max_len: usize,
) -> Option<Vec<Arc<pool::VerifiedTransaction>>> {
self.pending_filtered(block_number, current_timestamp, nonce_cap, max_len, None)
}
pub fn pending_filtered(
&self,
block_number: u64,
current_timestamp: u64,
nonce_cap: Option<&U256>,
max_len: usize,
filter: Option<TransactionFilter>,
) -> Option<Vec<Arc<pool::VerifiedTransaction>>> { ) -> Option<Vec<Arc<pool::VerifiedTransaction>>> {
// First check if we have anything in cache. // First check if we have anything in cache.
let pending = self.pending.as_ref()?; let pending = self.pending.as_ref()?;
@ -149,7 +164,14 @@ impl CachedPending {
return None; return None;
} }
Some(pending.iter().take(max_len).cloned().collect()) Some(
pending
.iter()
.filter(|tx| match_filter(&filter, tx))
.take(max_len)
.cloned()
.collect(),
)
} }
} }
@ -224,7 +246,10 @@ impl TransactionQueue {
insertion_id: Default::default(), insertion_id: Default::default(),
pool: RwLock::new(txpool::Pool::new( pool: RwLock::new(txpool::Pool::new(
Default::default(), Default::default(),
scoring::NonceAndGasPrice(strategy), scoring::NonceAndGasPrice {
strategy,
block_base_fee: verification_options.block_base_fee,
},
limits, limits,
)), )),
options: RwLock::new(verification_options), options: RwLock::new(verification_options),
@ -236,6 +261,26 @@ impl TransactionQueue {
} }
} }
/// If latest block has different base fee than it's parent, then transaction pool scoring needs to be updated.
pub fn update_scoring(&self, block_base_fee: U256) {
let update_needed = match self.pool.read().scoring().block_base_fee {
Some(base_fee) => base_fee != block_base_fee,
None => true,
};
if update_needed {
self.pool.write().set_scoring(
scoring::NonceAndGasPrice {
strategy: PrioritizationStrategy::GasPriceOnly,
block_base_fee: Some(block_base_fee),
},
ScoringEvent::BlockBaseFeeChanged,
);
self.cached_pending.write().clear();
}
}
/// Update verification options /// Update verification options
/// ///
/// Some parameters of verification may vary in time (like block gas limit or minimal gas price). /// Some parameters of verification may vary in time (like block gas limit or minimal gas price).
@ -286,8 +331,11 @@ impl TransactionQueue {
transaction_to_replace, transaction_to_replace,
); );
let mut replace = let mut replace = replace::ReplaceByScoreAndReadiness::new(
replace::ReplaceByScoreAndReadiness::new(self.pool.read().scoring().clone(), client); self.pool.read().scoring().clone(),
client,
self.options.read().block_base_fee,
);
let results = transactions let results = transactions
.into_iter() .into_iter()
@ -332,7 +380,10 @@ impl TransactionQueue {
/// Returns all transactions in the queue without explicit ordering. /// Returns all transactions in the queue without explicit ordering.
pub fn all_transactions(&self) -> Vec<Arc<pool::VerifiedTransaction>> { pub fn all_transactions(&self) -> Vec<Arc<pool::VerifiedTransaction>> {
let ready = |_tx: &pool::VerifiedTransaction| txpool::Readiness::Ready; let ready = |_tx: &pool::VerifiedTransaction| txpool::Readiness::Ready;
self.pool.read().unordered_pending(ready).collect() self.pool
.read()
.unordered_pending(ready, Default::default())
.collect()
} }
/// Returns all transaction hashes in the queue without explicit ordering. /// Returns all transaction hashes in the queue without explicit ordering.
@ -340,7 +391,7 @@ impl TransactionQueue {
let ready = |_tx: &pool::VerifiedTransaction| txpool::Readiness::Ready; let ready = |_tx: &pool::VerifiedTransaction| txpool::Readiness::Ready;
self.pool self.pool
.read() .read()
.unordered_pending(ready) .unordered_pending(ready, Default::default())
.map(|tx| tx.hash) .map(|tx| tx.hash)
.collect() .collect()
} }
@ -355,7 +406,7 @@ impl TransactionQueue {
let ready = ready::OptionalState::new(nonce); let ready = ready::OptionalState::new(nonce);
self.pool self.pool
.read() .read()
.unordered_pending(ready) .unordered_pending(ready, Default::default())
.map(|tx| tx.hash) .map(|tx| tx.hash)
.collect() .collect()
} }
@ -379,6 +430,7 @@ impl TransactionQueue {
nonce_cap, nonce_cap,
max_len, max_len,
ordering, ordering,
includable_boundary,
} = settings; } = settings;
if let Some(pending) = self.cached_pending.read().pending( if let Some(pending) = self.cached_pending.read().pending(
block_number, block_number,
@ -404,15 +456,19 @@ impl TransactionQueue {
return self return self
.pool .pool
.read() .read()
.unordered_pending(ready) .unordered_pending(ready, includable_boundary)
.take(max_len) .take(max_len)
.collect(); .collect();
} }
let pending: Vec<_> = let pending: Vec<_> = self.collect_pending(
self.collect_pending(client, block_number, current_timestamp, nonce_cap, |i| { client,
i.take(max_len).collect() includable_boundary,
}); block_number,
current_timestamp,
nonce_cap,
|i| i.take(max_len).collect(),
);
*cached_pending = CachedPending { *cached_pending = CachedPending {
block_number, block_number,
@ -426,6 +482,32 @@ impl TransactionQueue {
pending pending
} }
/// Returns current pending transactions filtered.
///
/// Different to the pending() method, this one does not cache.
pub fn pending_filtered<C>(
&self,
client: C,
settings: PendingSettings,
filter: &TransactionFilter,
) -> Vec<Arc<pool::VerifiedTransaction>>
where
C: client::NonceClient,
{
self.collect_pending(
client,
settings.includable_boundary,
settings.block_number,
settings.current_timestamp,
settings.nonce_cap,
|i| {
i.filter(|tx| filter.matches(tx))
.take(settings.max_len)
.collect()
},
)
}
/// Collect pending transactions. /// Collect pending transactions.
/// ///
/// NOTE This is re-computing the pending set and it might be expensive to do so. /// NOTE This is re-computing the pending set and it might be expensive to do so.
@ -433,6 +515,7 @@ impl TransactionQueue {
pub fn collect_pending<C, F, T>( pub fn collect_pending<C, F, T>(
&self, &self,
client: C, client: C,
includable_boundary: U256,
block_number: u64, block_number: u64,
current_timestamp: u64, current_timestamp: u64,
nonce_cap: Option<U256>, nonce_cap: Option<U256>,
@ -452,7 +535,7 @@ impl TransactionQueue {
debug!(target: "txqueue", "Re-computing pending set for block: {}", block_number); debug!(target: "txqueue", "Re-computing pending set for block: {}", block_number);
trace_time!("pool::collect_pending"); trace_time!("pool::collect_pending");
let ready = Self::ready(client, block_number, current_timestamp, nonce_cap); let ready = Self::ready(client, block_number, current_timestamp, nonce_cap);
collect(self.pool.read().pending(ready)) collect(self.pool.read().pending(ready, includable_boundary))
} }
fn ready<C>( fn ready<C>(
@ -480,7 +563,7 @@ impl TransactionQueue {
// We want to clear stale transactions from the queue as well. // We want to clear stale transactions from the queue as well.
// (Transactions that are occuping the queue for a long time without being included) // (Transactions that are occuping the queue for a long time without being included)
let stale_id = { let stale_id = {
let current_id = self.insertion_id.load(atomic::Ordering::Relaxed); let current_id = self.insertion_id.load(atomic::Ordering::SeqCst);
// wait at least for half of the queue to be replaced // wait at least for half of the queue to be replaced
let gap = self.pool.read().options().max_count / 2; let gap = self.pool.read().options().max_count / 2;
// but never less than 100 transactions // but never less than 100 transactions
@ -517,7 +600,7 @@ impl TransactionQueue {
self.pool self.pool
.read() .read()
.pending_from_sender(state_readiness, address) .pending_from_sender(state_readiness, address, Default::default())
.last() .last()
.map(|tx| tx.signed().tx().nonce.saturating_add(U256::from(1))) .map(|tx| tx.signed().tx().nonce.saturating_add(U256::from(1)))
} }
@ -566,18 +649,37 @@ impl TransactionQueue {
pub fn penalize<'a, T: IntoIterator<Item = &'a Address>>(&self, senders: T) { pub fn penalize<'a, T: IntoIterator<Item = &'a Address>>(&self, senders: T) {
let mut pool = self.pool.write(); let mut pool = self.pool.write();
for sender in senders { for sender in senders {
pool.update_scores(sender, ()); pool.update_scores(sender, ScoringEvent::Penalize);
} }
} }
/// Returns gas price of currently the worst transaction in the pool. /// Returns gas price of currently the worst transaction in the pool.
pub fn current_worst_gas_price(&self) -> U256 { pub fn current_worst_gas_price(&self) -> U256 {
match self.pool.read().worst_transaction() { match self.pool.read().worst_transaction() {
Some(tx) => tx.signed().tx().gas_price, Some(tx) => tx
None => self.options.read().minimal_gas_price, .signed()
.effective_gas_price(self.options.read().block_base_fee),
None => {
self.options.read().minimal_gas_price
+ self.options.read().block_base_fee.unwrap_or_default()
}
} }
} }
/// Returns effective priority fee gas price of currently the worst transaction in the pool.
/// If the worst transaction has zero gas price, the minimal gas price is returned.
pub fn current_worst_effective_priority_fee(&self) -> U256 {
self.pool
.read()
.worst_transaction()
.filter(|tx| !tx.signed().has_zero_gas_price())
.map(|tx| {
tx.signed()
.effective_priority_fee(self.options.read().block_base_fee)
})
.unwrap_or(self.options.read().minimal_gas_price)
}
/// Returns a status of the queue. /// Returns a status of the queue.
pub fn status(&self) -> Status { pub fn status(&self) -> Status {
let pool = self.pool.read(); let pool = self.pool.read();

View File

@ -39,12 +39,18 @@ use txpool::{
pub struct ReplaceByScoreAndReadiness<S, C> { pub struct ReplaceByScoreAndReadiness<S, C> {
scoring: S, scoring: S,
client: C, client: C,
/// Block base fee of the latest block, exists if the EIP 1559 is activated
block_base_fee: Option<U256>,
} }
impl<S, C> ReplaceByScoreAndReadiness<S, C> { impl<S, C> ReplaceByScoreAndReadiness<S, C> {
/// Create a new `ReplaceByScoreAndReadiness` /// Create a new `ReplaceByScoreAndReadiness`
pub fn new(scoring: S, client: C) -> Self { pub fn new(scoring: S, client: C, block_base_fee: Option<U256>) -> Self {
ReplaceByScoreAndReadiness { scoring, client } ReplaceByScoreAndReadiness {
scoring,
client,
block_base_fee,
}
} }
} }
@ -67,8 +73,9 @@ where
} else if both_local { } else if both_local {
Choice::InsertNew Choice::InsertNew
} else { } else {
let old_score = (old.priority(), old.gas_price()); let old_score = (old.priority(), old.effective_gas_price(self.block_base_fee));
let new_score = (new.priority(), new.gas_price()); let new_score = (new.priority(), new.effective_gas_price(self.block_base_fee));
if new_score > old_score { if new_score > old_score {
// Check if this is a replacement transaction. // Check if this is a replacement transaction.
// //
@ -117,7 +124,7 @@ where
mod tests { mod tests {
use super::*; use super::*;
use ethkey::{Generator, KeyPair, Random}; use crypto::publickey::{Generator, KeyPair, Random};
use pool::{ use pool::{
scoring::*, scoring::*,
tests::{ tests::{
@ -155,12 +162,15 @@ mod tests {
#[test] #[test]
fn should_always_accept_local_transactions_unless_same_sender_and_nonce() { fn should_always_accept_local_transactions_unless_same_sender_and_nonce() {
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly); let scoring = NonceAndGasPrice {
strategy: PrioritizationStrategy::GasPriceOnly,
block_base_fee: None,
};
let client = TestClient::new().with_nonce(1); let client = TestClient::new().with_nonce(1);
let replace = ReplaceByScoreAndReadiness::new(scoring, client); let replace = ReplaceByScoreAndReadiness::new(scoring, client, None);
// same sender txs // same sender txs
let keypair = Random.generate().unwrap(); let keypair = Random.generate();
let same_sender_tx1 = local_tx_verified( let same_sender_tx1 = local_tx_verified(
Tx { Tx {
@ -190,7 +200,7 @@ mod tests {
); );
// different sender txs // different sender txs
let sender1 = Random.generate().unwrap(); let sender1 = Random.generate();
let different_sender_tx1 = local_tx_verified( let different_sender_tx1 = local_tx_verified(
Tx { Tx {
nonce: 2, nonce: 2,
@ -200,7 +210,7 @@ mod tests {
&sender1, &sender1,
); );
let sender2 = Random.generate().unwrap(); let sender2 = Random.generate();
let different_sender_tx2 = local_tx_verified( let different_sender_tx2 = local_tx_verified(
Tx { Tx {
nonce: 1, nonce: 1,
@ -249,9 +259,12 @@ mod tests {
#[test] #[test]
fn should_replace_same_sender_by_nonce() { fn should_replace_same_sender_by_nonce() {
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly); let scoring = NonceAndGasPrice {
strategy: PrioritizationStrategy::GasPriceOnly,
block_base_fee: None,
};
let client = TestClient::new().with_nonce(1); let client = TestClient::new().with_nonce(1);
let replace = ReplaceByScoreAndReadiness::new(scoring, client); let replace = ReplaceByScoreAndReadiness::new(scoring, client, None);
let tx1 = Tx { let tx1 = Tx {
nonce: 1, nonce: 1,
@ -274,7 +287,7 @@ mod tests {
..Default::default() ..Default::default()
}; };
let keypair = Random.generate().unwrap(); let keypair = Random.generate();
let txs = vec![tx1, tx2, tx3, tx4] let txs = vec![tx1, tx2, tx3, tx4]
.into_iter() .into_iter()
.map(|tx| tx.unsigned().sign(keypair.secret(), None).verified()) .map(|tx| tx.unsigned().sign(keypair.secret(), None).verified())
@ -311,9 +324,12 @@ mod tests {
#[test] #[test]
fn should_replace_different_sender_by_priority_and_gas_price() { fn should_replace_different_sender_by_priority_and_gas_price() {
// given // given
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly); let scoring = NonceAndGasPrice {
strategy: PrioritizationStrategy::GasPriceOnly,
block_base_fee: None,
};
let client = TestClient::new().with_nonce(0); let client = TestClient::new().with_nonce(0);
let replace = ReplaceByScoreAndReadiness::new(scoring, client); let replace = ReplaceByScoreAndReadiness::new(scoring, client, None);
let tx_regular_low_gas = { let tx_regular_low_gas = {
let tx = Tx { let tx = Tx {
@ -406,9 +422,12 @@ mod tests {
#[test] #[test]
fn should_not_replace_ready_transaction_with_future_transaction() { fn should_not_replace_ready_transaction_with_future_transaction() {
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly); let scoring = NonceAndGasPrice {
strategy: PrioritizationStrategy::GasPriceOnly,
block_base_fee: None,
};
let client = TestClient::new().with_nonce(1); let client = TestClient::new().with_nonce(1);
let replace = ReplaceByScoreAndReadiness::new(scoring, client); let replace = ReplaceByScoreAndReadiness::new(scoring, client, None);
let tx_ready_low_score = { let tx_ready_low_score = {
let tx = Tx { let tx = Tx {
@ -436,11 +455,14 @@ mod tests {
#[test] #[test]
fn should_compute_readiness_with_pooled_transactions_from_the_same_sender_as_the_existing_transaction( fn should_compute_readiness_with_pooled_transactions_from_the_same_sender_as_the_existing_transaction(
) { ) {
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly); let scoring = NonceAndGasPrice {
strategy: PrioritizationStrategy::GasPriceOnly,
block_base_fee: None,
};
let client = TestClient::new().with_nonce(1); let client = TestClient::new().with_nonce(1);
let replace = ReplaceByScoreAndReadiness::new(scoring, client); let replace = ReplaceByScoreAndReadiness::new(scoring, client, None);
let old_sender = Random.generate().unwrap(); let old_sender = Random.generate();
let tx_old_ready_1 = { let tx_old_ready_1 = {
let tx = Tx { let tx = Tx {
nonce: 1, nonce: 1,
@ -504,9 +526,12 @@ mod tests {
#[test] #[test]
fn should_compute_readiness_with_pooled_transactions_from_the_same_sender_as_the_new_transaction( fn should_compute_readiness_with_pooled_transactions_from_the_same_sender_as_the_new_transaction(
) { ) {
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly); let scoring = NonceAndGasPrice {
strategy: PrioritizationStrategy::GasPriceOnly,
block_base_fee: None,
};
let client = TestClient::new().with_nonce(1); let client = TestClient::new().with_nonce(1);
let replace = ReplaceByScoreAndReadiness::new(scoring, client); let replace = ReplaceByScoreAndReadiness::new(scoring, client, None);
// current transaction is ready but has a lower gas price than the new one // current transaction is ready but has a lower gas price than the new one
let old_tx = { let old_tx = {
@ -518,7 +543,7 @@ mod tests {
tx.signed().verified() tx.signed().verified()
}; };
let new_sender = Random.generate().unwrap(); let new_sender = Random.generate();
let tx_new_ready_1 = { let tx_new_ready_1 = {
let tx = Tx { let tx = Tx {
nonce: 1, nonce: 1,
@ -572,9 +597,12 @@ mod tests {
#[test] #[test]
fn should_accept_local_tx_with_same_sender_and_nonce_with_better_gas_price() { fn should_accept_local_tx_with_same_sender_and_nonce_with_better_gas_price() {
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly); let scoring = NonceAndGasPrice {
strategy: PrioritizationStrategy::GasPriceOnly,
block_base_fee: None,
};
let client = TestClient::new().with_nonce(1); let client = TestClient::new().with_nonce(1);
let replace = ReplaceByScoreAndReadiness::new(scoring, client); let replace = ReplaceByScoreAndReadiness::new(scoring, client, None);
// current transaction is ready // current transaction is ready
let old_tx = { let old_tx = {
@ -586,7 +614,7 @@ mod tests {
tx.signed().verified() tx.signed().verified()
}; };
let new_sender = Random.generate().unwrap(); let new_sender = Random.generate();
let tx_new_ready_1 = local_tx_verified( let tx_new_ready_1 = local_tx_verified(
Tx { Tx {
nonce: 1, nonce: 1,
@ -627,9 +655,12 @@ mod tests {
#[test] #[test]
fn should_reject_local_tx_with_same_sender_and_nonce_with_worse_gas_price() { fn should_reject_local_tx_with_same_sender_and_nonce_with_worse_gas_price() {
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly); let scoring = NonceAndGasPrice {
strategy: PrioritizationStrategy::GasPriceOnly,
block_base_fee: None,
};
let client = TestClient::new().with_nonce(1); let client = TestClient::new().with_nonce(1);
let replace = ReplaceByScoreAndReadiness::new(scoring, client); let replace = ReplaceByScoreAndReadiness::new(scoring, client, None);
// current transaction is ready // current transaction is ready
let old_tx = { let old_tx = {
@ -641,7 +672,7 @@ mod tests {
tx.signed().verified() tx.signed().verified()
}; };
let new_sender = Random.generate().unwrap(); let new_sender = Random.generate();
let tx_new_ready_1 = local_tx_verified( let tx_new_ready_1 = local_tx_verified(
Tx { Tx {
nonce: 1, nonce: 1,

View File

@ -42,13 +42,25 @@ const GAS_PRICE_BUMP_SHIFT: usize = 3; // 2 = 25%, 3 = 12.5%, 4 = 6.25%
fn bump_gas_price(old_gp: U256) -> U256 { fn bump_gas_price(old_gp: U256) -> U256 {
old_gp.saturating_add(old_gp >> GAS_PRICE_BUMP_SHIFT) old_gp.saturating_add(old_gp >> GAS_PRICE_BUMP_SHIFT)
} }
/// List of events that trigger updating of scores
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum ScoringEvent {
/// Penalize transactions
Penalize,
/// Every time new block is added to blockchain, block base fee is changed and triggers score change.
BlockBaseFeeChanged,
}
/// Simple, gas-price based scoring for transactions. /// Simple, gas-price based scoring for transactions.
/// ///
/// NOTE: Currently penalization does not apply to new transactions that enter the pool. /// NOTE: Currently penalization does not apply to new transactions that enter the pool.
/// We might want to store penalization status in some persistent state. /// We might want to store penalization status in some persistent state.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct NonceAndGasPrice(pub PrioritizationStrategy); pub struct NonceAndGasPrice {
/// Strategy for prioritization
pub strategy: PrioritizationStrategy,
/// Block base fee. Exists if the EIP 1559 is activated.
pub block_base_fee: Option<U256>,
}
impl NonceAndGasPrice { impl NonceAndGasPrice {
/// Decide if the transaction should even be considered into the pool (if the pool is full). /// Decide if the transaction should even be considered into the pool (if the pool is full).
@ -67,7 +79,7 @@ impl NonceAndGasPrice {
return true; return true;
} }
&old.transaction.tx().gas_price > new.gas_price() old.effective_gas_price(self.block_base_fee) > new.effective_gas_price(self.block_base_fee)
} }
} }
@ -76,7 +88,7 @@ where
P: ScoredTransaction + txpool::VerifiedTransaction, P: ScoredTransaction + txpool::VerifiedTransaction,
{ {
type Score = U256; type Score = U256;
type Event = (); type Event = ScoringEvent;
fn compare(&self, old: &P, other: &P) -> cmp::Ordering { fn compare(&self, old: &P, other: &P) -> cmp::Ordering {
old.nonce().cmp(&other.nonce()) old.nonce().cmp(&other.nonce())
@ -87,10 +99,10 @@ where
return scoring::Choice::InsertNew; return scoring::Choice::InsertNew;
} }
let old_gp = old.gas_price(); let old_gp = old.effective_gas_price(self.block_base_fee);
let new_gp = new.gas_price(); let new_gp = new.effective_gas_price(self.block_base_fee);
let min_required_gp = bump_gas_price(*old_gp); let min_required_gp = bump_gas_price(old_gp);
match min_required_gp.cmp(&new_gp) { match min_required_gp.cmp(&new_gp) {
cmp::Ordering::Greater => scoring::Choice::RejectNew, cmp::Ordering::Greater => scoring::Choice::RejectNew,
@ -102,7 +114,7 @@ where
&self, &self,
txs: &[txpool::Transaction<P>], txs: &[txpool::Transaction<P>],
scores: &mut [U256], scores: &mut [U256],
change: scoring::Change, change: scoring::Change<ScoringEvent>,
) { ) {
use self::scoring::Change; use self::scoring::Change;
@ -113,21 +125,46 @@ where
assert!(i < txs.len()); assert!(i < txs.len());
assert!(i < scores.len()); assert!(i < scores.len());
scores[i] = *txs[i].transaction.gas_price(); scores[i] = txs[i].effective_gas_price(self.block_base_fee);
let boost = match txs[i].priority() { let boost = match txs[i].priority() {
super::Priority::Local => 15, super::Priority::Local => 15,
super::Priority::Retracted => 10, super::Priority::Retracted => 10,
super::Priority::Regular => 0, super::Priority::Regular => 0,
}; };
scores[i] = scores[i] << boost;
//boost local and retracted only if they are currently includable (base fee criteria)
if self.block_base_fee.is_none() || scores[i] >= self.block_base_fee.unwrap() {
scores[i] = scores[i] << boost;
}
} }
// We are only sending an event in case of penalization. // We are only sending an event in case of penalization.
// So just lower the priority of all non-local transactions. // So just lower the priority of all non-local transactions.
Change::Event(_) => { Change::Event(event) => {
for (score, tx) in scores.iter_mut().zip(txs) { match event {
// Never penalize local transactions. ScoringEvent::Penalize => {
if !tx.priority().is_local() { for (score, tx) in scores.iter_mut().zip(txs) {
*score = *score >> 3; // Never penalize local transactions.
if !tx.priority().is_local() {
*score = *score >> 3;
}
}
}
ScoringEvent::BlockBaseFeeChanged => {
for i in 0..txs.len() {
scores[i] = txs[i].transaction.effective_gas_price(self.block_base_fee);
let boost = match txs[i].priority() {
super::Priority::Local => 15,
super::Priority::Retracted => 10,
super::Priority::Regular => 0,
};
//boost local and retracted only if they are currently includable (base fee criteria)
if self.block_base_fee.is_none()
|| scores[i] >= self.block_base_fee.unwrap()
{
scores[i] = scores[i] << boost;
}
}
} }
} }
} }
@ -150,7 +187,10 @@ mod tests {
#[test] #[test]
fn should_calculate_score_correctly() { fn should_calculate_score_correctly() {
// given // given
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly); let scoring = NonceAndGasPrice {
strategy: PrioritizationStrategy::GasPriceOnly,
block_base_fee: None,
};
let (tx1, tx2, tx3) = Tx::default().signed_triple(); let (tx1, tx2, tx3) = Tx::default().signed_triple();
let transactions = vec![tx1, tx2, tx3] let transactions = vec![tx1, tx2, tx3]
.into_iter() .into_iter()
@ -200,7 +240,11 @@ mod tests {
assert_eq!(scores, vec![32768.into(), 1024.into(), 1.into()]); assert_eq!(scores, vec![32768.into(), 1024.into(), 1.into()]);
// Check penalization // Check penalization
scoring.update_scores(&transactions, &mut *scores, scoring::Change::Event(())); scoring.update_scores(
&transactions,
&mut *scores,
scoring::Change::Event(ScoringEvent::Penalize),
);
assert_eq!(scores, vec![32768.into(), 128.into(), 0.into()]); assert_eq!(scores, vec![32768.into(), 128.into(), 0.into()]);
} }
} }

View File

@ -43,6 +43,7 @@ impl Default for TestClient {
account_details: AccountDetails { account_details: AccountDetails {
nonce: 123.into(), nonce: 123.into(),
balance: 63_100.into(), balance: 63_100.into(),
code_hash: None,
is_local: false, is_local: false,
}, },
gas_required: 21_000.into(), gas_required: 21_000.into(),
@ -68,6 +69,11 @@ impl TestClient {
self self
} }
pub fn with_code_hash<T: Into<H256>>(mut self, code_hash: T) -> Self {
self.account_details.code_hash = Some(code_hash.into());
self
}
pub fn with_gas_required<T: Into<U256>>(mut self, gas_required: T) -> Self { pub fn with_gas_required<T: Into<U256>>(mut self, gas_required: T) -> Self {
self.gas_required = gas_required.into(); self.gas_required = gas_required.into();
self self

View File

@ -15,6 +15,7 @@
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>. // along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use ethereum_types::U256; use ethereum_types::U256;
use hash::KECCAK_EMPTY;
use txpool; use txpool;
use types::transaction::{self, PendingTransaction}; use types::transaction::{self, PendingTransaction};
@ -46,6 +47,8 @@ fn new_queue() -> TransactionQueue {
block_gas_limit: 1_000_000.into(), block_gas_limit: 1_000_000.into(),
tx_gas_limit: 1_000_000.into(), tx_gas_limit: 1_000_000.into(),
no_early_reject: false, no_early_reject: false,
block_base_fee: None,
allow_non_eoa_sender: false,
}, },
PrioritizationStrategy::GasPriceOnly, PrioritizationStrategy::GasPriceOnly,
) )
@ -64,6 +67,8 @@ fn should_return_correct_nonces_when_dropped_because_of_limit() {
block_gas_limit: 1_000_000.into(), block_gas_limit: 1_000_000.into(),
tx_gas_limit: 1_000_000.into(), tx_gas_limit: 1_000_000.into(),
no_early_reject: false, no_early_reject: false,
block_base_fee: None,
allow_non_eoa_sender: false,
}, },
PrioritizationStrategy::GasPriceOnly, PrioritizationStrategy::GasPriceOnly,
); );
@ -124,6 +129,8 @@ fn should_never_drop_local_transactions_from_different_senders() {
block_gas_limit: 1_000_000.into(), block_gas_limit: 1_000_000.into(),
tx_gas_limit: 1_000_000.into(), tx_gas_limit: 1_000_000.into(),
no_early_reject: false, no_early_reject: false,
block_base_fee: None,
allow_non_eoa_sender: false,
}, },
PrioritizationStrategy::GasPriceOnly, PrioritizationStrategy::GasPriceOnly,
); );
@ -269,6 +276,71 @@ fn should_import_transaction_below_min_gas_price_threshold_if_local() {
assert_eq!(txq.status().status.transaction_count, 1); assert_eq!(txq.status().status.transaction_count, 1);
} }
#[test]
fn should_reject_transaction_from_non_eoa_if_non_eoa_sender_is_not_allowed() {
// given
let txq = new_queue();
let tx = Tx::default();
let code_hash = [
0x0c, 0x0a, 0x0f, 0x0e, 0x0c, 0x0a, 0x0f, 0x0e, 0x0c, 0x0a, 0x0f, 0x0e, 0x0c, 0x0a, 0x0f,
0x0e, 0x0c, 0x0a, 0x0f, 0x0e, 0x0c, 0x0a, 0x0f, 0x0e, 0x0c, 0x0a, 0x0f, 0x0e, 0x0c, 0x0a,
0x0f, 0x0e,
];
// when
let res = txq.import(
TestClient::new().with_code_hash(code_hash),
vec![tx.signed().unverified()],
);
// then
assert_eq!(res, vec![Err(transaction::Error::SenderIsNotEOA)]);
assert_eq!(txq.status().status.transaction_count, 0);
}
#[test]
fn should_import_transaction_from_non_eoa_if_non_eoa_sender_is_allowed() {
// given
let txq = new_queue();
let tx = Tx::default();
let code_hash = [
0x0c, 0x0a, 0x0f, 0x0e, 0x0c, 0x0a, 0x0f, 0x0e, 0x0c, 0x0a, 0x0f, 0x0e, 0x0c, 0x0a, 0x0f,
0x0e, 0x0c, 0x0a, 0x0f, 0x0e, 0x0c, 0x0a, 0x0f, 0x0e, 0x0c, 0x0a, 0x0f, 0x0e, 0x0c, 0x0a,
0x0f, 0x0e,
];
txq.set_verifier_options(verifier::Options {
allow_non_eoa_sender: true,
..Default::default()
});
// when
let res = txq.import(
TestClient::new().with_code_hash(code_hash),
vec![tx.signed().unverified()],
);
// then
assert_eq!(res, vec![Ok(())]);
assert_eq!(txq.status().status.transaction_count, 1);
}
#[test]
fn should_import_transaction_if_account_code_hash_is_keccak_empty() {
// given
let txq = new_queue();
let tx = Tx::default();
// when
let res = txq.import(
TestClient::new().with_code_hash(KECCAK_EMPTY),
vec![tx.signed().unverified()],
);
// then
assert_eq!(res, vec![Ok(())]);
assert_eq!(txq.status().status.transaction_count, 1);
}
#[test] #[test]
fn should_import_txs_from_same_sender() { fn should_import_txs_from_same_sender() {
// given // given
@ -541,6 +613,8 @@ fn should_prefer_current_transactions_when_hitting_the_limit() {
block_gas_limit: 1_000_000.into(), block_gas_limit: 1_000_000.into(),
tx_gas_limit: 1_000_000.into(), tx_gas_limit: 1_000_000.into(),
no_early_reject: false, no_early_reject: false,
block_base_fee: None,
allow_non_eoa_sender: false,
}, },
PrioritizationStrategy::GasPriceOnly, PrioritizationStrategy::GasPriceOnly,
); );
@ -898,6 +972,7 @@ fn should_not_return_transactions_over_nonce_cap() {
nonce_cap: Some(123.into()), nonce_cap: Some(123.into()),
max_len: usize::max_value(), max_len: usize::max_value(),
ordering: PendingOrdering::Priority, ordering: PendingOrdering::Priority,
includable_boundary: Default::default(),
}, },
); );
@ -932,6 +1007,7 @@ fn should_return_cached_pending_even_if_unordered_is_requested() {
nonce_cap: None, nonce_cap: None,
max_len: 3, max_len: 3,
ordering: PendingOrdering::Unordered, ordering: PendingOrdering::Unordered,
includable_boundary: Default::default(),
}, },
); );
@ -960,6 +1036,7 @@ fn should_return_unordered_and_not_populate_the_cache() {
nonce_cap: None, nonce_cap: None,
max_len: usize::max_value(), max_len: usize::max_value(),
ordering: PendingOrdering::Unordered, ordering: PendingOrdering::Unordered,
includable_boundary: Default::default(),
}, },
); );
@ -1035,6 +1112,8 @@ fn should_include_local_transaction_to_a_full_pool() {
block_gas_limit: 1_000_000.into(), block_gas_limit: 1_000_000.into(),
tx_gas_limit: 1_000_000.into(), tx_gas_limit: 1_000_000.into(),
no_early_reject: false, no_early_reject: false,
block_base_fee: None,
allow_non_eoa_sender: false,
}, },
PrioritizationStrategy::GasPriceOnly, PrioritizationStrategy::GasPriceOnly,
); );
@ -1067,6 +1146,8 @@ fn should_avoid_verifying_transaction_already_in_pool() {
block_gas_limit: 1_000_000.into(), block_gas_limit: 1_000_000.into(),
tx_gas_limit: 1_000_000.into(), tx_gas_limit: 1_000_000.into(),
no_early_reject: false, no_early_reject: false,
block_base_fee: None,
allow_non_eoa_sender: false,
}, },
PrioritizationStrategy::GasPriceOnly, PrioritizationStrategy::GasPriceOnly,
); );
@ -1102,6 +1183,8 @@ fn should_avoid_reverifying_recently_rejected_transactions() {
block_gas_limit: 1_000_000.into(), block_gas_limit: 1_000_000.into(),
tx_gas_limit: 1_000_000.into(), tx_gas_limit: 1_000_000.into(),
no_early_reject: false, no_early_reject: false,
block_base_fee: None,
allow_non_eoa_sender: false,
}, },
PrioritizationStrategy::GasPriceOnly, PrioritizationStrategy::GasPriceOnly,
); );
@ -1150,6 +1233,8 @@ fn should_reject_early_in_case_gas_price_is_less_than_min_effective() {
block_gas_limit: 1_000_000.into(), block_gas_limit: 1_000_000.into(),
tx_gas_limit: 1_000_000.into(), tx_gas_limit: 1_000_000.into(),
no_early_reject: false, no_early_reject: false,
block_base_fee: None,
allow_non_eoa_sender: false,
}, },
PrioritizationStrategy::GasPriceOnly, PrioritizationStrategy::GasPriceOnly,
); );
@ -1192,6 +1277,8 @@ fn should_not_reject_early_in_case_gas_price_is_less_than_min_effective() {
block_gas_limit: 1_000_000.into(), block_gas_limit: 1_000_000.into(),
tx_gas_limit: 1_000_000.into(), tx_gas_limit: 1_000_000.into(),
no_early_reject: true, no_early_reject: true,
block_base_fee: None,
allow_non_eoa_sender: false,
}, },
PrioritizationStrategy::GasPriceOnly, PrioritizationStrategy::GasPriceOnly,
); );

View File

@ -14,8 +14,8 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>. // along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use crypto::publickey::{Generator, Random};
use ethereum_types::{H256, U256}; use ethereum_types::{H256, U256};
use ethkey::{Generator, Random};
use rustc_hex::FromHex; use rustc_hex::FromHex;
use types::transaction::{ use types::transaction::{
self, SignedTransaction, Transaction, TypedTransaction, UnverifiedTransaction, self, SignedTransaction, Transaction, TypedTransaction, UnverifiedTransaction,
@ -49,7 +49,7 @@ impl Tx {
} }
pub fn signed(self) -> SignedTransaction { pub fn signed(self) -> SignedTransaction {
let keypair = Random.generate().unwrap(); let keypair = Random.generate();
self.unsigned().sign(keypair.secret(), None) self.unsigned().sign(keypair.secret(), None)
} }
@ -59,7 +59,7 @@ impl Tx {
} }
pub fn signed_triple(mut self) -> (SignedTransaction, SignedTransaction, SignedTransaction) { pub fn signed_triple(mut self) -> (SignedTransaction, SignedTransaction, SignedTransaction) {
let keypair = Random.generate().unwrap(); let keypair = Random.generate();
let tx1 = self.clone().unsigned().sign(keypair.secret(), None); let tx1 = self.clone().unsigned().sign(keypair.secret(), None);
self.nonce += 1; self.nonce += 1;
let tx2 = self.clone().unsigned().sign(keypair.secret(), None); let tx2 = self.clone().unsigned().sign(keypair.secret(), None);
@ -70,7 +70,7 @@ impl Tx {
} }
pub fn signed_replacement(mut self) -> (SignedTransaction, SignedTransaction) { pub fn signed_replacement(mut self) -> (SignedTransaction, SignedTransaction) {
let keypair = Random.generate().unwrap(); let keypair = Random.generate();
let tx1 = self.clone().unsigned().sign(keypair.secret(), None); let tx1 = self.clone().unsigned().sign(keypair.secret(), None);
self.gas_price += 1; self.gas_price += 1;
let tx2 = self.unsigned().sign(keypair.secret(), None); let tx2 = self.unsigned().sign(keypair.secret(), None);
@ -90,7 +90,7 @@ impl Tx {
} }
pub fn big_one(self) -> SignedTransaction { pub fn big_one(self) -> SignedTransaction {
let keypair = Random.generate().unwrap(); let keypair = Random.generate();
let tx = TypedTransaction::Legacy(Transaction { let tx = TypedTransaction::Legacy(Transaction {
action: transaction::Action::Create, action: transaction::Action::Create,
value: U256::from(100), value: U256::from(100),

View File

@ -0,0 +1,129 @@
// Copyright 2015-2021 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
//! Filter options available in the parity_pendingTransaction endpoint of the JSONRPC API.
#![allow(missing_docs)]
use ethereum_types::{Address, U256};
use pool::VerifiedTransaction;
use types::transaction::Action;
#[allow(non_camel_case_types)]
#[derive(Debug, Deserialize, Serialize)]
#[serde()]
pub enum SenderArgument {
eq(Address),
None,
}
impl Default for SenderArgument {
fn default() -> Self {
Self::None
}
}
impl SenderArgument {
fn matches(&self, value: &Address) -> bool {
match self {
Self::eq(expected) => value == expected,
Self::None => true,
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Deserialize, Serialize)]
#[serde()]
pub enum ActionArgument {
eq(Address),
action(String),
None,
}
impl Default for ActionArgument {
fn default() -> Self {
Self::None
}
}
impl ActionArgument {
fn matches(&self, value: &Action) -> bool {
match self {
Self::eq(expected) => *value == Action::Call(*expected),
Self::action(name) => *value == Action::Create && name == "contract_creation",
Self::None => true,
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Deserialize, Serialize)]
#[serde()]
pub enum ValueFilterArgument {
eq(U256),
lt(U256),
gt(U256),
None,
}
impl Default for ValueFilterArgument {
fn default() -> Self {
Self::None
}
}
impl ValueFilterArgument {
fn matches(&self, value: &U256) -> bool {
match self {
ValueFilterArgument::eq(expected) => value == expected,
ValueFilterArgument::lt(threshold) => value < threshold,
ValueFilterArgument::gt(threshold) => value > threshold,
ValueFilterArgument::None => true,
}
}
}
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(default, rename_all = "camelCase")]
pub struct TransactionFilter {
from: SenderArgument,
to: ActionArgument,
gas: ValueFilterArgument,
gas_price: ValueFilterArgument,
value: ValueFilterArgument,
nonce: ValueFilterArgument,
}
impl TransactionFilter {
pub fn matches(&self, transaction: &VerifiedTransaction) -> bool {
let tx = transaction.signed().tx();
self.from.matches(&transaction.sender)
&& self.to.matches(&tx.action)
&& self.gas.matches(&tx.gas)
&& self.gas_price.matches(&tx.gas_price)
&& self.nonce.matches(&tx.nonce)
&& self.value.matches(&tx.value)
}
}
pub fn match_filter(filter: &Option<TransactionFilter>, transaction: &VerifiedTransaction) -> bool {
match filter {
Some(f) => f.matches(transaction),
None => true,
}
}

View File

@ -31,6 +31,7 @@ use std::{
}; };
use ethereum_types::{H256, U256}; use ethereum_types::{H256, U256};
use hash::KECCAK_EMPTY;
use txpool; use txpool;
use types::transaction; use types::transaction;
@ -42,14 +43,18 @@ use super::{
/// Verification options. /// Verification options.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Options { pub struct Options {
/// Minimal allowed gas price. /// Minimal allowed gas price (actually minimal block producer reward = effective_priority_fee).
pub minimal_gas_price: U256, pub minimal_gas_price: U256,
/// Current block gas limit. /// Current block gas limit.
pub block_gas_limit: U256, pub block_gas_limit: U256,
/// Block base fee. Exists if the EIP 1559 is activated.
pub block_base_fee: Option<U256>,
/// Maximal gas limit for a single transaction. /// Maximal gas limit for a single transaction.
pub tx_gas_limit: U256, pub tx_gas_limit: U256,
/// Skip checks for early rejection, to make sure that local transactions are always imported. /// Skip checks for early rejection, to make sure that local transactions are always imported.
pub no_early_reject: bool, pub no_early_reject: bool,
/// Accept transactions from non EOAs (see EIP-3607)
pub allow_non_eoa_sender: bool,
} }
#[cfg(test)] #[cfg(test)]
@ -58,8 +63,10 @@ impl Default for Options {
Options { Options {
minimal_gas_price: 0.into(), minimal_gas_price: 0.into(),
block_gas_limit: U256::max_value(), block_gas_limit: U256::max_value(),
block_base_fee: None,
tx_gas_limit: U256::max_value(), tx_gas_limit: U256::max_value(),
no_early_reject: false, no_early_reject: false,
allow_non_eoa_sender: false,
} }
} }
} }
@ -93,7 +100,7 @@ impl Transaction {
} }
} }
/// Return transaction gas price /// Return transaction gas price for non 1559 transactions or maxFeePerGas for 1559 transactions.
pub fn gas_price(&self) -> &U256 { pub fn gas_price(&self) -> &U256 {
match *self { match *self {
Transaction::Unverified(ref tx) => &tx.tx().gas_price, Transaction::Unverified(ref tx) => &tx.tx().gas_price,
@ -110,6 +117,33 @@ impl Transaction {
} }
} }
/// Return actual gas price of the transaction depending on the current block base fee
pub fn effective_gas_price(&self, block_base_fee: Option<U256>) -> U256 {
match *self {
Transaction::Unverified(ref tx) => tx.effective_gas_price(block_base_fee),
Transaction::Retracted(ref tx) => tx.effective_gas_price(block_base_fee),
Transaction::Local(ref tx) => tx.effective_gas_price(block_base_fee),
}
}
/// Return effective fee - part of the transaction fee that goes to the miner
pub fn effective_priority_fee(&self, block_base_fee: Option<U256>) -> U256 {
match *self {
Transaction::Unverified(ref tx) => tx.effective_priority_fee(block_base_fee),
Transaction::Retracted(ref tx) => tx.effective_priority_fee(block_base_fee),
Transaction::Local(ref tx) => tx.effective_priority_fee(block_base_fee),
}
}
/// Check if transaction has zero gas price
pub fn has_zero_gas_price(&self) -> bool {
match *self {
Transaction::Unverified(ref tx) => tx.has_zero_gas_price(),
Transaction::Retracted(ref tx) => tx.has_zero_gas_price(),
Transaction::Local(ref tx) => tx.has_zero_gas_price(),
}
}
fn transaction(&self) -> &transaction::TypedTransaction { fn transaction(&self) -> &transaction::TypedTransaction {
match *self { match *self {
Transaction::Unverified(ref tx) => &*tx, Transaction::Unverified(ref tx) => &*tx,
@ -213,22 +247,26 @@ impl<C: Client> txpool::Verifier<Transaction>
} }
let is_own = tx.is_local(); let is_own = tx.is_local();
let has_zero_gas_price = tx.has_zero_gas_price();
// Quick exit for non-service and non-local transactions // Quick exit for non-service and non-local transactions
// //
// We're checking if the transaction is below configured minimal gas price // We're checking if the transaction is below configured minimal gas price
// or the effective minimal gas price in case the pool is full. // or the effective minimal gas price in case the pool is full.
if !tx.gas_price().is_zero() && !is_own {
if tx.gas_price() < &self.options.minimal_gas_price { if !has_zero_gas_price && !is_own {
let effective_priority_fee = tx.effective_priority_fee(self.options.block_base_fee);
if effective_priority_fee < self.options.minimal_gas_price {
trace!( trace!(
target: "txqueue", target: "txqueue",
"[{:?}] Rejected tx below minimal gas price threshold: {} < {}", "[{:?}] Rejected tx below minimal gas price threshold: {} < {}",
hash, hash,
tx.gas_price(), effective_priority_fee,
self.options.minimal_gas_price, self.options.minimal_gas_price,
); );
bail!(transaction::Error::InsufficientGasPrice { bail!(transaction::Error::InsufficientGasPrice {
minimal: self.options.minimal_gas_price, minimal: self.options.minimal_gas_price,
got: *tx.gas_price(), got: effective_priority_fee,
}); });
} }
@ -238,12 +276,15 @@ impl<C: Client> txpool::Verifier<Transaction>
target: "txqueue", target: "txqueue",
"[{:?}] Rejected tx early, cause it doesn't have any chance to get to the pool: (gas price: {} < {})", "[{:?}] Rejected tx early, cause it doesn't have any chance to get to the pool: (gas price: {} < {})",
hash, hash,
tx.gas_price(), tx.effective_gas_price(self.options.block_base_fee),
vtx.transaction.tx().gas_price, vtx.transaction.effective_gas_price(self.options.block_base_fee),
); );
return Err(transaction::Error::TooCheapToReplace { return Err(transaction::Error::TooCheapToReplace {
prev: Some(vtx.transaction.tx().gas_price), prev: Some(
new: Some(*tx.gas_price()), vtx.transaction
.effective_gas_price(self.options.block_base_fee),
),
new: Some(tx.effective_gas_price(self.options.block_base_fee)),
}); });
} }
} }
@ -280,7 +321,24 @@ impl<C: Client> txpool::Verifier<Transaction>
let sender = transaction.sender(); let sender = transaction.sender();
let account_details = self.client.account_details(&sender); let account_details = self.client.account_details(&sender);
if transaction.tx().gas_price < self.options.minimal_gas_price { if !self.options.allow_non_eoa_sender {
if let Some(code_hash) = account_details.code_hash {
if code_hash != KECCAK_EMPTY {
debug!(
target: "txqueue",
"[{:?}] Rejected tx, sender is not an EOA: {}",
hash,
code_hash
);
bail!(transaction::Error::SenderIsNotEOA);
}
}
}
let effective_priority_fee =
transaction.effective_priority_fee(self.options.block_base_fee);
if effective_priority_fee < self.options.minimal_gas_price {
let transaction_type = self.client.transaction_type(&transaction); let transaction_type = self.client.transaction_type(&transaction);
if let TransactionType::Service = transaction_type { if let TransactionType::Service = transaction_type {
debug!(target: "txqueue", "Service tx {:?} below minimal gas price accepted", hash); debug!(target: "txqueue", "Service tx {:?} below minimal gas price accepted", hash);
@ -291,20 +349,26 @@ impl<C: Client> txpool::Verifier<Transaction>
target: "txqueue", target: "txqueue",
"[{:?}] Rejected tx below minimal gas price threshold: {} < {}", "[{:?}] Rejected tx below minimal gas price threshold: {} < {}",
hash, hash,
transaction.tx().gas_price, effective_priority_fee,
self.options.minimal_gas_price, self.options.minimal_gas_price,
); );
bail!(transaction::Error::InsufficientGasPrice { bail!(transaction::Error::InsufficientGasPrice {
minimal: self.options.minimal_gas_price, minimal: self.options.minimal_gas_price,
got: transaction.tx().gas_price, got: effective_priority_fee,
}); });
} }
} }
let (full_gas_price, overflow_1) = transaction let gas_price = transaction.tx().gas_price;
.tx()
.gas_price if gas_price < transaction.max_priority_fee_per_gas() {
.overflowing_mul(transaction.tx().gas); bail!(transaction::Error::InsufficientGasPrice {
minimal: transaction.max_priority_fee_per_gas(),
got: gas_price,
});
}
let (full_gas_price, overflow_1) = gas_price.overflowing_mul(transaction.tx().gas);
let (cost, overflow_2) = transaction.tx().value.overflowing_add(full_gas_price); let (cost, overflow_2) = transaction.tx().value.overflowing_add(full_gas_price);
if overflow_1 || overflow_2 { if overflow_1 || overflow_2 {
trace!( trace!(

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